From 7ef0243922914d39ce0d635da274cbf1ade231d1 Mon Sep 17 00:00:00 2001 From: Floens Date: Sat, 31 Mar 2018 19:38:51 +0200 Subject: [PATCH] add boardrepository make siterepository the owner of site instances --- .../src/main/java/org/floens/chan/Chan.java | 8 +- .../core/database/DatabaseBoardManager.java | 123 ++++++++- .../database/DatabaseLoadableManager.java | 6 +- .../chan/core/database/DatabaseManager.java | 41 ++- .../database/DatabaseSavedReplyManager.java | 4 +- .../chan/core/manager/BoardManager.java | 121 ++------- .../org/floens/chan/core/model/orm/Board.java | 31 ++- .../core/presenter/BoardsMenuPresenter.java | 12 +- .../chan/core/presenter/BrowsePresenter.java | 12 +- .../core/presenter/SitesSetupPresenter.java | 87 ++++-- .../chan/core/repository/BoardRepository.java | 189 +++++++++++++ .../chan/core/repository/SiteRepository.java | 249 ++++++++++++++++++ .../org/floens/chan/core/site/SiteBase.java | 16 +- .../floens/chan/core/site/SiteRepository.java | 63 ----- .../floens/chan/core/site/SiteResolver.java | 15 +- .../floens/chan/core/site/SiteService.java | 123 +-------- .../java/org/floens/chan/core/site/Sites.java | 35 --- .../chan/ui/activity/StartActivity.java | 6 +- .../ui/controller/SitesSetupController.java | 30 ++- .../floens/chan/ui/layout/FilterLayout.java | 7 +- 20 files changed, 765 insertions(+), 413 deletions(-) create mode 100644 Clover/app/src/main/java/org/floens/chan/core/repository/BoardRepository.java create mode 100644 Clover/app/src/main/java/org/floens/chan/core/repository/SiteRepository.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/core/site/SiteRepository.java delete mode 100644 Clover/app/src/main/java/org/floens/chan/core/site/Sites.java diff --git a/Clover/app/src/main/java/org/floens/chan/Chan.java b/Clover/app/src/main/java/org/floens/chan/Chan.java index bc3822a1..3a2d404b 100644 --- a/Clover/app/src/main/java/org/floens/chan/Chan.java +++ b/Clover/app/src/main/java/org/floens/chan/Chan.java @@ -31,6 +31,7 @@ import org.floens.chan.core.database.DatabaseManager; import org.floens.chan.core.di.AppModule; import org.floens.chan.core.di.NetModule; import org.floens.chan.core.di.UserAgentProvider; +import org.floens.chan.core.manager.BoardManager; import org.floens.chan.core.site.SiteService; import org.floens.chan.utils.AndroidUtils; import org.floens.chan.utils.Logger; @@ -52,11 +53,14 @@ public class Chan extends Application implements UserAgentProvider, Application. private String userAgent; private int activityForegroundCounter = 0; + @Inject + DatabaseManager databaseManager; + @Inject SiteService siteService; @Inject - DatabaseManager databaseManager; + BoardManager boardManager; private Feather feather; @@ -94,6 +98,8 @@ public class Chan extends Application implements UserAgentProvider, Application. initializeGraph(); siteService.initialize(); + boardManager.initialize(); + databaseManager.initializeAndTrim(); Time.endTiming("Initializing application", startTime); diff --git a/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseBoardManager.java b/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseBoardManager.java index e4756135..9c343950 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseBoardManager.java +++ b/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseBoardManager.java @@ -1,14 +1,23 @@ package org.floens.chan.core.database; +import android.annotation.SuppressLint; +import android.util.Pair; + import com.j256.ormlite.stmt.PreparedUpdate; import com.j256.ormlite.stmt.QueryBuilder; import com.j256.ormlite.stmt.SelectArg; import com.j256.ormlite.stmt.UpdateBuilder; import org.floens.chan.core.model.orm.Board; +import org.floens.chan.core.model.orm.SiteModel; import org.floens.chan.core.site.Site; +import org.floens.chan.utils.Time; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.Callable; public class DatabaseBoardManager { @@ -29,9 +38,9 @@ public class DatabaseBoardManager { .and().eq("value", board.code); Board existing = q.queryForFirst(); if (existing != null) { - existing.updateExcudingUserFields(board); + existing.updateExcludingUserFields(board); helper.boardsDao.update(existing); - board.updateExcudingUserFields(existing); + board.updateExcludingUserFields(existing); } else { helper.boardsDao.create(board); } @@ -80,22 +89,62 @@ public class DatabaseBoardManager { }; } - public Callable createAll(final List boards) { + public Callable createAll(final Site site, final List boards) { return () -> { - // TODO: optimize + long start = Time.startTiming(); + + List allFromDb = helper.boardsDao.queryForEq("site", site.id()); + Map byCodeFromDb = new HashMap<>(); + for (Board board : allFromDb) { + byCodeFromDb.put(board.code, board); + board.site = site; + } + + List toCreate = new ArrayList<>(); + List> toUpdate = new ArrayList<>(); for (Board board : boards) { + if (byCodeFromDb.containsKey(board.code)) { + Board dbBoard = byCodeFromDb.get(board.code); + if (!dbBoard.propertiesEqual(board)) { + toUpdate.add(new Pair<>(dbBoard, board)); + } + } else { + toCreate.add(board); + } + } + + if (!toCreate.isEmpty()) { + for (Board board : toCreate) { + helper.boardsDao.create(board); + } + } + + if (!toUpdate.isEmpty()) { + for (Pair pair : toUpdate) { + Board dbBoard = pair.first; + Board newPropertiesBoard = pair.second; + + dbBoard.updateExcludingUserFields(newPropertiesBoard); + helper.boardsDao.update(dbBoard); + } + } + + /*for (Board board : boards) { QueryBuilder q = helper.boardsDao.queryBuilder(); q.where().eq("site", board.getSite().id()) .and().eq("value", board.code); Board existing = q.queryForFirst(); if (existing != null) { - existing.updateExcudingUserFields(board); + existing.updateExcludingUserFields(board); helper.boardsDao.update(existing); - board.updateExcudingUserFields(existing); + board.updateExcludingUserFields(existing); } else { helper.boardsDao.create(board); } - } + }*/ + + Time.endTiming("createAll boards " + + toCreate.size() + ", " + toUpdate.size(), start); return null; }; @@ -116,6 +165,66 @@ public class DatabaseBoardManager { }; } + @SuppressLint("UseSparseArrays") + public Callable>>> getBoardsForAllSitesOrdered(List sites) { + return () -> { + long start = Time.startTiming(); + + // Query the orders of the sites. + QueryBuilder q = helper.siteDao.queryBuilder(); + q.selectColumns("id", "order"); + List modelsWithOrder = q.query(); + Map ordering = new HashMap<>(); + for (SiteModel siteModel : modelsWithOrder) { + ordering.put(siteModel.id, siteModel.order); + } + + List sitesOrdered = new ArrayList<>(sites); + // Sort the given sites array with these orders. + Collections.sort(sitesOrdered, + (lhs, rhs) -> ordering.get(lhs.id()) - ordering.get(rhs.id())); + + // Query all boards belonging to any of these sites. + List siteIds = new ArrayList<>(sitesOrdered.size()); + for (Site site : sitesOrdered) { + siteIds.add(site.id()); + } + List allBoards = helper.boardsDao.queryBuilder() + .where().in("site", siteIds) + .query(); + + // Map the boards from siteId to a list of boards. + Map sitesById = new HashMap<>(); + for (Site site : sites) { + sitesById.put(site.id(), site); + } + Map> bySite = new HashMap<>(); + for (Board board : allBoards) { + board.site = sitesById.get(board.siteId); + + List boards = bySite.get(board.siteId); + if (boards == null) { + boards = new ArrayList<>(); + bySite.put(board.siteId, boards); + } + boards.add(board); + } + + // And map the site to the board, and order these boards. + List>> res = new ArrayList<>(); + for (Site site : sitesOrdered) { + List siteBoards = bySite.get(site.id()); + if (siteBoards == null) siteBoards = new ArrayList<>(); + Collections.sort(siteBoards, (lhs, rhs) -> lhs.order - rhs.order); + res.add(new Pair<>(site, siteBoards)); + } + + Time.endTiming("getBoardsForAllSitesOrdered", start); + + return res; + }; + } + public Callable> getSiteBoards(final Site site) { return () -> { List boards = helper.boardsDao.queryBuilder() diff --git a/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseLoadableManager.java b/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseLoadableManager.java index 8921412c..32bc5888 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseLoadableManager.java +++ b/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseLoadableManager.java @@ -22,7 +22,7 @@ import android.util.Log; import com.j256.ormlite.stmt.QueryBuilder; import org.floens.chan.core.model.orm.Loadable; -import org.floens.chan.core.site.Sites; +import org.floens.chan.core.repository.SiteRepository; import org.floens.chan.utils.Logger; import org.floens.chan.utils.Time; @@ -124,7 +124,7 @@ public class DatabaseLoadableManager { // Add it to the cache, refresh contents helper.loadableDao.refresh(loadable); - loadable.site = Sites.forId(loadable.siteId); + loadable.site = SiteRepository.forId(loadable.siteId); loadable.board = loadable.site.board(loadable.boardCode); cachedLoadables.put(loadable, loadable); return loadable; @@ -165,7 +165,7 @@ public class DatabaseLoadableManager { result = loadable; } else { Log.d(TAG, "Loadable found in db"); - result.site = Sites.forId(result.siteId); + result.site = SiteRepository.forId(result.siteId); result.board = result.site.board(result.boardCode); } diff --git a/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseManager.java b/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseManager.java index 36fbacd2..5e8dab4b 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseManager.java +++ b/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseManager.java @@ -33,8 +33,9 @@ import java.sql.SQLException; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -70,7 +71,10 @@ public class DatabaseManager { @Inject public DatabaseManager(Context context) { - backgroundExecutor = Executors.newSingleThreadExecutor(); + backgroundExecutor = new ThreadPoolExecutor( + 1, 1, + 1000L, TimeUnit.DAYS, + new LinkedBlockingQueue<>()); helper = new DatabaseHelper(context); databaseLoadableManager = new DatabaseLoadableManager(this, helper); @@ -81,10 +85,18 @@ public class DatabaseManager { databaseBoardManager = new DatabaseBoardManager(this, helper); databaseSiteManager = new DatabaseSiteManager(this, helper); databaseHideManager = new DatabaseHideManager(this, helper); - initialize(); EventBus.getDefault().register(this); } + public void initializeAndTrim() { + // Loads data into fields. + runTask(databaseSavedReplyManager.load()); + + // Only trims. + runTaskAsync(databaseHistoryManager.load()); + runTaskAsync(databaseHideManager.load()); + } + public DatabasePinManager getDatabasePinManager() { return databasePinManager; } @@ -116,29 +128,20 @@ public class DatabaseManager { public DatabaseHideManager getDatabaseHideManager() { return databaseHideManager; } - // Called when the app changes foreground state + public void onEvent(Chan.ForegroundChangedMessage message) { if (!message.inForeground) { runTaskAsync(databaseLoadableManager.flush()); } } - private void initialize() { - // Loads data into fields. - runTask(databaseSavedReplyManager.load()); - - // Only trims. - runTaskAsync(databaseHistoryManager.load()); - runTaskAsync(databaseHideManager.load()); - } - /** * Reset all tables in the database. Used for the developer screen. */ public void reset() { helper.reset(); - initialize(); + initializeAndTrim(); } /** @@ -187,7 +190,8 @@ public class DatabaseManager { } public void runTaskAsync(final Callable taskCallable) { - runTaskAsync(taskCallable, null); + runTaskAsync(taskCallable, result -> { + }); } public void runTaskAsync(final Callable taskCallable, final TaskResult taskResult) { @@ -254,12 +258,7 @@ public class DatabaseManager { try { final T result = TransactionManager.callInTransaction(helper.getConnectionSource(), taskCallable); if (taskResult != null) { - new Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - taskResult.onComplete(result); - } - }); + new Handler(Looper.getMainLooper()).post(() -> taskResult.onComplete(result)); } return result; } catch (Exception e) { diff --git a/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseSavedReplyManager.java b/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseSavedReplyManager.java index 402ff716..49d38f52 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseSavedReplyManager.java +++ b/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseSavedReplyManager.java @@ -24,7 +24,7 @@ import com.j256.ormlite.table.TableUtils; import org.floens.chan.core.model.orm.Board; import org.floens.chan.core.model.orm.SavedReply; -import org.floens.chan.core.site.Sites; +import org.floens.chan.core.repository.SiteRepository; import org.floens.chan.utils.Time; import java.util.ArrayList; @@ -92,7 +92,7 @@ public class DatabaseSavedReplyManager { for (int i = 0; i < all.size(); i++) { SavedReply savedReply = all.get(i); - savedReply.site = Sites.forId(savedReply.siteId); + savedReply.site = SiteRepository.forId(savedReply.siteId); List list = savedRepliesByNo.get(savedReply.no); if (list == null) { diff --git a/Clover/app/src/main/java/org/floens/chan/core/manager/BoardManager.java b/Clover/app/src/main/java/org/floens/chan/core/manager/BoardManager.java index 6d89e382..56c5a69f 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/manager/BoardManager.java +++ b/Clover/app/src/main/java/org/floens/chan/core/manager/BoardManager.java @@ -17,20 +17,11 @@ */ package org.floens.chan.core.manager; -import android.util.Pair; - -import org.floens.chan.core.database.DatabaseBoardManager; -import org.floens.chan.core.database.DatabaseManager; import org.floens.chan.core.model.orm.Board; +import org.floens.chan.core.repository.BoardRepository; import org.floens.chan.core.site.Site; -import org.floens.chan.core.site.SiteService; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; import java.util.List; -import java.util.Observable; -import java.util.Observer; import javax.inject.Inject; import javax.inject.Singleton; @@ -48,46 +39,22 @@ import javax.inject.Singleton; * favorite board list, along with a {@link Board#order} in which they appear. */ @Singleton -public class BoardManager implements Observer { +public class BoardManager { private static final String TAG = "BoardManager"; - private static final Comparator ORDER_SORT = (lhs, rhs) -> lhs.order - rhs.order; - - private final DatabaseManager databaseManager; - private final DatabaseBoardManager databaseBoardManager; - private final SiteService siteService; - private final SiteService.SitesChangedObservable sitesChangedObservable; - - private final AllBoards allBoardsObservable = new AllBoards(); - private final SavedBoards savedBoardsObservable = new SavedBoards(); - - private final List>> sitesWithBoards = new ArrayList<>(); - private final List>> sitesWithSavedBoards = new ArrayList<>(); + private final BoardRepository boardRepository; @Inject - public BoardManager(DatabaseManager databaseManager, SiteService siteService) { - this.databaseManager = databaseManager; - this.siteService = siteService; - - sitesChangedObservable = siteService.getSitesChangedObservable(); - - databaseBoardManager = databaseManager.getDatabaseBoardManager(); - - updateObservables(); - - sitesChangedObservable.addObserver(this); + public BoardManager(BoardRepository boardRepository) { + this.boardRepository = boardRepository; } - @Override - public void update(Observable o, Object arg) { - // If the sites changed (added, removed or reordered) we need to reload the boards. - if (o == sitesChangedObservable) { - updateObservables(); - } + public void initialize() { + boardRepository.initialize(); } - public void createAll(List boards) { - databaseManager.runTask(databaseBoardManager.createAll(boards)); + public void updateAvailableBoardsForSite(Site site, List boards) { + boardRepository.updateAvailableBoardsForSite(site, boards); } /** @@ -99,84 +66,34 @@ public class BoardManager implements Observer { * @return the board code with the same site and board code, or {@code null} if not found. */ public Board getBoard(Site site, String code) { - return databaseManager.runTask(databaseBoardManager.getBoard(site, code)); + return boardRepository.getFromCode(site, code); } public List getSiteBoards(Site site) { - List boards = databaseManager.runTask(databaseBoardManager.getSiteBoards(site)); - Collections.sort(boards, ORDER_SORT); - return boards; + return boardRepository.getSiteBoards(site); } public List getSiteSavedBoards(Site site) { - List boards = databaseManager.runTask(databaseBoardManager.getSiteSavedBoards(site)); - Collections.sort(boards, ORDER_SORT); - return boards; + return boardRepository.getSiteSavedBoards(site); } - public AllBoards getAllBoardsObservable() { - return allBoardsObservable; + public BoardRepository.SitesBoards getAllBoardsObservable() { + return boardRepository.getAll(); } - public SavedBoards getSavedBoardsObservable() { - return savedBoardsObservable; + public BoardRepository.SitesBoards getSavedBoardsObservable() { + return boardRepository.getSaved(); } public void updateBoardOrders(List boards) { - databaseManager.runTask(databaseBoardManager.updateOrders(boards)); - updateObservables(); + boardRepository.updateBoardOrders(boards); } public void setSaved(Board board, boolean saved) { - board.saved = saved; - databaseManager.runTask(databaseBoardManager.updateIncludingUserFields(board)); - updateObservables(); + boardRepository.setSaved(board, saved); } public void setAllSaved(List boards, boolean saved) { - for (Board board : boards) { - board.saved = saved; - } - databaseManager.runTask(databaseBoardManager.updateIncludingUserFields(boards)); - updateObservables(); - } - - private void updateObservables() { - sitesWithBoards.clear(); - for (Site site : siteService.getAllSitesInOrder()) { - List all = getSiteBoards(site); - sitesWithBoards.add(new Pair<>(site, all)); - - List saved = new ArrayList<>(); - for (Board siteBoard : all) { - if (siteBoard.saved) saved.add(siteBoard); - } - sitesWithSavedBoards.add(new Pair<>(site, saved)); - } - - allBoardsObservable.doNotify(); - savedBoardsObservable.doNotify(); - } - - public class AllBoards extends Observable { - private void doNotify() { - setChanged(); - notifyObservers(); - } - - public List>> get() { - return sitesWithBoards; - } - } - - public class SavedBoards extends Observable { - private void doNotify() { - setChanged(); - notifyObservers(); - } - - public List>> get() { - return sitesWithSavedBoards; - } + boardRepository.setAllSaved(boards, saved); } } diff --git a/Clover/app/src/main/java/org/floens/chan/core/model/orm/Board.java b/Clover/app/src/main/java/org/floens/chan/core/model/orm/Board.java index a6aecdaa..404886a9 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/model/orm/Board.java +++ b/Clover/app/src/main/java/org/floens/chan/core/model/orm/Board.java @@ -17,6 +17,7 @@ */ package org.floens.chan.core.model.orm; +import android.support.v4.util.ObjectsCompat; import android.text.TextUtils; import com.j256.ormlite.field.DatabaseField; @@ -180,7 +181,7 @@ public class Board implements SiteReference { * * @param o other board to update from. */ - public void updateExcudingUserFields(Board o) { + public void updateExcludingUserFields(Board o) { siteId = o.siteId; site = o.site; name = o.name; @@ -249,4 +250,32 @@ public class Board implements SiteReference { b.archive = archive; return b; } + + public boolean propertiesEqual(Board b) { + return name.equals(b.name) && + code.equals(b.code) && + workSafe == b.workSafe && + perPage == b.perPage && + pages == b.pages && + maxFileSize == b.maxFileSize && + maxWebmSize == b.maxWebmSize && + maxCommentChars == b.maxCommentChars && + bumpLimit == b.bumpLimit && + imageLimit == b.imageLimit && + cooldownThreads == b.cooldownThreads && + cooldownReplies == b.cooldownReplies && + cooldownImages == b.cooldownImages && + cooldownRepliesIntra == b.cooldownRepliesIntra && + cooldownImagesIntra == b.cooldownImagesIntra && + spoilers == b.spoilers && + customSpoilers == b.customSpoilers && + userIds == b.userIds && + codeTags == b.codeTags && + preuploadCaptcha == b.preuploadCaptcha && + countryFlags == b.countryFlags && + trollFlags == b.trollFlags && + mathTags == b.mathTags && + ObjectsCompat.equals(description, b.description) && + archive == b.archive; + } } diff --git a/Clover/app/src/main/java/org/floens/chan/core/presenter/BoardsMenuPresenter.java b/Clover/app/src/main/java/org/floens/chan/core/presenter/BoardsMenuPresenter.java index 0b09d853..63a6dd97 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/presenter/BoardsMenuPresenter.java +++ b/Clover/app/src/main/java/org/floens/chan/core/presenter/BoardsMenuPresenter.java @@ -18,10 +18,10 @@ package org.floens.chan.core.presenter; import android.support.annotation.Nullable; -import android.util.Pair; import org.floens.chan.core.manager.BoardManager; import org.floens.chan.core.model.orm.Board; +import org.floens.chan.core.repository.BoardRepository; import org.floens.chan.core.site.Site; import org.floens.chan.ui.helper.BoardHelper; @@ -34,7 +34,7 @@ import javax.inject.Inject; public class BoardsMenuPresenter implements Observer { private Callback callback; - private BoardManager.AllBoards allBoards; + private BoardRepository.SitesBoards allBoards; private Items items; @@ -89,14 +89,14 @@ public class BoardsMenuPresenter implements Observer { public Items() { } - public void update(List>> allBoards, String filter) { + public void update(List allBoards, String filter) { items.clear(); items.add(new Item(0, Item.Type.SEARCH)); - for (Pair> siteAndBoards : allBoards) { - Site site = siteAndBoards.first; - List boards = siteAndBoards.second; + for (BoardRepository.SiteBoards siteAndBoards : allBoards) { + Site site = siteAndBoards.site; + List boards = siteAndBoards.boards; items.add(new Item(itemIdCounter++, site)); diff --git a/Clover/app/src/main/java/org/floens/chan/core/presenter/BrowsePresenter.java b/Clover/app/src/main/java/org/floens/chan/core/presenter/BrowsePresenter.java index eb18707a..ef280195 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/presenter/BrowsePresenter.java +++ b/Clover/app/src/main/java/org/floens/chan/core/presenter/BrowsePresenter.java @@ -17,15 +17,13 @@ */ package org.floens.chan.core.presenter; -import android.util.Pair; - import org.floens.chan.core.database.DatabaseManager; import org.floens.chan.core.manager.BoardManager; import org.floens.chan.core.model.orm.Board; import org.floens.chan.core.model.orm.Loadable; +import org.floens.chan.core.repository.BoardRepository; import org.floens.chan.core.site.Site; -import java.util.List; import java.util.Observable; import java.util.Observer; @@ -39,7 +37,7 @@ public class BrowsePresenter implements Observer { private boolean hadBoards = false; private Board currentBoard; - private BoardManager.SavedBoards savedBoardsObservable; + private BoardRepository.SitesBoards savedBoardsObservable; @Inject public BrowsePresenter(DatabaseManager databaseManager, BoardManager boardManager) { @@ -99,9 +97,9 @@ public class BrowsePresenter implements Observer { } private Board firstBoard() { - for (Pair> siteListPair : savedBoardsObservable.get()) { - if (!siteListPair.second.isEmpty()) { - return siteListPair.second.get(0); + for (BoardRepository.SiteBoards item : savedBoardsObservable.get()) { + if (!item.boards.isEmpty()) { + return item.boards.get(0); } } return null; diff --git a/Clover/app/src/main/java/org/floens/chan/core/presenter/SitesSetupPresenter.java b/Clover/app/src/main/java/org/floens/chan/core/presenter/SitesSetupPresenter.java index da0899ea..abc6e6b7 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/presenter/SitesSetupPresenter.java +++ b/Clover/app/src/main/java/org/floens/chan/core/presenter/SitesSetupPresenter.java @@ -20,55 +20,78 @@ package org.floens.chan.core.presenter; import org.floens.chan.core.manager.BoardManager; import org.floens.chan.core.site.Site; +import org.floens.chan.core.repository.SiteRepository; import org.floens.chan.core.site.SiteService; import java.util.ArrayList; import java.util.List; +import java.util.Observable; +import java.util.Observer; import javax.inject.Inject; -public class SitesSetupPresenter { - private SiteService siteService; - private BoardManager boardManager; +public class SitesSetupPresenter implements Observer { + private final SiteService siteService; + private final SiteRepository siteRepository; + private final BoardManager boardManager; private Callback callback; private AddCallback addCallback; - private List sites = new ArrayList<>(); + private SiteRepository.Sites sites; + private List sitesShown = new ArrayList<>(); @Inject - public SitesSetupPresenter(SiteService siteService, BoardManager boardManager) { + public SitesSetupPresenter(SiteService siteService, SiteRepository siteRepository, + BoardManager boardManager) { this.siteService = siteService; + this.siteRepository = siteRepository; this.boardManager = boardManager; } public void create(Callback callback) { this.callback = callback; - sites.addAll(siteService.getAllSitesInOrder()); + sites = siteRepository.all(); + sites.addObserver(this); - this.callback.setAddedSites(sites); + sitesShown.addAll(sites.getAllInOrder()); - this.callback.setNextAllowed(!sites.isEmpty()); + updateSitesInUi(); - if (sites.isEmpty()) { + this.callback.setNextAllowed(!sitesShown.isEmpty()); + + if (sitesShown.isEmpty()) { callback.presentIntro(); } } + public void destroy() { + sites.deleteObserver(this); + } + + @Override + public void update(Observable o, Object arg) { + if (o == sites) { + sitesShown.clear(); + sitesShown.addAll(sites.getAllInOrder()); + updateSitesInUi(); + } + } + public void show() { - callback.setAddedSites(sites); + updateSitesInUi(); } public void move(int from, int to) { - Site item = sites.remove(from); - sites.add(to, item); + Site item = sitesShown.remove(from); + sitesShown.add(to, item); saveOrder(); - callback.setAddedSites(sites); + updateSitesInUi(); } public void onIntroDismissed() { - if (sites.isEmpty()) { + if (sitesShown.isEmpty()) { callback.showHint(); } } @@ -82,7 +105,7 @@ public class SitesSetupPresenter { } public boolean mayExit() { - return sites.size() > 0; + return sitesShown.size() > 0; } public void onShowDialogClicked() { @@ -111,17 +134,13 @@ public class SitesSetupPresenter { public void onDoneClicked() { } - public int getSiteBoardCount(Site site) { - return boardManager.getSiteSavedBoards(site).size(); - } - private void siteAdded(Site site) { - sites.add(site); + sitesShown.add(site); saveOrder(); - callback.setAddedSites(sites); + updateSitesInUi(); - callback.setNextAllowed(!sites.isEmpty()); + callback.setNextAllowed(!sitesShown.isEmpty()); } public void onSiteCellSettingsClicked(Site site) { @@ -129,18 +148,36 @@ public class SitesSetupPresenter { } private void saveOrder() { - siteService.updateOrdering(sites); + siteService.updateOrdering(sitesShown); + } + + private void updateSitesInUi() { + List r = new ArrayList<>(); + for (Site site : sitesShown) { + r.add(new SiteBoardCount(site, boardManager.getSiteSavedBoards(site).size())); + } + callback.setSites(r); + } + + public class SiteBoardCount { + public Site site; + public int boardCount; + + public SiteBoardCount(Site site, int boardCount) { + this.site = site; + this.boardCount = boardCount; + } } public interface Callback { + void setSites(List sites); + void presentIntro(); void showHint(); void showAddDialog(); - void setAddedSites(List sites); - void setNextAllowed(boolean nextAllowed); void openSiteConfiguration(Site site); diff --git a/Clover/app/src/main/java/org/floens/chan/core/repository/BoardRepository.java b/Clover/app/src/main/java/org/floens/chan/core/repository/BoardRepository.java new file mode 100644 index 00000000..44b67661 --- /dev/null +++ b/Clover/app/src/main/java/org/floens/chan/core/repository/BoardRepository.java @@ -0,0 +1,189 @@ +/* + * 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 . + */ +package org.floens.chan.core.repository; + +import android.util.Pair; + +import org.floens.chan.core.database.DatabaseBoardManager; +import org.floens.chan.core.database.DatabaseManager; +import org.floens.chan.core.model.orm.Board; +import org.floens.chan.core.site.Site; +import org.floens.chan.utils.Time; + +import java.util.ArrayList; +import java.util.List; +import java.util.Observable; +import java.util.Observer; + +import javax.inject.Inject; +import javax.inject.Singleton; + +@Singleton +public class BoardRepository implements Observer { + private final DatabaseManager databaseManager; + private final DatabaseBoardManager databaseBoardManager; + + private final SiteRepository siteRepository; + private final SiteRepository.Sites allSites; + + private SitesBoards allBoards = new SitesBoards(); + private SitesBoards savedBoards = new SitesBoards(); + + @Inject + public BoardRepository(DatabaseManager databaseManager, SiteRepository siteRepository) { + this.databaseManager = databaseManager; + databaseBoardManager = databaseManager.getDatabaseBoardManager(); + + this.siteRepository = siteRepository; + + allSites = this.siteRepository.all(); + allSites.addObserver(this); + } + + public void initialize() { + updateObservablesSync(); + } + + @Override + public void update(Observable o, Object arg) { + if (o == allSites) { + updateObservablesAsync(); + } + } + + public void updateAvailableBoardsForSite(Site site, List availableBoards) { + databaseManager.runTask(databaseBoardManager.createAll(site, availableBoards)); + } + + public Board getFromCode(Site site, String code) { + for (SiteBoards siteBoards : allBoards.get()) { + if (siteBoards.site.id() == site.id()) { + for (Board board : siteBoards.boards) { + if (board.code.equals(code)) { + return board; + } + + } + return null; + } + } + + return null; + } + + public SitesBoards getAll() { + return allBoards; + } + + public SitesBoards getSaved() { + return savedBoards; + } + + public List getSiteBoards(Site site) { + for (SiteBoards item : allBoards.siteBoards) { + if (item.site.id() == site.id()) { + return item.boards; + } + } + return new ArrayList<>(); + } + + public List getSiteSavedBoards(Site site) { + for (SiteBoards item : savedBoards.siteBoards) { + if (item.site.id() == site.id()) { + return item.boards; + } + } + return new ArrayList<>(); + } + + public void updateBoardOrders(List boards) { + databaseManager.runTaskAsync(databaseBoardManager.updateOrders(boards), + (e) -> updateObservablesAsync()); + } + + public void setSaved(Board board, boolean saved) { + board.saved = saved; + databaseManager.runTaskAsync(databaseBoardManager.updateIncludingUserFields(board), + (e) -> updateObservablesAsync()); + } + + public void setAllSaved(List boards, boolean saved) { + for (Board board : boards) { + board.saved = saved; + } + databaseManager.runTaskAsync(databaseBoardManager.updateIncludingUserFields(boards), + (e) -> updateObservablesAsync()); + } + + private void updateObservablesSync() { + long start = Time.startTiming(); + updateWith(databaseManager.runTask( + databaseBoardManager.getBoardsForAllSitesOrdered(allSites.getAll()))); + Time.endTiming("BoardRepository.updateObservablesSync", start); + } + + private void updateObservablesAsync() { + databaseManager.runTaskAsync( + databaseBoardManager.getBoardsForAllSitesOrdered(allSites.getAll()), + this::updateWith); + } + + private void updateWith(List>> databaseData) { + List all = new ArrayList<>(); + List saved = new ArrayList<>(); + for (Pair> item : databaseData) { + all.add(new SiteBoards(item.first, item.second)); + + List savedBoards = new ArrayList<>(); + for (Board board : item.second) { + if (board.saved) savedBoards.add(board); + } + saved.add(new SiteBoards(item.first, savedBoards)); + } + + allBoards.set(all); + savedBoards.set(saved); + + allBoards.notifyObservers(); + savedBoards.notifyObservers(); + } + + public class SitesBoards extends Observable { + private List siteBoards = new ArrayList<>(); + + public void set(List siteBoards) { + this.siteBoards = siteBoards; + setChanged(); + } + + public List get() { + return siteBoards; + } + } + + public class SiteBoards { + public final Site site; + public final List boards; + + public SiteBoards(Site site, List boards) { + this.site = site; + this.boards = boards; + } + } +} diff --git a/Clover/app/src/main/java/org/floens/chan/core/repository/SiteRepository.java b/Clover/app/src/main/java/org/floens/chan/core/repository/SiteRepository.java new file mode 100644 index 00000000..ab99f84a --- /dev/null +++ b/Clover/app/src/main/java/org/floens/chan/core/repository/SiteRepository.java @@ -0,0 +1,249 @@ +package org.floens.chan.core.repository; + +import android.util.Pair; +import android.util.SparseArray; + +import org.floens.chan.core.database.DatabaseManager; +import org.floens.chan.core.model.json.site.SiteConfig; +import org.floens.chan.core.model.orm.SiteModel; +import org.floens.chan.core.settings.json.JsonSettings; +import org.floens.chan.core.site.Site; +import org.floens.chan.core.site.SiteRegistry; +import org.floens.chan.core.site.sites.chan4.Chan4; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Observable; + +import javax.inject.Inject; +import javax.inject.Singleton; + +@Singleton +public class SiteRepository { + private DatabaseManager databaseManager; + + private Sites sitesObservable = new Sites(); + + // Shortcut + private static SiteRepository instance; + + public static Site forId(int id) { + return instance.sitesObservable.forId(id); + } + + @Inject + public SiteRepository(DatabaseManager databaseManager) { + instance = this; + this.databaseManager = databaseManager; + } + + public Sites all() { + return sitesObservable; + } + + public SiteModel byId(int id) { + return databaseManager.runTask(databaseManager.getDatabaseSiteManager() + .byId(id)); + } + + public void setId(SiteModel siteModel, int id) { + databaseManager.runTask(databaseManager.getDatabaseSiteManager() + .updateId(siteModel, id)); + } + + public void updateSiteUserSettingsAsync(SiteModel siteModel, JsonSettings jsonSettings) { + siteModel.storeUserSettings(jsonSettings); + databaseManager.runTaskAsync(databaseManager.getDatabaseSiteManager() + .update(siteModel)); + } + + public Map getOrdering() { + return databaseManager.runTask(databaseManager.getDatabaseSiteManager().getOrdering()); + } + + public void updateSiteOrderingAsync(List sites) { + List ids = new ArrayList<>(sites.size()); + for (Site site : sites) { + ids.add(site.id()); + } + + databaseManager.runTaskAsync( + databaseManager.getDatabaseSiteManager().updateOrdering(ids), + (r) -> { + sitesObservable.wasReordered(); + sitesObservable.notifyObservers(); + }); + } + + public void initialize() { + List sites = new ArrayList<>(); + + List models = databaseManager.runTask( + databaseManager.getDatabaseSiteManager().getAll()); + + for (SiteModel siteModel : models) { + SiteConfigSettingsHolder holder = instantiateSiteFromModel(siteModel); + + Site site = holder.site; + SiteConfig config = holder.config; + JsonSettings settings = holder.settings; + + site.initialize(siteModel.id, config, settings); + + sites.add(site); + } + + sitesObservable.addAll(sites); + + for (Site site : sites) { + site.postInitialize(); + } + + sitesObservable.notifyObservers(); + } + + // Called before #initialize to add the old 4chan site when the database was upgraded from + // an older version. It only adds the model to the database with id 0. + public void addLegacySite() { + Site site = new Chan4(); + + SiteConfig config = new SiteConfig(); + config.classId = SiteRegistry.SITE_CLASSES.indexOfValue(site.getClass()); + config.external = false; + + SiteModel model = createFromClass(config, new JsonSettings()); + setId(model, 0); + } + + public Site createFromClass(Class siteClass) { + Site site = instantiateSiteClass(siteClass); + + SiteConfig config = new SiteConfig(); + JsonSettings settings = new JsonSettings(); + + config.classId = SiteRegistry.SITE_CLASSES.indexOfValue(site.getClass()); + config.external = false; + + SiteModel model = createFromClass(config, settings); + + site.initialize(model.id, config, settings); + + sitesObservable.add(site); + + site.postInitialize(); + + sitesObservable.notifyObservers(); + + return site; + } + + private SiteModel createFromClass(SiteConfig config, JsonSettings userSettings) { + SiteModel siteModel = new SiteModel(); + siteModel.storeConfig(config); + siteModel.storeUserSettings(userSettings); + databaseManager.runTask(databaseManager.getDatabaseSiteManager().add(siteModel)); + + return siteModel; + } + + private SiteConfigSettingsHolder instantiateSiteFromModel(SiteModel siteModel) { + Pair configFields = siteModel.loadConfigFields(); + SiteConfig config = configFields.first; + JsonSettings settings = configFields.second; + + return new SiteConfigSettingsHolder( + instantiateSiteClass(config.classId), + config, + settings); + } + + private Site instantiateSiteClass(int classId) { + Class clazz = SiteRegistry.SITE_CLASSES.get(classId); + if (clazz == null) { + throw new IllegalArgumentException("Unknown class id"); + } + return instantiateSiteClass(clazz); + } + + private Site instantiateSiteClass(Class clazz) { + Site site; + try { + site = clazz.newInstance(); + } catch (InstantiationException e) { + throw new IllegalArgumentException(); + } catch (IllegalAccessException e) { + throw new IllegalArgumentException(); + } + return site; + } + + public class Sites extends Observable { + private List sites = Collections.unmodifiableList(new ArrayList<>()); + private SparseArray sitesById = new SparseArray<>(); + + public Site forId(int id) { + Site s = sitesById.get(id); + if (s == null) { + throw new IllegalArgumentException("No site with id (" + id + ")"); + } + return s; + } + + public List getAll() { + return new ArrayList<>(sites); + } + + public List getAllInOrder() { + Map ordering = getOrdering(); + + List ordered = new ArrayList<>(sites); + Collections.sort(ordered, + (lhs, rhs) -> ordering.get(lhs.id()) - ordering.get(rhs.id())); + + return ordered; + } + + private void addAll(List all) { + List copy = new ArrayList<>(sites); + copy.addAll(all); + resetSites(copy); + setChanged(); + } + + private void add(Site site) { + List copy = new ArrayList<>(sites); + copy.add(site); + resetSites(copy); + setChanged(); + } + + // We don't keep the order ourselves here, that's the task of listeners. Do notify the + // listeners. + private void wasReordered() { + setChanged(); + } + + private void resetSites(List newSites) { + sites = Collections.unmodifiableList(newSites); + SparseArray byId = new SparseArray<>(newSites.size()); + for (Site newSite : newSites) { + byId.put(newSite.id(), newSite); + } + sitesById = byId; + } + } + + private class SiteConfigSettingsHolder { + Site site; + SiteConfig config; + JsonSettings settings; + + public SiteConfigSettingsHolder(Site site, SiteConfig config, JsonSettings settings) { + this.site = site; + this.config = config; + this.settings = settings; + } + } +} diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/SiteBase.java b/Clover/app/src/main/java/org/floens/chan/core/site/SiteBase.java index 7c4be085..6042e8cb 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/site/SiteBase.java +++ b/Clover/app/src/main/java/org/floens/chan/core/site/SiteBase.java @@ -30,6 +30,7 @@ import org.floens.chan.core.settings.SettingProvider; import org.floens.chan.core.settings.json.JsonSettings; import org.floens.chan.core.settings.json.JsonSettingsProvider; import org.floens.chan.core.site.http.HttpCallManager; +import org.floens.chan.utils.Time; import java.util.ArrayList; import java.util.Collections; @@ -49,15 +50,24 @@ public abstract class SiteBase implements Site { private JsonSettings userSettings; protected SettingProvider settingsProvider; + private boolean initialized = false; + @Override public void initialize(int id, SiteConfig config, JsonSettings userSettings) { this.id = id; this.config = config; this.userSettings = userSettings; + + if (initialized) { + throw new IllegalStateException(); + } + initialized = true; } @Override public void postInitialize() { + long start = Time.startTiming(); + Feather injector = injector(); httpCallManager = injector.instance(HttpCallManager.class); requestQueue = injector.instance(RequestQueue.class); @@ -72,8 +82,10 @@ public abstract class SiteBase implements Site { initializeSettings(); if (boardsType().canList) { - actions().boards(boards -> boardManager.createAll(boards.boards)); + actions().boards(boards -> boardManager.updateAvailableBoardsForSite(this, boards.boards)); } + + Time.endTiming("initialized " + name(), start); } @Override @@ -102,7 +114,7 @@ public abstract class SiteBase implements Site { } Board board = Board.fromSiteNameCode(this, name, code); - boardManager.createAll(Collections.singletonList(board)); + boardManager.updateAvailableBoardsForSite(this, Collections.singletonList(board)); return board; } } diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/SiteRepository.java b/Clover/app/src/main/java/org/floens/chan/core/site/SiteRepository.java deleted file mode 100644 index 80f6aa3c..00000000 --- a/Clover/app/src/main/java/org/floens/chan/core/site/SiteRepository.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.floens.chan.core.site; - -import org.floens.chan.core.database.DatabaseManager; -import org.floens.chan.core.model.json.site.SiteConfig; -import org.floens.chan.core.model.orm.SiteModel; -import org.floens.chan.core.settings.json.JsonSettings; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import javax.inject.Inject; - -public class SiteRepository { - private DatabaseManager databaseManager; - - @Inject - public SiteRepository(DatabaseManager databaseManager) { - this.databaseManager = databaseManager; - } - - public List all() { - return databaseManager.runTask(databaseManager.getDatabaseSiteManager().getAll()); - } - - public SiteModel byId(int id) { - return databaseManager.runTask(databaseManager.getDatabaseSiteManager() - .byId(id)); - } - - public SiteModel create(SiteConfig config, JsonSettings userSettings) { - SiteModel siteModel = new SiteModel(); - siteModel.storeConfig(config); - siteModel.storeUserSettings(userSettings); - databaseManager.runTask(databaseManager.getDatabaseSiteManager().add(siteModel)); - return siteModel; - } - - public void setId(SiteModel siteModel, int id) { - databaseManager.runTask(databaseManager.getDatabaseSiteManager() - .updateId(siteModel, id)); - } - - public void updateSiteUserSettingsAsync(SiteModel siteModel, JsonSettings jsonSettings) { - siteModel.storeUserSettings(jsonSettings); - databaseManager.runTaskAsync(databaseManager.getDatabaseSiteManager() - .update(siteModel)); - } - - public Map getOrdering() { - return databaseManager.runTask(databaseManager.getDatabaseSiteManager().getOrdering()); - } - - public void updateSiteOrderingAsync(List sites, Runnable done) { - List ids = new ArrayList<>(sites.size()); - for (Site site : sites) { - ids.add(site.id()); - } - - databaseManager.runTaskAsync(databaseManager.getDatabaseSiteManager().updateOrdering(ids), - result -> done.run()); - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/SiteResolver.java b/Clover/app/src/main/java/org/floens/chan/core/site/SiteResolver.java index cac65f3d..57356a4a 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/site/SiteResolver.java +++ b/Clover/app/src/main/java/org/floens/chan/core/site/SiteResolver.java @@ -22,6 +22,7 @@ import android.support.annotation.Nullable; import org.floens.chan.core.database.LoadableProvider; import org.floens.chan.core.model.orm.Loadable; +import org.floens.chan.core.repository.SiteRepository; import java.util.List; @@ -30,18 +31,22 @@ import javax.inject.Inject; import okhttp3.HttpUrl; public class SiteResolver { - private LoadableProvider loadableProvider; + private final SiteRepository siteRepository; + private final LoadableProvider loadableProvider; @Inject - public SiteResolver(LoadableProvider loadableProvider) { + public SiteResolver(SiteRepository siteRepository, LoadableProvider loadableProvider) { + this.siteRepository = siteRepository; this.loadableProvider = loadableProvider; } public Site findSiteForUrl(String url) { HttpUrl httpUrl = sanitizeUrl(url); + SiteRepository.Sites sites = siteRepository.all(); + if (httpUrl == null) { - for (Site site : Sites.allSites()) { + for (Site site : sites.getAll()) { SiteUrlHandler siteUrlHandler = site.resolvable(); if (siteUrlHandler.matchesName(url)) { @@ -56,7 +61,7 @@ public class SiteResolver { httpUrl = httpUrl.newBuilder().scheme("https").build(); } - for (Site site : Sites.allSites()) { + for (Site site : sites.getAll()) { SiteUrlHandler siteUrlHandler = site.resolvable(); if (siteUrlHandler.respondsTo(httpUrl)) { return site; @@ -104,7 +109,7 @@ public class SiteResolver { return null; } - for (Site site : Sites.allSites()) { + for (Site site : siteRepository.all().getAll()) { if (site.resolvable().respondsTo(httpUrl)) { Loadable resolved = loadableProvider.get( site.resolvable().resolveLoadable(site, httpUrl)); diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/SiteService.java b/Clover/app/src/main/java/org/floens/chan/core/site/SiteService.java index 7724816b..d29c3bd1 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/site/SiteService.java +++ b/Clover/app/src/main/java/org/floens/chan/core/site/SiteService.java @@ -18,18 +18,11 @@ package org.floens.chan.core.site; -import android.util.Pair; - -import org.floens.chan.core.model.json.site.SiteConfig; import org.floens.chan.core.model.orm.SiteModel; +import org.floens.chan.core.repository.SiteRepository; import org.floens.chan.core.settings.json.JsonSettings; -import org.floens.chan.core.site.sites.chan4.Chan4; -import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import java.util.Map; -import java.util.Observable; import javax.inject.Inject; import javax.inject.Singleton; @@ -50,21 +43,14 @@ public class SiteService { private boolean initialized = false; - private SitesChangedObservable sitesChangedObservable = new SitesChangedObservable(); - @Inject - public SiteService(SiteRepository siteRepository, - SiteResolver resolver) { + public SiteService(SiteRepository siteRepository, SiteResolver resolver) { this.siteRepository = siteRepository; this.resolver = resolver; } - public SitesChangedObservable getSitesChangedObservable() { - return sitesChangedObservable; - } - public boolean areSitesSetup() { - return !Sites.allSites().isEmpty(); + return !siteRepository.all().getAll().isEmpty(); } public void addSite(String url, SiteAddCallback callback) { @@ -87,14 +73,9 @@ public class SiteService { return; } - Site site = instantiateSiteClass(siteClass); - createNewSite(site); - - loadSites(); + Site site = siteRepository.createFromClass(siteClass); callback.onSiteAdded(site); - - sitesChangedObservable.doNotify(); } public void updateUserSettings(Site site, JsonSettings jsonSettings) { @@ -103,22 +84,8 @@ public class SiteService { siteRepository.updateSiteUserSettingsAsync(siteModel, jsonSettings); } - public List getAllSitesInOrder() { - Map ordering = siteRepository.getOrdering(); - - List all = Sites.allSites(); - - Site[] ordered = new Site[all.size()]; - for (Site site : all) { - ordered[ordering.get(site.id())] = site; - } - - return Arrays.asList(ordered); - } - public void updateOrdering(List sitesInNewOrder) { - siteRepository.updateSiteOrderingAsync(sitesInNewOrder, - () -> sitesChangedObservable.doNotify()); + siteRepository.updateSiteOrderingAsync(sitesInNewOrder); } public void initialize() { @@ -129,79 +96,10 @@ public class SiteService { if (addSiteForLegacy) { addSiteForLegacy = false; - - Site site = new Chan4(); - - SiteConfig config = new SiteConfig(); - config.classId = SiteRegistry.SITE_CLASSES.indexOfValue(site.getClass()); - config.external = false; - - SiteModel model = siteRepository.create(config, new JsonSettings()); - siteRepository.setId(model, 0); - } - - loadSites(); - } - - private void loadSites() { - List sites = new ArrayList<>(); - - for (SiteModel siteModel : siteRepository.all()) { - sites.add(fromModel(siteModel)); + siteRepository.addLegacySite(); } - Sites.initialize(sites); - - for (Site site : sites) { - site.postInitialize(); - } - } - - /** - * Create a new site from the Site instance. This will insert the model for the site - * into the database and calls initialize on the site instance. - * - * @param site the site to add. - */ - private void createNewSite(Site site) { - SiteConfig config = new SiteConfig(); - JsonSettings settings = new JsonSettings(); - - config.classId = SiteRegistry.SITE_CLASSES.indexOfValue(site.getClass()); - config.external = false; - - siteRepository.create(config, settings); - } - - private Site fromModel(SiteModel siteModel) { - Pair configFields = siteModel.loadConfigFields(); - SiteConfig config = configFields.first; - JsonSettings settings = configFields.second; - - Site site = instantiateSiteClass(config.classId); - site.initialize(siteModel.id, config, settings); - return site; - } - - private Site instantiateSiteClass(int classId) { - Class clazz = SiteRegistry.SITE_CLASSES.get(classId); - if (clazz == null) { - throw new IllegalArgumentException("Unknown class id"); - } - return instantiateSiteClass(clazz); - } - - private Site instantiateSiteClass(Class clazz) { - Site site; - //noinspection TryWithIdenticalCatches - try { - site = clazz.newInstance(); - } catch (InstantiationException e) { - throw new IllegalArgumentException(); - } catch (IllegalAccessException e) { - throw new IllegalArgumentException(); - } - return site; + siteRepository.initialize(); } public interface SiteAddCallback { @@ -209,11 +107,4 @@ public class SiteService { void onSiteAddFailed(String message); } - - public class SitesChangedObservable extends Observable { - private void doNotify() { - setChanged(); - notifyObservers(); - } - } } diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/Sites.java b/Clover/app/src/main/java/org/floens/chan/core/site/Sites.java deleted file mode 100644 index e4545e33..00000000 --- a/Clover/app/src/main/java/org/floens/chan/core/site/Sites.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.floens.chan.core.site; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public class Sites { - private static List ALL_SITES = Collections.unmodifiableList(new ArrayList()); - - /** - * Return all sites known in the system. - *

This list is immutable. Changes to the known sites cause this function to return a new immutable list - * with the site changes. - * - * @return list of sites known in the system. - */ - public static List allSites() { - return ALL_SITES; - } - - public static Site forId(int id) { - // TODO: better datastructure - for (Site site : ALL_SITES) { - if (site.id() == id) { - return site; - } - } - - return null; - } - - static void initialize(List sites) { - Sites.ALL_SITES = Collections.unmodifiableList(new ArrayList<>(sites)); - } -} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java index 49689e84..02a3f8b1 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java @@ -44,9 +44,9 @@ import org.floens.chan.core.model.orm.Loadable; import org.floens.chan.core.model.orm.Pin; import org.floens.chan.core.settings.ChanSettings; import org.floens.chan.core.site.Site; -import org.floens.chan.core.site.SiteService; +import org.floens.chan.core.repository.SiteRepository; import org.floens.chan.core.site.SiteResolver; -import org.floens.chan.core.site.Sites; +import org.floens.chan.core.site.SiteService; import org.floens.chan.ui.controller.BrowseController; import org.floens.chan.ui.controller.DoubleNavigationController; import org.floens.chan.ui.controller.DrawerController; @@ -228,7 +228,7 @@ public class StartActivity extends AppCompatActivity implements NfcAdapter.Creat } private Loadable resolveLoadable(Loadable stateLoadable, boolean forThread) { - Site site = Sites.forId(stateLoadable.siteId); + Site site = SiteRepository.forId(stateLoadable.siteId); if (site != null) { Board board = site.board(stateLoadable.boardCode); if (board != null) { diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/SitesSetupController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/SitesSetupController.java index 06ccffc7..38da6ce4 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/SitesSetupController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/SitesSetupController.java @@ -22,6 +22,7 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.DialogInterface; import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; import android.support.design.widget.FloatingActionButton; import android.support.v4.graphics.drawable.DrawableCompat; import android.support.v7.app.AlertDialog; @@ -38,6 +39,7 @@ import android.widget.TextView; import org.floens.chan.R; import org.floens.chan.core.presenter.SitesSetupPresenter; +import org.floens.chan.core.presenter.SitesSetupPresenter.SiteBoardCount; import org.floens.chan.core.site.Site; import org.floens.chan.core.site.SiteIcon; import org.floens.chan.ui.helper.HintPopup; @@ -75,7 +77,7 @@ public class SitesSetupController extends StyledToolbarNavigationController impl private SitesAdapter sitesAdapter; private ItemTouchHelper itemTouchHelper; - private List sites = new ArrayList<>(); + private List sites = new ArrayList<>(); private ItemTouchHelper.SimpleCallback touchHelperCallback = new ItemTouchHelper.SimpleCallback( ItemTouchHelper.UP | ItemTouchHelper.DOWN, @@ -141,6 +143,13 @@ public class SitesSetupController extends StyledToolbarNavigationController impl presenter.show(); } + @Override + public void onDestroy() { + super.onDestroy(); + + presenter.destroy(); + } + public void showDoneCheckmark() { navigation.swipeable = false; navigation.menu = new ToolbarMenu(context); @@ -225,7 +234,7 @@ public class SitesSetupController extends StyledToolbarNavigationController impl } @Override - public void setAddedSites(List sites) { + public void setSites(List sites) { this.sites.clear(); this.sites.addAll(sites); sitesAdapter.notifyDataSetChanged(); @@ -254,22 +263,23 @@ public class SitesSetupController extends StyledToolbarNavigationController impl @Override public long getItemId(int position) { - return sites.get(position).id(); + return sites.get(position).site.id(); } + @NonNull @Override - public SiteCell onCreateViewHolder(ViewGroup parent, int viewType) { + public SiteCell onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { return new SiteCell(LayoutInflater.from(context).inflate(R.layout.cell_site, parent, false)); } @Override - public void onBindViewHolder(SiteCell holder, int position) { - Site site = sites.get(position); - holder.setSite(site); - holder.setSiteIcon(site); - holder.text.setText(site.name()); + public void onBindViewHolder(@NonNull SiteCell holder, int position) { + SiteBoardCount site = sites.get(position); + holder.setSite(site.site); + holder.setSiteIcon(site.site); + holder.text.setText(site.site.name()); - int boards = presenter.getSiteBoardCount(site); + int boards = site.boardCount; String boardsString = context.getResources().getQuantityString(R.plurals.board, boards, boards); String descriptionText = context.getString(R.string.setup_sites_site_description, boardsString); holder.description.setText(descriptionText); diff --git a/Clover/app/src/main/java/org/floens/chan/ui/layout/FilterLayout.java b/Clover/app/src/main/java/org/floens/chan/ui/layout/FilterLayout.java index 7af21f53..57844ab4 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/layout/FilterLayout.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/layout/FilterLayout.java @@ -31,7 +31,6 @@ import android.text.style.BackgroundColorSpan; import android.text.style.StyleSpan; import android.text.style.TypefaceSpan; import android.util.AttributeSet; -import android.util.Pair; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; @@ -46,7 +45,7 @@ import org.floens.chan.core.manager.FilterEngine; import org.floens.chan.core.manager.FilterType; import org.floens.chan.core.model.orm.Board; import org.floens.chan.core.model.orm.Filter; -import org.floens.chan.core.site.Site; +import org.floens.chan.core.repository.BoardRepository; import org.floens.chan.ui.controller.FiltersController; import org.floens.chan.ui.dialog.ColorPickerView; import org.floens.chan.ui.drawable.DropdownArrowDrawable; @@ -231,8 +230,8 @@ public class FilterLayout extends LinearLayout implements View.OnClickListener { List> items = new ArrayList<>(); List allSavedBoards = new ArrayList<>(); - for (Pair> sites : boardManager.getSavedBoardsObservable().get()) { - allSavedBoards.addAll(sites.second); + for (BoardRepository.SiteBoards item : boardManager.getSavedBoardsObservable().get()) { + allSavedBoards.addAll(item.boards); } for (Board board : allSavedBoards) {