mirror of https://github.com/kurisufriend/Clover
Added json models. Seperated normal models, orm models and json models packages.multisite
parent
e7f0038bbd
commit
345c22de7f
@ -0,0 +1,28 @@ |
||||
/* |
||||
* Clover - 4chan browser https://github.com/Floens/Clover/
|
||||
* Copyright (C) 2014 Floens |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
package org.floens.chan.core.model.json.site; |
||||
|
||||
import com.google.gson.annotations.SerializedName; |
||||
|
||||
public class SiteConfig { |
||||
@SerializedName("external") |
||||
public boolean external; |
||||
|
||||
@SerializedName("internal_site_id") |
||||
public int classId; |
||||
} |
@ -0,0 +1,14 @@ |
||||
package org.floens.chan.core.site; |
||||
|
||||
|
||||
public interface Resolvable { |
||||
enum ResolveResult { |
||||
NO, |
||||
NAME_MATCH, |
||||
FULL_MATCH |
||||
} |
||||
|
||||
ResolveResult resolve(String value); |
||||
|
||||
Class<? extends Site> getSiteClass(); |
||||
} |
@ -0,0 +1,40 @@ |
||||
/* |
||||
* Clover - 4chan browser https://github.com/Floens/Clover/
|
||||
* Copyright (C) 2014 Floens |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
package org.floens.chan.core.site; |
||||
|
||||
|
||||
import org.floens.chan.core.model.json.site.SiteConfig; |
||||
import org.floens.chan.core.model.json.site.SiteUserSettings; |
||||
|
||||
public abstract class SiteBase implements Site { |
||||
protected int id; |
||||
protected SiteConfig config; |
||||
protected SiteUserSettings userSettings; |
||||
|
||||
@Override |
||||
public void initialize(int id, SiteConfig config, SiteUserSettings userSettings) { |
||||
this.id = id; |
||||
this.config = config; |
||||
this.userSettings = userSettings; |
||||
} |
||||
|
||||
@Override |
||||
public int id() { |
||||
return id; |
||||
} |
||||
} |
@ -0,0 +1,183 @@ |
||||
/* |
||||
* Clover - 4chan browser https://github.com/Floens/Clover/
|
||||
* Copyright (C) 2014 Floens |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
package org.floens.chan.core.site; |
||||
|
||||
|
||||
import android.util.Pair; |
||||
|
||||
import com.google.gson.Gson; |
||||
|
||||
import org.floens.chan.core.database.DatabaseManager; |
||||
import org.floens.chan.core.model.json.site.SiteConfig; |
||||
import org.floens.chan.core.model.json.site.SiteUserSettings; |
||||
import org.floens.chan.core.model.orm.SiteModel; |
||||
import org.floens.chan.core.site.sites.chan4.Chan4; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import javax.inject.Inject; |
||||
import javax.inject.Singleton; |
||||
|
||||
@Singleton |
||||
public class SiteManager { |
||||
@Inject |
||||
DatabaseManager databaseManager; |
||||
|
||||
private SiteResolver resolver; |
||||
|
||||
private Gson gson = new Gson(); |
||||
|
||||
@Inject |
||||
public SiteManager() { |
||||
resolver = new SiteResolver(); |
||||
} |
||||
|
||||
public void addSite(String url, SiteAddCallback callback) { |
||||
SiteResolver.SiteResolverResult resolve = resolver.resolve(url); |
||||
|
||||
Site site; |
||||
if (resolve.match == SiteResolver.SiteResolverResult.Match.BUILTIN) { |
||||
site = instantiateSiteClass(resolve.builtinResult); |
||||
} else if (resolve.match == SiteResolver.SiteResolverResult.Match.EXTERNAL) { |
||||
callback.onSiteAddFailed("external todo"); |
||||
return; |
||||
} else { |
||||
callback.onSiteAddFailed("not a url"); |
||||
return; |
||||
} |
||||
|
||||
site = createNewSite(site); |
||||
|
||||
List<Site> newAllSites = new ArrayList<>(Sites.ALL_SITES); |
||||
newAllSites.add(site); |
||||
Sites.initialize(newAllSites); |
||||
|
||||
callback.onSiteAdded(site); |
||||
} |
||||
|
||||
public void initialize() { |
||||
List<Site> sites = loadSitesFromDatabase(); |
||||
|
||||
if (sites.isEmpty()) { |
||||
Site site = new Chan4(); |
||||
|
||||
SiteConfig config = new SiteConfig(); |
||||
config.classId = Sites.SITE_CLASSES.indexOfValue(site.getClass()); |
||||
config.external = false; |
||||
|
||||
SiteUserSettings userSettings = new SiteUserSettings(); |
||||
|
||||
SiteModel siteModel = new SiteModel(); |
||||
storeConfigFields(siteModel, config, userSettings); |
||||
siteModel = databaseManager.runTaskSync(databaseManager.getDatabaseSiteManager().add(siteModel)); |
||||
databaseManager.runTaskSync(databaseManager.getDatabaseSiteManager().updateId(siteModel, 0)); |
||||
|
||||
sites.add(site); |
||||
} |
||||
|
||||
Sites.initialize(sites); |
||||
} |
||||
|
||||
private List<Site> loadSitesFromDatabase() { |
||||
List<Site> sites = new ArrayList<>(); |
||||
|
||||
List<SiteModel> siteModels = databaseManager.runTaskSync(databaseManager.getDatabaseSiteManager().getAll()); |
||||
|
||||
for (SiteModel siteModel : siteModels) { |
||||
Pair<SiteConfig, SiteUserSettings> configPair = loadConfigFields(siteModel); |
||||
SiteConfig config = configPair.first; |
||||
SiteUserSettings userSettings = configPair.second; |
||||
|
||||
Site site = loadSiteFromModel(siteModel, config, userSettings); |
||||
sites.add(site); |
||||
} |
||||
|
||||
return sites; |
||||
} |
||||
|
||||
private Site createNewSite(Site site) { |
||||
SiteConfig config = new SiteConfig(); |
||||
config.classId = Sites.SITE_CLASSES.indexOfValue(site.getClass()); |
||||
config.external = false; |
||||
|
||||
SiteUserSettings userSettings = new SiteUserSettings(); |
||||
|
||||
SiteModel siteModel = createNewSiteModel(site, config, userSettings); |
||||
|
||||
initializeSite(site, siteModel.id, config, userSettings); |
||||
|
||||
return site; |
||||
} |
||||
|
||||
private SiteModel createNewSiteModel(Site site, SiteConfig config, SiteUserSettings userSettings) { |
||||
SiteModel siteModel = new SiteModel(); |
||||
storeConfigFields(siteModel, config, userSettings); |
||||
siteModel = databaseManager.runTaskSync(databaseManager.getDatabaseSiteManager().add(siteModel)); |
||||
return siteModel; |
||||
} |
||||
|
||||
private void storeConfigFields(SiteModel siteModel, SiteConfig config, SiteUserSettings userSettings) { |
||||
siteModel.configuration = gson.toJson(config); |
||||
siteModel.userSettings = gson.toJson(userSettings); |
||||
} |
||||
|
||||
private Pair<SiteConfig, SiteUserSettings> loadConfigFields(SiteModel siteModel) { |
||||
SiteConfig config = gson.fromJson(siteModel.configuration, SiteConfig.class); |
||||
SiteUserSettings userSettings = gson.fromJson(siteModel.userSettings, SiteUserSettings.class); |
||||
return Pair.create(config, userSettings); |
||||
} |
||||
|
||||
private Site loadSiteFromModel(SiteModel model, SiteConfig config, SiteUserSettings userSettings) { |
||||
Site site = instantiateSiteFromConfig(config); |
||||
return initializeSite(site, model.id, config, userSettings); |
||||
} |
||||
|
||||
private Site initializeSite(Site site, int id, SiteConfig config, SiteUserSettings userSettings) { |
||||
site.initialize(id, config, userSettings); |
||||
return site; |
||||
} |
||||
|
||||
private Site instantiateSiteFromConfig(SiteConfig siteConfig) { |
||||
int siteClassId = siteConfig.classId; |
||||
Class<? extends Site> clazz = Sites.SITE_CLASSES.get(siteClassId); |
||||
if (clazz == null) { |
||||
throw new IllegalArgumentException(); |
||||
} |
||||
return instantiateSiteClass(clazz); |
||||
} |
||||
|
||||
private Site instantiateSiteClass(Class<? extends Site> clazz) { |
||||
Site site; |
||||
//noinspection TryWithIdenticalCatches
|
||||
try { |
||||
site = clazz.newInstance(); |
||||
} catch (InstantiationException e) { |
||||
throw new IllegalArgumentException(); |
||||
} catch (IllegalAccessException e) { |
||||
throw new IllegalArgumentException(); |
||||
} |
||||
return site; |
||||
} |
||||
|
||||
public interface SiteAddCallback { |
||||
void onSiteAdded(Site site); |
||||
|
||||
void onSiteAddFailed(String message); |
||||
} |
||||
} |
@ -0,0 +1,81 @@ |
||||
/* |
||||
* Clover - 4chan browser https://github.com/Floens/Clover/
|
||||
* Copyright (C) 2014 Floens |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
package org.floens.chan.core.site; |
||||
|
||||
|
||||
import java.util.List; |
||||
|
||||
import okhttp3.HttpUrl; |
||||
|
||||
class SiteResolver { |
||||
SiteResolverResult resolve(String url) { |
||||
List<Resolvable> resolvables = Sites.RESOLVABLES; |
||||
|
||||
HttpUrl httpUrl = HttpUrl.parse(url); |
||||
|
||||
if (httpUrl == null) { |
||||
httpUrl = HttpUrl.parse("https://" + url); |
||||
} |
||||
|
||||
if (httpUrl != null) { |
||||
if (httpUrl.host().indexOf('.') < 0) { |
||||
httpUrl = null; |
||||
} |
||||
} |
||||
|
||||
if (httpUrl == null) { |
||||
for (Resolvable resolvable : resolvables) { |
||||
if (resolvable.resolve(url) == Resolvable.ResolveResult.NAME_MATCH) { |
||||
return new SiteResolverResult(SiteResolverResult.Match.BUILTIN, resolvable.getSiteClass(), null); |
||||
} |
||||
} |
||||
|
||||
return new SiteResolverResult(SiteResolverResult.Match.NONE, null, null); |
||||
} |
||||
|
||||
if (!httpUrl.scheme().equals("https")) { |
||||
httpUrl = httpUrl.newBuilder().scheme("https").build(); |
||||
} |
||||
|
||||
for (Resolvable resolvable : resolvables) { |
||||
if (resolvable.resolve(httpUrl.toString()) == Resolvable.ResolveResult.FULL_MATCH) { |
||||
return new SiteResolverResult(SiteResolverResult.Match.BUILTIN, resolvable.getSiteClass(), null); |
||||
} |
||||
} |
||||
|
||||
return new SiteResolverResult(SiteResolverResult.Match.EXTERNAL, null, httpUrl); |
||||
} |
||||
|
||||
static class SiteResolverResult { |
||||
enum Match { |
||||
NONE, |
||||
BUILTIN, |
||||
EXTERNAL |
||||
} |
||||
|
||||
Match match; |
||||
Class<? extends Site> builtinResult; |
||||
HttpUrl externalResult; |
||||
|
||||
public SiteResolverResult(Match match, Class<? extends Site> builtinResult, HttpUrl externalResult) { |
||||
this.match = match; |
||||
this.builtinResult = builtinResult; |
||||
this.externalResult = externalResult; |
||||
} |
||||
} |
||||
} |
@ -1,44 +1,52 @@ |
||||
package org.floens.chan.core.site; |
||||
|
||||
import android.content.SharedPreferences; |
||||
import android.util.SparseArray; |
||||
|
||||
import org.floens.chan.core.site.sites.chan4.Chan4; |
||||
import org.floens.chan.utils.AndroidUtils; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
public class Sites { |
||||
public static final Chan4 CHAN4 = new Chan4(); |
||||
public static final SparseArray<Class<? extends Site>> SITE_CLASSES = new SparseArray<>(); |
||||
|
||||
public static final List<? extends Site> ALL_SITES = Arrays.asList( |
||||
CHAN4 |
||||
); |
||||
static { |
||||
// This id-siteclass mapping is used to look up the correct site class at deserialization.
|
||||
// This differs from the Site.id() id, that id is used for site instance linking, this is just to
|
||||
// find the correct class to use.
|
||||
SITE_CLASSES.put(0, Chan4.class); |
||||
} |
||||
|
||||
private static final Site[] BY_ID; |
||||
public static final List<Resolvable> RESOLVABLES = new ArrayList<>(); |
||||
|
||||
static { |
||||
int highestId = 0; |
||||
RESOLVABLES.add(Chan4.RESOLVABLE); |
||||
} |
||||
|
||||
public static final List<Site> ALL_SITES = new ArrayList<>(); |
||||
|
||||
@Deprecated |
||||
private static Site defaultSite; |
||||
|
||||
public static Site forId(int id) { |
||||
// TODO: better datastructure
|
||||
for (Site site : ALL_SITES) { |
||||
if (site.id() > highestId) { |
||||
highestId = site.id(); |
||||
if (site.id() == id) { |
||||
return site; |
||||
} |
||||
} |
||||
BY_ID = new Site[highestId + 1]; |
||||
for (Site site : ALL_SITES) { |
||||
BY_ID[site.id()] = site; |
||||
} |
||||
} |
||||
|
||||
public static Site forId(int id) { |
||||
return BY_ID[id]; |
||||
return null; |
||||
} |
||||
|
||||
@Deprecated |
||||
public static Site defaultSite() { |
||||
return CHAN4; |
||||
return defaultSite; |
||||
} |
||||
|
||||
public static SharedPreferences getPreferences(Site site) { |
||||
return AndroidUtils.getPreferences(site.id() + "_site_preferences"); |
||||
static void initialize(List<Site> sites) { |
||||
Sites.defaultSite = sites.isEmpty() ? null : sites.get(0); |
||||
Sites.ALL_SITES.clear(); |
||||
Sites.ALL_SITES.addAll(sites); |
||||
} |
||||
} |
||||
|
Loading…
Reference in new issue