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 b41125fc..7c6f6332 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 @@ -4,10 +4,7 @@ import com.j256.ormlite.stmt.QueryBuilder; import org.floens.chan.core.model.orm.Board; import org.floens.chan.core.site.Site; -import org.floens.chan.core.site.Sites; -import org.floens.chan.utils.Logger; -import java.sql.SQLException; import java.util.List; import java.util.concurrent.Callable; @@ -23,122 +20,91 @@ public class DatabaseBoardManager { } public Callable createOrUpdate(final Board board) { - return new Callable() { - @Override - public Board call() throws Exception { - helper.boardsDao.createOrUpdate(board); - - return board; + return () -> { + 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.update(board); + helper.boardsDao.update(existing); + board.update(existing); + } else { + helper.boardsDao.create(board); } + + return board; }; } public Callable update(final Board board) { - return new Callable() { - @Override - public Void call() throws Exception { - helper.boardsDao.update(board); + return () -> { + helper.boardsDao.update(board); - return null; - } + return null; }; } public Callable createAll(final List boards) { - return new Callable() { - @Override - public Void call() throws Exception { - // TODO: optimize - 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.update(board); - helper.boardsDao.update(existing); - board.update(existing); - } else { - helper.boardsDao.create(board); - } + return () -> { + // TODO: optimize + 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.update(board); + helper.boardsDao.update(existing); + board.update(existing); + } else { + helper.boardsDao.create(board); } - - return null; } - }; - } - public Callable> getSiteBoards(final Site site) { - return new Callable>() { - @Override - public List call() throws Exception { - List boards = helper.boardsDao.queryBuilder() - .where().eq("site", site.id()) - .query(); - for (int i = 0; i < boards.size(); i++) { - Board board = boards.get(i); - board.site = site; - } - return boards; - } + return null; }; } - public Callable> getSiteSavedBoards(final Site site) { - return new Callable>() { - @Override - public List call() throws Exception { - List boards = helper.boardsDao.queryBuilder() - .where().eq("site", site.id()) - .and().eq("saved", true) - .query(); - for (int i = 0; i < boards.size(); i++) { - Board board = boards.get(i); - board.site = site; - } - return boards; + public Callable getBoard(final Site site, final String code) { + return () -> { + Board board = helper.boardsDao.queryBuilder() + .where().eq("site", site.id()) + .and().eq("value", code) + .queryForFirst(); + + if (board != null) { + board.site = site; } + + return board; }; } - public Callable> getSavedBoards() { - return new Callable>() { - @Override - public List call() throws Exception { - List boards = null; - try { - boards = helper.boardsDao.queryBuilder() - .where().eq("saved", true) - .query(); - for (int i = 0; i < boards.size(); i++) { - Board board = boards.get(i); - board.site = Sites.forId(board.siteId); - } - } catch (SQLException e) { - Logger.e(TAG, "Error getting boards from db", e); - } - - return boards; + public Callable> getSiteBoards(final Site site) { + return () -> { + List boards = helper.boardsDao.queryBuilder() + .where().eq("site", site.id()) + .query(); + for (int i = 0; i < boards.size(); i++) { + Board board = boards.get(i); + board.site = site; } + return boards; }; } - public Callable> getAllBoards() { - return new Callable>() { - @Override - public List call() throws Exception { - List boards = null; - try { - boards = helper.boardsDao.queryForAll(); - for (int i = 0; i < boards.size(); i++) { - Board board = boards.get(i); - board.site = Sites.forId(board.siteId); - } - } catch (SQLException e) { - Logger.e(TAG, "Error getting boards from db", e); - } - return boards; + public Callable> getSiteSavedBoards(final Site site) { + return () -> { + List boards = helper.boardsDao.queryBuilder() + .where().eq("site", site.id()) + .and().eq("saved", true) + .query(); + for (int i = 0; i < boards.size(); i++) { + Board board = boards.get(i); + board.site = site; } + return boards; }; } } diff --git a/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseHelper.java b/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseHelper.java index e577d4ad..e8a4d272 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseHelper.java +++ b/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseHelper.java @@ -33,6 +33,7 @@ import org.floens.chan.core.model.orm.Pin; import org.floens.chan.core.model.orm.SavedReply; import org.floens.chan.core.model.orm.SiteModel; import org.floens.chan.core.model.orm.ThreadHide; +import org.floens.chan.core.site.SiteManager; import org.floens.chan.utils.Logger; import java.sql.SQLException; @@ -40,6 +41,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import static org.floens.chan.Chan.getGraph; + public class DatabaseHelper extends OrmLiteSqliteOpenHelper { private static final String TAG = "DatabaseHelper"; @@ -219,7 +222,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { Logger.e(TAG, "Error upgrading to version 22", e); } - int siteId = 0; + final int siteId = 0; try { boardsDao.executeRawNoArgs("ALTER TABLE loadable ADD COLUMN site INTEGER default " + siteId + ";"); @@ -229,6 +232,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { } catch (SQLException e) { Logger.e(TAG, "Error upgrading to version 22", e); } + + getGraph().get(SiteManager.class).addSiteForLegacy(); } isUpgrading = false; 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 54bad1f0..36683989 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 @@ -22,7 +22,9 @@ import android.support.annotation.AnyThread; import com.j256.ormlite.stmt.QueryBuilder; 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.utils.Time; import java.util.ArrayList; @@ -55,19 +57,19 @@ public class DatabaseSavedReplyManager { * Check if the given board-no combination is in the database.
* This is unlike other methods in that it immediately returns the result instead of * a Callable. This method is thread-safe and optimized. - * @param board board code of the post - * @param no post number + * + * @param board board of the post + * @param postNo post number * @return {@code true} if the post is in the saved reply database, {@code false} otherwise. */ @AnyThread - public boolean isSaved(String board, int no) { - // TODO(multi-site) + public boolean isSaved(Board board, int postNo) { synchronized (savedRepliesByNo) { - if (savedRepliesByNo.containsKey(no)) { - List items = savedRepliesByNo.get(no); + if (savedRepliesByNo.containsKey(postNo)) { + List items = savedRepliesByNo.get(postNo); for (int i = 0; i < items.size(); i++) { SavedReply item = items.get(i); - if (item.board.equals(board)) { + if (item.board.equals(board.code) && item.siteId == board.site.id()) { return true; } } @@ -79,74 +81,69 @@ public class DatabaseSavedReplyManager { } public Callable load() { - return new Callable() { - @Override - public Void call() throws Exception { - databaseManager.trimTable(helper.savedDao, "savedreply", SAVED_REPLY_TRIM_TRIGGER, SAVED_REPLY_TRIM_COUNT); - - final List all = helper.savedDao.queryForAll(); - - synchronized (savedRepliesByNo) { - savedRepliesByNo.clear(); - for (int i = 0; i < all.size(); i++) { - SavedReply savedReply = all.get(i); - if (savedRepliesByNo.containsKey(savedReply.no)) { - savedRepliesByNo.get(savedReply.no).add(savedReply); - } else { - List items = new ArrayList<>(); - items.add(savedReply); - savedRepliesByNo.put(savedReply.no, items); - } + return () -> { + databaseManager.trimTable(helper.savedDao, "savedreply", + SAVED_REPLY_TRIM_TRIGGER, SAVED_REPLY_TRIM_COUNT); + + final List all = helper.savedDao.queryForAll(); + + synchronized (savedRepliesByNo) { + savedRepliesByNo.clear(); + for (int i = 0; i < all.size(); i++) { + SavedReply savedReply = all.get(i); + + savedReply.site = Sites.forId(savedReply.siteId); + + List list = savedRepliesByNo.get(savedReply.no); + if (list == null) { + list = new ArrayList<>(1); + savedRepliesByNo.put(savedReply.no, list); } + + list.add(savedReply); } - return null; } + return null; }; } public Callable clearSavedReplies() { - return new Callable() { - @Override - public Void call() throws Exception { - long start = Time.startTiming(); - TableUtils.clearTable(helper.getConnectionSource(), SavedReply.class); - synchronized (savedRepliesByNo) { - savedRepliesByNo.clear(); - } - Time.endTiming("Clear saved replies", start); - - return null; + return () -> { + long start = Time.startTiming(); + TableUtils.clearTable(helper.getConnectionSource(), SavedReply.class); + synchronized (savedRepliesByNo) { + savedRepliesByNo.clear(); } + Time.endTiming("Clear saved replies", start); + + return null; }; } public Callable saveReply(final SavedReply savedReply) { - return new Callable() { - @Override - public SavedReply call() throws Exception { - helper.savedDao.create(savedReply); - synchronized (savedRepliesByNo) { - if (savedRepliesByNo.containsKey(savedReply.no)) { - savedRepliesByNo.get(savedReply.no).add(savedReply); - } else { - List items = new ArrayList<>(); - items.add(savedReply); - savedRepliesByNo.put(savedReply.no, items); - } + return () -> { + helper.savedDao.create(savedReply); + synchronized (savedRepliesByNo) { + List list = savedRepliesByNo.get(savedReply.no); + if (list == null) { + list = new ArrayList<>(1); + savedRepliesByNo.put(savedReply.no, list); } - return savedReply; + + list.add(savedReply); } + return savedReply; }; } - public Callable findSavedReply(final String board, final int no) { - return new Callable() { - @Override - public SavedReply call() throws Exception { - QueryBuilder builder = helper.savedDao.queryBuilder(); - List query = builder.where().eq("board", board).and().eq("no", no).query(); - return query.isEmpty() ? null : query.get(0); - } + public Callable findSavedReply(final Board board, final int no) { + return () -> { + QueryBuilder builder = helper.savedDao.queryBuilder(); + List query = builder.where() + .eq("site", board.site.id()) + .and().eq("board", board) + .and().eq("no", no).query(); + return query.isEmpty() ? null : query.get(0); }; } } diff --git a/Clover/app/src/main/java/org/floens/chan/core/di/AppModule.java b/Clover/app/src/main/java/org/floens/chan/core/di/AppModule.java index 2fd634bb..604077b9 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/di/AppModule.java +++ b/Clover/app/src/main/java/org/floens/chan/core/di/AppModule.java @@ -24,7 +24,6 @@ import org.floens.chan.core.saver.ImageSaveTask; import org.floens.chan.core.site.SiteManager; import org.floens.chan.core.site.common.ChanReaderRequest; import org.floens.chan.core.site.http.HttpCallManager; -import org.floens.chan.core.site.sites.chan4.Chan4; import org.floens.chan.core.update.UpdateManager; import org.floens.chan.ui.activity.BoardActivity; import org.floens.chan.ui.adapter.DrawerAdapter; @@ -99,8 +98,6 @@ import dagger.Provides; SitesSetupController.class, BoardSetupController.class, ReplyLayout.class, - - Chan4.class, }, complete = false, includes = NetModule.class 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 7cf54244..81e85ae1 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 @@ -21,11 +21,8 @@ import android.util.Pair; import org.floens.chan.core.database.DatabaseManager; import org.floens.chan.core.model.orm.Board; -import org.floens.chan.core.site.Boards; import org.floens.chan.core.site.Site; -import org.floens.chan.core.site.SiteManager; import org.floens.chan.core.site.Sites; -import org.floens.chan.utils.Logger; import java.util.ArrayList; import java.util.Collections; @@ -36,8 +33,6 @@ import java.util.Observable; import javax.inject.Inject; import javax.inject.Singleton; -import de.greenrobot.event.EventBus; - /** *

Keeps track of {@link Board}s in the system. *

There are a few types of sites, those who provide a list of all boards known, @@ -45,7 +40,8 @@ import de.greenrobot.event.EventBus; * and those who don't provide a board list at all. *

We try to save as much info about boards as possible, this means that we try to save all * boards we encounter. - * For sites with a small list of boards which does provide a board list api we save all those boards. + * For sites with a small list of boards which does provide a board list api we save all those + * boards. *

All boards have a {@link Board#saved} flag indicating if it should be visible in the user's * favorite board list, along with a {@link Board#order} in which they appear. */ @@ -53,57 +49,36 @@ import de.greenrobot.event.EventBus; public class BoardManager { private static final String TAG = "BoardManager"; - private static final Comparator ORDER_SORT = new Comparator() { - @Override - public int compare(Board lhs, Board rhs) { - return lhs.order - rhs.order; - } - }; - - private static final Comparator NAME_SORT = new Comparator() { - @Override - public int compare(Board lhs, Board rhs) { - return lhs.name.compareTo(rhs.name); - } - }; + private static final Comparator ORDER_SORT = (lhs, rhs) -> lhs.order - rhs.order; private final DatabaseManager databaseManager; - private final SiteManager siteManager; - private final List savedBoards = new ArrayList<>(); - - private final List>> sitesWithBoards = new ArrayList<>(); + private final List>> sitesWithSavedBoards = new ArrayList<>(); private final SavedBoards savedBoardsObservable = new SavedBoards(); @Inject - public BoardManager(DatabaseManager databaseManager, SiteManager siteManager) { + public BoardManager(DatabaseManager databaseManager) { this.databaseManager = databaseManager; - this.siteManager = siteManager; updateSavedBoards(); - - fetchLimitedSitesTheirBoards(); } - public Board getForCode(Site site, String code) { - if (site.boardsType() == Site.BoardsType.DYNAMIC) { - for (Board board : getSavedBoards()) { - if (board.site == site && board.code.equals(code)) { - return board; - } - } - return null; - } else { - return Board.fromSiteNameCode(site, code, code); - } + public void createAll(List boards) { + databaseManager.runTaskSync( + databaseManager.getDatabaseBoardManager().createAll(boards)); } - public List getSavedBoards() { - return savedBoards; - } - - public SavedBoards getSavedBoardsObservable() { - return savedBoardsObservable; + /** + * Get the board with the same {@code code} for the given site. The board does not need + * to be saved. + * + * @param site the site + * @param code the board code + * @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.runTaskSync( + databaseManager.getDatabaseBoardManager().getBoard(site, code)); } public List getSiteBoards(Site site) { @@ -118,6 +93,10 @@ public class BoardManager { return boards; } + public SavedBoards getSavedBoardsObservable() { + return savedBoardsObservable; + } + public void saveBoard(Board board) { setSaved(board, true); } @@ -128,12 +107,9 @@ public class BoardManager { public void updateBoardOrder(Board board, int order) { board.order = order; - databaseManager.runTask(databaseManager.getDatabaseBoardManager().update(board), new DatabaseManager.TaskResult() { - @Override - public void onComplete(Void result) { - updateSavedBoards(); - } - }); + // not sync, does not update observable. + databaseManager.runTask(databaseManager.getDatabaseBoardManager().update(board), + result -> updateSavedBoards()); } private void setSaved(Board board, boolean saved) { @@ -142,137 +118,19 @@ public class BoardManager { updateSavedBoards(); } - private void fetchLimitedSitesTheirBoards() { - List sites = Sites.allSites(); - for (final Site site : sites) { - if (site.boardsType() == Site.BoardsType.DYNAMIC) { - site.boards(new Site.BoardsListener() { - @Override - public void onBoardsReceived(Boards boards) { - handleBoardsFetch(site, boards); - } - }); - } - } - } - - private void handleBoardsFetch(Site site, Boards boards) { - Logger.i(TAG, "Got boards for " + site.name()); - - databaseManager.runTask(databaseManager.getDatabaseBoardManager().createAll(boards.boards)); - } - private void updateSavedBoards() { - savedBoards.clear(); - savedBoards.addAll(databaseManager.runTaskSync(databaseManager.getDatabaseBoardManager().getSavedBoards())); - - sitesWithBoards.clear(); + sitesWithSavedBoards.clear(); for (Site site : Sites.allSites()) { List siteBoards = getSiteSavedBoards(site); - sitesWithBoards.add(new Pair<>(site, siteBoards)); + sitesWithSavedBoards.add(new Pair<>(site, siteBoards)); } - // TODO: remove, use the observable - EventBus.getDefault().post(new BoardsChangedMessage()); - savedBoardsObservable.notifyObservers(); } public class SavedBoards extends Observable { public List>> get() { - return sitesWithBoards; - } - } - - /*private void appendBoards(Boards response) { - List boardsToAddWs = new ArrayList<>(); - List boardsToAddNws = new ArrayList<>(); - - for (int i = 0; i < response.boards.size(); i++) { - Board serverBoard = response.boards.get(i); - - Board existing = getBoardByCode(serverBoard.code); - if (existing != null) { - existing.update(serverBoard); - } else { - serverBoard.saved = true; - if (serverBoard.workSafe) { - boardsToAddWs.add(serverBoard); - } else { - boardsToAddNws.add(serverBoard); - } - } - } - - Collections.sort(boardsToAddWs, NAME_SORT); - Collections.sort(boardsToAddNws, NAME_SORT); - - for (int i = 0; i < boardsToAddWs.size(); i++) { - Board board = boardsToAddWs.get(i); - board.order = boards.size(); - boards.add(board); - } - - for (int i = 0; i < boardsToAddNws.size(); i++) { - Board board = boardsToAddNws.get(i); - board.order = boards.size(); - boards.add(board); - } - - saveDatabase(); - update(true); - } - - // Thread-safe - private Board getBoardByCode(String code) { - synchronized (boardsByCode) { - return boardsByCode.get(code); - } - } - - public List getAllBoards() { - return boards; - } - - public List getSavedBoards() { - return savedBoards; - } - - public void flushOrderAndSaved() { - saveDatabase(); - update(true); - }*/ - - /*private void update(boolean notify) { - savedBoards.clear(); - savedBoards.addAll(filterSaved(boards)); - synchronized (boardsByCode) { - boardsByCode.clear(); - for (Board board : boards) { - boardsByCode.put(board.code, board); - } - } - if (notify) { - EventBus.getDefault().post(new BoardsChangedMessage()); - } - }*/ - - /*private void saveDatabase() { - databaseManager.runTask(databaseManager.getDatabaseBoardManager().setBoards(boards)); - }*/ - - /*private List filterSaved(List all) { - List saved = new ArrayList<>(all.size()); - for (int i = 0; i < all.size(); i++) { - Board board = all.get(i); - if (board.saved) { - saved.add(board); - } + return sitesWithSavedBoards; } - Collections.sort(saved, ORDER_SORT); - return saved; - }*/ - - public static class BoardsChangedMessage { } } diff --git a/Clover/app/src/main/java/org/floens/chan/core/model/orm/SavedReply.java b/Clover/app/src/main/java/org/floens/chan/core/model/orm/SavedReply.java index bd92bd89..868e0f71 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/model/orm/SavedReply.java +++ b/Clover/app/src/main/java/org/floens/chan/core/model/orm/SavedReply.java @@ -20,22 +20,41 @@ package org.floens.chan.core.model.orm; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; +import org.floens.chan.core.site.Site; + @DatabaseTable(tableName = "savedreply") public class SavedReply { public SavedReply() { } + @Deprecated public SavedReply(String board, int no, String password) { this.board = board; this.no = no; this.password = password; } + public static SavedReply fromSiteBoardNoPassword(Site site, Board board, int no, + String password) { + SavedReply savedReply = new SavedReply(); + savedReply.siteId = site.id(); + savedReply.site = site; + savedReply.board = board.code; + savedReply.no = no; + savedReply.password = password; + return savedReply; + } + @DatabaseField(generatedId = true) private int id; @DatabaseField(columnName = "site") - public int site; + public int siteId; + + /** + * The site this board belongs to, loaded with {@link #siteId} in the database manager. + */ + public transient Site site; @DatabaseField(index = true, canBeNull = false) public String board; diff --git a/Clover/app/src/main/java/org/floens/chan/core/model/orm/SiteModel.java b/Clover/app/src/main/java/org/floens/chan/core/model/orm/SiteModel.java index 230cc546..b45b44ef 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/model/orm/SiteModel.java +++ b/Clover/app/src/main/java/org/floens/chan/core/model/orm/SiteModel.java @@ -17,11 +17,19 @@ */ package org.floens.chan.core.model.orm; +import android.util.Pair; + +import com.google.gson.Gson; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; +import org.floens.chan.core.model.json.site.SiteConfig; +import org.floens.chan.core.model.json.site.SiteUserSettings; + @DatabaseTable(tableName = "site") public class SiteModel { + private static final Gson gson = new Gson(); + @DatabaseField(generatedId = true, allowGeneratedIdInsert = true) public int id; @@ -33,4 +41,16 @@ public class SiteModel { public SiteModel() { } + + public void storeConfigFields(SiteConfig config, SiteUserSettings userSettings) { + this.configuration = gson.toJson(config); + this.userSettings = gson.toJson(userSettings); + } + + public Pair loadConfigFields() { + return Pair.create( + gson.fromJson(this.configuration, SiteConfig.class), + gson.fromJson(this.userSettings, SiteUserSettings.class) + ); + } } diff --git a/Clover/app/src/main/java/org/floens/chan/core/presenter/BoardSetupPresenter.java b/Clover/app/src/main/java/org/floens/chan/core/presenter/BoardSetupPresenter.java index 1f9b86c0..b772806d 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/presenter/BoardSetupPresenter.java +++ b/Clover/app/src/main/java/org/floens/chan/core/presenter/BoardSetupPresenter.java @@ -28,7 +28,6 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.concurrent.Callable; import java.util.concurrent.Executor; import java.util.concurrent.Executors; @@ -105,9 +104,9 @@ public class BoardSetupPresenter { } } else { for (String suggestion : selectedSuggestions) { - // TODO(multisite) - Board board = new Board(site, suggestion, suggestion, true, true); + Board board = site.createBoard(suggestion, suggestion); boardManager.saveBoard(board); + boardManager.updateBoardOrder(board, savedBoards.size()); count++; } } @@ -164,53 +163,46 @@ public class BoardSetupPresenter { final String query = userQuery == null ? null : userQuery.replace("/", "").replace("\\", ""); - suggestionCall = BackgroundUtils.runWithExecutor(executor, new Callable>() { - @Override - public List call() throws Exception { - List suggestions = new ArrayList<>(); - if (site.boardsType() == Site.BoardsType.DYNAMIC) { - List siteBoards = boardManager.getSiteBoards(site); - List allUnsavedBoards = new ArrayList<>(); - for (Board siteBoard : siteBoards) { - if (!siteBoard.saved) { - allUnsavedBoards.add(siteBoard); - } + suggestionCall = BackgroundUtils.runWithExecutor(executor, () -> { + List suggestions = new ArrayList<>(); + if (site.boardsType() == Site.BoardsType.DYNAMIC) { + List siteBoards = boardManager.getSiteBoards(site); + List allUnsavedBoards = new ArrayList<>(); + for (Board siteBoard : siteBoards) { + if (!siteBoard.saved) { + allUnsavedBoards.add(siteBoard); } + } - List toSuggest; - if (query == null || query.equals("")) { - toSuggest = new ArrayList<>(allUnsavedBoards.size()); - for (Board b : allUnsavedBoards) { - if (b.workSafe) toSuggest.add(b); - } - for (Board b : allUnsavedBoards) { - if (!b.workSafe) toSuggest.add(b); - } - toSuggest = allUnsavedBoards; - } else { - toSuggest = BoardHelper.search(allUnsavedBoards, query); + List toSuggest; + if (query == null || query.equals("")) { + toSuggest = new ArrayList<>(allUnsavedBoards.size()); + for (Board b : allUnsavedBoards) { + if (b.workSafe) toSuggest.add(b); } - - for (Board board : toSuggest) { - BoardSuggestion suggestion = new BoardSuggestion(board); - suggestions.add(suggestion); + for (Board b : allUnsavedBoards) { + if (!b.workSafe) toSuggest.add(b); } } else { - if (query != null && !query.equals("")) { - suggestions.add(new BoardSuggestion(query)); - } + toSuggest = BoardHelper.search(allUnsavedBoards, query); } - return suggestions; + for (Board board : toSuggest) { + BoardSuggestion suggestion = new BoardSuggestion(board); + suggestions.add(suggestion); + } + } else { + if (query != null && !query.equals("")) { + suggestions.add(new BoardSuggestion(query)); + } } - }, new BackgroundUtils.BackgroundResult>() { - @Override - public void onResult(List result) { - updateSuggestions(result); - if (addCallback != null) { - addCallback.updateSuggestions(); - } + return suggestions; + }, result -> { + updateSuggestions(result); + + if (addCallback != null) { + addCallback.updateSuggestions(); } }); } 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 8a0b78c9..1f018bd7 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 @@ -74,7 +74,10 @@ public class BrowsePresenter implements Observer { } public void loadWithDefaultBoard() { - loadBoard(firstBoard()); + Board first = firstBoard(); + if (first != null) { + loadBoard(first); + } } public void onBoardsFloatingMenuSiteClicked(Site site) { @@ -96,13 +99,7 @@ public class BrowsePresenter implements Observer { } private boolean hasBoards() { - for (Pair> siteListPair : savedBoardsObservable.get()) { - if (!siteListPair.second.isEmpty()) { - return true; - } - } - - return false; + return firstBoard() != null; } private Board firstBoard() { diff --git a/Clover/app/src/main/java/org/floens/chan/core/presenter/ReplyPresenter.java b/Clover/app/src/main/java/org/floens/chan/core/presenter/ReplyPresenter.java index c1add0d2..26c073ff 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/presenter/ReplyPresenter.java +++ b/Clover/app/src/main/java/org/floens/chan/core/presenter/ReplyPresenter.java @@ -224,7 +224,8 @@ public class ReplyPresenter implements CaptchaCallback, ImagePickDelegate.ImageP } } - SavedReply savedReply = new SavedReply(loadable.boardCode, replyResponse.postNo, replyResponse.password); + SavedReply savedReply = SavedReply.fromSiteBoardNoPassword( + loadable.site, loadable.board, replyResponse.postNo, replyResponse.password); databaseManager.runTask(databaseManager.getDatabaseSavedReplyManager().saveReply(savedReply)); switchPage(Page.INPUT, false); diff --git a/Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java b/Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java index f09f236f..2d18a863 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java +++ b/Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java @@ -450,7 +450,7 @@ public class ThreadPresenter implements ChanLoader.ChanLoaderCallback, PostAdapt } if (loadable.site.feature(Site.Feature.POST_DELETE) && - databaseManager.getDatabaseSavedReplyManager().isSaved(post.boardId, post.no)) { + databaseManager.getDatabaseSavedReplyManager().isSaved(post.board, post.no)) { menu.add(new FloatingMenuItem(POST_OPTION_DELETE, R.string.delete)); } @@ -496,7 +496,8 @@ public class ThreadPresenter implements ChanLoader.ChanLoaderCallback, PostAdapt requestDeletePost(post); break; case POST_OPTION_SAVE: - SavedReply savedReply = new SavedReply(post.boardId, post.no, ""); + SavedReply savedReply = SavedReply.fromSiteBoardNoPassword( + post.board.site, post.board, post.no, ""); databaseManager.runTask(databaseManager.getDatabaseSavedReplyManager().saveReply(savedReply)); break; case POST_OPTION_PIN: @@ -606,7 +607,7 @@ public class ThreadPresenter implements ChanLoader.ChanLoaderCallback, PostAdapt threadPresenterCallback.showDeleting(); SavedReply reply = databaseManager.runTaskSync( - databaseManager.getDatabaseSavedReplyManager().findSavedReply(post.boardId, post.no) + databaseManager.getDatabaseSavedReplyManager().findSavedReply(post.board, post.no) ); if (reply != null) { Site site = loadable.getSite(); @@ -634,7 +635,7 @@ public class ThreadPresenter implements ChanLoader.ChanLoaderCallback, PostAdapt private void requestDeletePost(Post post) { SavedReply reply = databaseManager.runTaskSync( - databaseManager.getDatabaseSavedReplyManager().findSavedReply(post.boardId, post.no) + databaseManager.getDatabaseSavedReplyManager().findSavedReply(post.board, post.no) ); if (reply != null) { threadPresenterCallback.confirmPostDelete(post); diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/Site.java b/Clover/app/src/main/java/org/floens/chan/core/site/Site.java index cbfd4e3a..dd2370c2 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/site/Site.java +++ b/Clover/app/src/main/java/org/floens/chan/core/site/Site.java @@ -102,8 +102,18 @@ public interface Site { INFINITE } + /** + * Initialize the site with the given id, config, and userSettings. + *

Note: do not use any managers at this point, because they rely on the sites being initialized. + * Instead, use {@link #postInitialize()} + * @param id the site id + * @param config the site config + * @param userSettings the site user settings + */ void initialize(int id, SiteConfig config, SiteUserSettings userSettings); + void postInitialize(); + /** * Global positive (>0) integer that uniquely identifies this site.
* Use the id received from {@link #initialize(int, SiteConfig, SiteUserSettings)}. @@ -136,13 +146,26 @@ public interface Site { void onBoardsReceived(Boards boards); } + /** + * Return the board for this site with the given {@code code}. + *

This does not need to create the board if it doesn't exist. This is important for + * sites that have a board type different to DYNAMIC. Returning from the database is + * enough.

+ * + * @param code the board code + * @return a board with the board code, or {@code null}. + */ Board board(String code); - interface BoardListener { - void onBoardReceived(Board board); - - void onBoardNonexistent(); - } + /** + * Create a new board with the specified {@code code} and {@code name}. + *

This is only applicable to sites with a board type other than DYNAMIC.

+ * + * @param name the name of the board. + * @param code the code to create the board with. + * @return the created board. + */ + Board createBoard(String name, String code); ChanReader chanReader(); 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 a112d382..6ba78f87 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 @@ -18,14 +18,29 @@ package org.floens.chan.core.site; +import com.android.volley.RequestQueue; + +import org.floens.chan.core.manager.BoardManager; 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.Board; +import org.floens.chan.core.site.http.HttpCallManager; + +import java.util.Collections; + +import dagger.ObjectGraph; + +import static org.floens.chan.Chan.getGraph; public abstract class SiteBase implements Site { protected int id; protected SiteConfig config; protected SiteUserSettings userSettings; + protected HttpCallManager httpCallManager; + protected RequestQueue requestQueue; + protected BoardManager boardManager; + @Override public void initialize(int id, SiteConfig config, SiteUserSettings userSettings) { this.id = id; @@ -33,8 +48,38 @@ public abstract class SiteBase implements Site { this.userSettings = userSettings; } + @Override + public void postInitialize() { + ObjectGraph graph = getGraph(); + + httpCallManager = graph.get(HttpCallManager.class); + requestQueue = graph.get(RequestQueue.class); + boardManager = graph.get(BoardManager.class); + + if (boardsType() == BoardsType.DYNAMIC) { + boards(boards -> boardManager.createAll(boards.boards)); + } + } + @Override public int id() { return id; } + + @Override + public Board board(String code) { + return boardManager.getBoard(this, code); + } + + @Override + public Board createBoard(String name, String code) { + Board existing = board(code); + if (existing != null) { + return existing; + } + + Board board = Board.fromSiteNameCode(this, name, code); + boardManager.createAll(Collections.singletonList(board)); + return board; + } } diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/SiteManager.java b/Clover/app/src/main/java/org/floens/chan/core/site/SiteManager.java index fcf57a9a..13b6c4fd 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/site/SiteManager.java +++ b/Clover/app/src/main/java/org/floens/chan/core/site/SiteManager.java @@ -20,9 +20,6 @@ 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; @@ -36,16 +33,17 @@ import javax.inject.Singleton; @Singleton public class SiteManager { - @Inject - DatabaseManager databaseManager; - + private SiteRepository siteRepository; private SiteResolver resolver; - private Gson gson = new Gson(); + private boolean initialized = false; + private boolean addSiteForLegacy = false; @Inject - public SiteManager() { - resolver = new SiteResolver(); + public SiteManager(SiteRepository siteRepository, + SiteResolver resolver) { + this.siteRepository = siteRepository; + this.resolver = resolver; } public void addSite(String url, SiteAddCallback callback) { @@ -62,125 +60,90 @@ public class SiteManager { return; } - addSiteFromClass(siteClass, callback); - } - - public void addSiteFromClass(Class siteClass, SiteAddCallback callback) { Site site = instantiateSiteClass(siteClass); createNewSite(site); - List newAllSites = new ArrayList<>(Sites.allSites()); - newAllSites.add(site); - setAvailableSites(newAllSites); + loadSites(); callback.onSiteAdded(site); } + /** + * Called from the DatabaseHelper when upgrading to the tables with a site id. + */ + public void addSiteForLegacy() { + addSiteForLegacy = true; + } + public void initialize() { - List sites = loadSitesFromDatabase(); + if (initialized) { + throw new IllegalStateException("Already initialized"); + } - if (sites.isEmpty()) { + if (addSiteForLegacy) { 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); + SiteModel model = siteRepository.create(config, new SiteUserSettings()); + siteRepository.setId(model, 0); } - setAvailableSites(sites); + loadSites(); } - private void setAvailableSites(List newAllSites) { - Sites.initialize(newAllSites); - } - - private List loadSitesFromDatabase() { + private void loadSites() { List sites = new ArrayList<>(); - List siteModels = databaseManager.runTaskSync(databaseManager.getDatabaseSiteManager().getAll()); + for (SiteModel siteModel : siteRepository.all()) { + sites.add(fromModel(siteModel)); + } - for (SiteModel siteModel : siteModels) { - Pair configPair = loadConfigFields(siteModel); - SiteConfig config = configPair.first; - SiteUserSettings userSettings = configPair.second; + Sites.initialize(sites); - Site site = loadSiteFromModel(siteModel, config, userSettings); - sites.add(site); + for (Site site : sites) { + site.postInitialize(); } - - return sites; } /** * 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(); + SiteUserSettings settings = new SiteUserSettings(); + 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); - } - - 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; - } + siteRepository.create(config, settings); - private void storeConfigFields(SiteModel siteModel, SiteConfig config, SiteUserSettings userSettings) { - siteModel.configuration = gson.toJson(config); - siteModel.userSettings = gson.toJson(userSettings); + loadSites(); } - private Pair 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 fromModel(SiteModel siteModel) { + Pair configFields = siteModel.loadConfigFields(); + SiteConfig config = configFields.first; + SiteUserSettings settings = configFields.second; - 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); + Site site = instantiateSiteClass(config.classId); + site.initialize(siteModel.id, config, settings); return site; } - private Site instantiateSiteFromConfig(SiteConfig siteConfig) { - int siteClassId = siteConfig.classId; - Class clazz = Sites.SITE_CLASSES.get(siteClassId); + private Site instantiateSiteClass(int classId) { + Class clazz = Sites.SITE_CLASSES.get(classId); if (clazz == null) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException("Unknown class id"); } return instantiateSiteClass(clazz); } - /** - * Create the instance of the site class. Catches any reflection exceptions as runtime - * exceptions. - * @param clazz the class to instantiate - * @return the instantiated clas - * @throws IllegalArgumentException on reflection exceptions, should never happen. - */ private Site instantiateSiteClass(Class clazz) { Site site; //noinspection TryWithIdenticalCatches @@ -194,9 +157,6 @@ public class SiteManager { return site; } - public static class SiteAlreadyAdded extends IllegalArgumentException { - } - public interface SiteAddCallback { void onSiteAdded(Site site); 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 new file mode 100644 index 00000000..8dde2aa7 --- /dev/null +++ b/Clover/app/src/main/java/org/floens/chan/core/site/SiteRepository.java @@ -0,0 +1,35 @@ +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.json.site.SiteUserSettings; +import org.floens.chan.core.model.orm.SiteModel; + +import java.util.List; + +import javax.inject.Inject; + +public class SiteRepository { + private DatabaseManager databaseManager; + + @Inject + public SiteRepository(DatabaseManager databaseManager) { + this.databaseManager = databaseManager; + } + + public List all() { + return databaseManager.runTaskSync(databaseManager.getDatabaseSiteManager().getAll()); + } + + public SiteModel create(SiteConfig config, SiteUserSettings userSettings) { + SiteModel siteModel = new SiteModel(); + siteModel.storeConfigFields(config, userSettings); + databaseManager.runTaskSync(databaseManager.getDatabaseSiteManager().add(siteModel)); + return siteModel; + } + + public void setId(SiteModel siteModel, int id) { + databaseManager.runTaskSync(databaseManager.getDatabaseSiteManager() + .updateId(siteModel, id)); + } +} 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 c7587434..ffbd6b9e 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 @@ -20,9 +20,15 @@ package org.floens.chan.core.site; import java.util.List; +import javax.inject.Inject; + import okhttp3.HttpUrl; class SiteResolver { + @Inject + public SiteResolver() { + } + SiteResolverResult resolve(String url) { List resolvables = Sites.RESOLVABLES; diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/common/ChanParser.java b/Clover/app/src/main/java/org/floens/chan/core/site/common/ChanParser.java index 8b4f8f3f..7fb8e979 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/site/common/ChanParser.java +++ b/Clover/app/src/main/java/org/floens/chan/core/site/common/ChanParser.java @@ -21,5 +21,9 @@ import org.floens.chan.core.model.Post; import org.floens.chan.ui.theme.Theme; public interface ChanParser { - Post parse(Theme theme, Post.Builder builder); + Post parse(Theme theme, Post.Builder builder, Callback callback); + + interface Callback { + boolean isSaved(int postNo); + } } diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/common/FutabaChanParser.java b/Clover/app/src/main/java/org/floens/chan/core/site/common/FutabaChanParser.java index 28485f1a..2ae1de28 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/site/common/FutabaChanParser.java +++ b/Clover/app/src/main/java/org/floens/chan/core/site/common/FutabaChanParser.java @@ -46,6 +46,7 @@ public class FutabaChanParser implements ChanParser { private static final String TAG = "FutabaChanParser"; private static final String SAVED_REPLY_SUFFIX = " (You)"; private static final String OP_REPLY_SUFFIX = " (OP)"; + public static final String EXTERN_THREAD_LINK_SUFFIX = " \u2192"; // arrow to the right private FutabaChanParserHandler handler; @@ -54,7 +55,7 @@ public class FutabaChanParser implements ChanParser { } @Override - public Post parse(Theme theme, Post.Builder builder) { + public Post parse(Theme theme, Post.Builder builder, Callback callback) { if (theme == null) { theme = ThemeHelper.getInstance().getTheme(); } @@ -74,7 +75,7 @@ public class FutabaChanParser implements ChanParser { parseSpans(theme, builder); if (builder.comment != null) { - builder.comment = parseComment(theme, builder, builder.comment); + builder.comment = parseComment(theme, builder, builder.comment, callback); } else { builder.comment = ""; } @@ -177,7 +178,7 @@ public class FutabaChanParser implements ChanParser { builder.spans(subjectSpan, nameTripcodeIdCapcodeSpan); } - private CharSequence parseComment(Theme theme, Post.Builder post, CharSequence commentRaw) { + private CharSequence parseComment(Theme theme, Post.Builder post, CharSequence commentRaw, Callback callback) { CharSequence total = new SpannableString(""); try { @@ -189,7 +190,7 @@ public class FutabaChanParser implements ChanParser { List texts = new ArrayList<>(nodes.size()); for (Node node : nodes) { - CharSequence nodeParsed = parseNode(theme, post, node); + CharSequence nodeParsed = parseNode(theme, post, callback, node); if (nodeParsed != null) { texts.add(nodeParsed); } @@ -203,7 +204,7 @@ public class FutabaChanParser implements ChanParser { return total; } - private CharSequence parseNode(Theme theme, Post.Builder post, Node node) { + private CharSequence parseNode(Theme theme, Post.Builder post, Callback callback, Node node) { if (node instanceof TextNode) { String text = ((TextNode) node).text(); SpannableString spannable = new SpannableString(text); @@ -219,7 +220,7 @@ public class FutabaChanParser implements ChanParser { List texts = new ArrayList<>(innerNodes.size() + 1); for (Node innerNode : innerNodes) { - CharSequence nodeParsed = parseNode(theme, post, innerNode); + CharSequence nodeParsed = parseNode(theme, post, callback, innerNode); if (nodeParsed != null) { texts.add(nodeParsed); } @@ -246,7 +247,7 @@ public class FutabaChanParser implements ChanParser { return handler.handleStrong(this, theme, post, (Element) node); } case "a": { - CharSequence anchor = parseAnchor(theme, post, (Element) node); + CharSequence anchor = parseAnchor(theme, post, callback, (Element) node); if (anchor != null) { return anchor; } else { @@ -271,38 +272,41 @@ public class FutabaChanParser implements ChanParser { } } - private CharSequence parseAnchor(Theme theme, Post.Builder post, Element anchor) { - FutabaChanParserHandler.Link handlerLink = handler.handleAnchor(this, theme, post, anchor); + private CharSequence parseAnchor(Theme theme, Post.Builder post, Callback callback, + Element anchor) { + FutabaChanParserHandler.Link handlerLink = + handler.handleAnchor(this, theme, post, anchor); if (handlerLink != null) { - SpannableString link = new SpannableString(handlerLink.key); - PostLinkable pl = new PostLinkable(theme, handlerLink.key, handlerLink.value, handlerLink.type); - link.setSpan(pl, 0, link.length(), 0); - post.addLinkable(pl); - if (handlerLink.type == PostLinkable.Type.THREAD) { - handlerLink.key += " \u2192"; // arrow to the right + handlerLink.key += EXTERN_THREAD_LINK_SUFFIX; } if (handlerLink.type == PostLinkable.Type.QUOTE) { int postNo = (int) handlerLink.value; post.addReplyTo(postNo); - // Append OP when its a reply to OP + // Append (OP) when its a reply to OP if (postNo == post.opId) { handlerLink.key += OP_REPLY_SUFFIX; } - // Append You when it's a reply to an saved reply - // TODO(multisite) - /*if (databaseManager.getDatabaseSavedReplyManager().isSaved(post.board.code, id)) { - key += SAVED_REPLY_SUFFIX; - }*/ + // Append (You) when it's a reply to an saved reply + if (callback.isSaved(postNo)) { + handlerLink.key += SAVED_REPLY_SUFFIX; + } } + SpannableString link = new SpannableString(handlerLink.key); + PostLinkable pl = new PostLinkable(theme, handlerLink.key, handlerLink.value, handlerLink.type); + link.setSpan(pl, 0, link.length(), 0); + post.addLinkable(pl); + return link; } else { return null; } } + + } diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/common/PostParseCallable.java b/Clover/app/src/main/java/org/floens/chan/core/site/common/PostParseCallable.java index 22e07769..ed44d7a8 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/site/common/PostParseCallable.java +++ b/Clover/app/src/main/java/org/floens/chan/core/site/common/PostParseCallable.java @@ -53,13 +53,18 @@ class PostParseCallable implements Callable { // Process the filters before finish, because parsing the html is dependent on filter matches processPostFilter(post); - post.isSavedReply(savedReplyManager.isSaved(post.board.code, post.id)); + post.isSavedReply(savedReplyManager.isSaved(post.board, post.id)); // if (!post.parse(parser)) { // Logger.e(TAG, "Incorrect data about post received for post " + post.no); // return null; // } - return reader.getParser().parse(null, post); + return reader.getParser().parse(null, post, new ChanParser.Callback() { + @Override + public boolean isSaved(int postNo) { + return savedReplyManager.isSaved(post.board, postNo); + } + }); } private void processPostFilter(Post.Builder post) { diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4.java b/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4.java index 01742158..e83c1b09 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4.java +++ b/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4.java @@ -22,11 +22,6 @@ import android.support.annotation.Nullable; import android.webkit.CookieManager; import android.webkit.WebView; -import com.android.volley.RequestQueue; -import com.android.volley.Response; -import com.android.volley.VolleyError; - -import org.floens.chan.core.manager.BoardManager; import org.floens.chan.core.model.Post; import org.floens.chan.core.model.orm.Board; import org.floens.chan.core.model.orm.Loadable; @@ -44,7 +39,6 @@ import org.floens.chan.core.site.common.CommonReplyHttpCall; import org.floens.chan.core.site.common.FutabaChanReader; import org.floens.chan.core.site.http.DeleteRequest; import org.floens.chan.core.site.http.HttpCall; -import org.floens.chan.core.site.http.HttpCallManager; import org.floens.chan.core.site.http.LoginRequest; import org.floens.chan.core.site.http.LoginResponse; import org.floens.chan.core.site.http.Reply; @@ -58,13 +52,9 @@ import java.util.Locale; import java.util.Map; import java.util.Random; -import javax.inject.Inject; - import okhttp3.HttpUrl; import okhttp3.Request; -import static org.floens.chan.Chan.getGraph; - public class Chan4 extends SiteBase { public static final Resolvable RESOLVABLE = new Resolvable() { @Override @@ -88,12 +78,6 @@ public class Chan4 extends SiteBase { private static final Random random = new Random(); - @Inject - HttpCallManager httpCallManager; - - @Inject - RequestQueue requestQueue; - private final SiteEndpoints endpoints = new SiteEndpoints() { private final HttpUrl a = new HttpUrl.Builder() .scheme("https") @@ -276,8 +260,6 @@ public class Chan4 extends SiteBase { private final StringSetting passToken; public Chan4() { - getGraph().inject(this); - SharedPreferences p = AndroidUtils.getPreferences(); passUser = new StringSetting(p, "preference_pass_token", ""); passPass = new StringSetting(p, "preference_pass_pin", ""); @@ -353,40 +335,22 @@ public class Chan4 extends SiteBase { @Override public void boards(final BoardsListener listener) { - requestQueue.add(new Chan4BoardsRequest(this, new Response.Listener>() { - @Override - public void onResponse(List response) { - listener.onBoardsReceived(new Boards(response)); - } - }, new Response.ErrorListener() { - @Override - public void onErrorResponse(VolleyError error) { - Logger.e(TAG, "Failed to get boards from server", error); - - // API fail, provide some default boards - List list = new ArrayList<>(); - list.add(new Board(Chan4.this, "Technology", "g", true, true)); - list.add(new Board(Chan4.this, "Food & Cooking", "ck", true, true)); - list.add(new Board(Chan4.this, "Do It Yourself", "diy", true, true)); - list.add(new Board(Chan4.this, "Animals & Nature", "an", true, true)); - Collections.shuffle(list); - listener.onBoardsReceived(new Boards(list)); - } + requestQueue.add(new Chan4BoardsRequest(this, response -> { + listener.onBoardsReceived(new Boards(response)); + }, (error) -> { + Logger.e(TAG, "Failed to get boards from server", error); + + // API fail, provide some default boards + List list = new ArrayList<>(); + list.add(new Board(Chan4.this, "Technology", "g", true, true)); + list.add(new Board(Chan4.this, "Food & Cooking", "ck", true, true)); + list.add(new Board(Chan4.this, "Do It Yourself", "diy", true, true)); + list.add(new Board(Chan4.this, "Animals & Nature", "an", true, true)); + Collections.shuffle(list); + listener.onBoardsReceived(new Boards(list)); })); } - @Override - public Board board(String code) { - List allBoards = getGraph().get(BoardManager.class).getSavedBoards(); - for (Board board : allBoards) { - if (board.code.equals(code)) { - return board; - } - } - - return null; - } - @Override public SiteEndpoints endpoints() { return endpoints; diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan8/Chan8.java b/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan8/Chan8.java index 5f176799..57440a64 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan8/Chan8.java +++ b/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan8/Chan8.java @@ -21,7 +21,6 @@ package org.floens.chan.core.site.sites.chan8; import android.support.annotation.Nullable; import android.webkit.WebView; -import org.floens.chan.core.manager.BoardManager; import org.floens.chan.core.model.Post; import org.floens.chan.core.model.orm.Board; import org.floens.chan.core.model.orm.Loadable; @@ -236,11 +235,6 @@ public class Chan8 extends SiteBase { public void boards(BoardsListener boardsListener) { } - @Override - public Board board(String code) { - return getGraph().get(BoardManager.class).getForCode(this, code); - } - @Override public ChanReader chanReader() { FutabaChanParser parser = new FutabaChanParser(new Chan8ParserHandler()); 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 fc4bf8b5..ce9af43f 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 @@ -180,11 +180,12 @@ public class StartActivity extends AppCompatActivity implements NfcAdapter.Creat // Not from a state or from an url, launch the setup controller if no boards are setup up yet, // otherwise load the default saved board. if (loadDefault) { - if (boardManager.getSavedBoards().isEmpty()) { + /*if (boardManager.getSavedBoards().isEmpty()) { setupWithNoBoards(); } else { browseController.loadWithDefaultBoard(); - } + }*/ + browseController.loadWithDefaultBoard(); } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/DeveloperSettingsController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/DeveloperSettingsController.java index 576f92d0..f558b1e1 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/DeveloperSettingsController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/DeveloperSettingsController.java @@ -27,9 +27,6 @@ import android.widget.TextView; import org.floens.chan.R; import org.floens.chan.controller.Controller; import org.floens.chan.core.database.DatabaseManager; -import org.floens.chan.core.model.orm.SavedReply; - -import java.util.Random; import javax.inject.Inject; @@ -98,24 +95,6 @@ public class DeveloperSettingsController extends Controller { resetDbButton.setText("Delete database"); wrapper.addView(resetDbButton); - Button savedReplyDummyAdd = new Button(context); - savedReplyDummyAdd.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(final View v) { - Random r = new Random(); - int j = 0; - for (int i = 0; i < 100; i++) { - j += r.nextInt(10000); - - SavedReply saved = new SavedReply("g", j, ""); - databaseManager.runTask(databaseManager.getDatabaseSavedReplyManager().saveReply(saved)); - } - setDbSummary(); - } - }); - savedReplyDummyAdd.setText("Add test rows to savedReply"); - wrapper.addView(savedReplyDummyAdd); - ScrollView scrollView = new ScrollView(context); scrollView.addView(wrapper); view = scrollView; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/ThemeSettingsController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/ThemeSettingsController.java index 18385105..8d30ca8e 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/ThemeSettingsController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/ThemeSettingsController.java @@ -37,6 +37,7 @@ import android.widget.LinearLayout; import android.widget.TextView; import org.floens.chan.R; +import org.floens.chan.core.site.common.ChanParser; import org.floens.chan.core.site.common.DefaultFutabaChanParserHandler; import org.floens.chan.core.site.common.FutabaChanParser; import org.floens.chan.controller.Controller; @@ -106,6 +107,13 @@ public class ThemeSettingsController extends Controller implements View.OnClickL } }; + private ChanParser.Callback parserCallback = new ChanParser.Callback() { + @Override + public boolean isSaved(int postNo) { + return false; + } + }; + private ViewPager pager; private FloatingActionButton done; private TextView textView; @@ -251,7 +259,7 @@ public class ThemeSettingsController extends Controller implements View.OnClickL "http://example.com/" + "
" + "Phasellus consequat semper sodales. Donec dolor lectus, aliquet nec mollis vel, rutrum vel enim."); - Post post = new FutabaChanParser(new DefaultFutabaChanParserHandler()).parse(theme, builder); + Post post = new FutabaChanParser(new DefaultFutabaChanParserHandler()).parse(theme, builder, parserCallback); LinearLayout linearLayout = new LinearLayout(themeContext); linearLayout.setOrientation(LinearLayout.VERTICAL); 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 858fa0a6..2bcfbd39 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,6 +31,7 @@ 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; @@ -45,6 +46,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.ui.controller.FiltersController; import org.floens.chan.ui.dialog.ColorPickerView; import org.floens.chan.ui.drawable.DropdownArrowDrawable; @@ -228,7 +230,12 @@ public class FilterLayout extends LinearLayout implements View.OnClickListener { List> items = new ArrayList<>(); - for (Board board : boardManager.getSavedBoards()) { + List allSavedBoards = new ArrayList<>(); + for (Pair> sites : boardManager.getSavedBoardsObservable().get()) { + allSavedBoards.addAll(sites.second); + } + + for (Board board : allSavedBoards) { String name = BoardHelper.getName(board); boolean checked = filterEngine.matchesBoard(filter, board);