Work on making all components work without a complete board list.

We want to support sites which have no boards.json like endpoint or have
support for infine boards, so we want to work without boards being
available.
Don't crash when no board is loaded.
Partial workaround for filters, will get to that later.
multisite
Floens 8 years ago
parent 29450067b8
commit 2f31d19279
  1. 17
      Clover/app/src/main/java/org/floens/chan/core/manager/BoardManager.java
  2. 41
      Clover/app/src/main/java/org/floens/chan/core/manager/FilterEngine.java
  3. 2
      Clover/app/src/main/java/org/floens/chan/core/presenter/ReplyPresenter.java
  4. 4
      Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java
  5. 10
      Clover/app/src/main/java/org/floens/chan/core/site/Site.java
  6. 57
      Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4.java
  7. 42
      Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java
  8. 46
      Clover/app/src/main/java/org/floens/chan/ui/controller/BrowseController.java
  9. 8
      Clover/app/src/main/java/org/floens/chan/ui/controller/HistoryController.java
  10. 88
      Clover/app/src/main/java/org/floens/chan/ui/layout/FilterLayout.java
  11. 36
      Clover/app/src/main/res/layout/layout_site_board_select.xml
  12. 2
      Clover/app/src/main/res/values/strings.xml

@ -35,6 +35,9 @@ import javax.inject.Singleton;
import de.greenrobot.event.EventBus; import de.greenrobot.event.EventBus;
/**
* Keeps track of {@link Board}s that the user has "saved" to their list.
*/
@Singleton @Singleton
public class BoardManager { public class BoardManager {
private static final String TAG = "BoardManager"; private static final String TAG = "BoardManager";
@ -67,13 +70,6 @@ public class BoardManager {
boards = databaseManager.runTaskSync(databaseManager.getDatabaseBoardManager().getBoards(defaultSite)); boards = databaseManager.runTaskSync(databaseManager.getDatabaseBoardManager().getBoards(defaultSite));
if (boards.isEmpty()) { if (boards.isEmpty()) {
defaultSite.boards(new Site.BoardsListener() {
@Override
public void onBoardsReceived(Boards boards) {
appendBoards(boards);
}
});
} else {
update(false); update(false);
} }
} }
@ -118,12 +114,7 @@ public class BoardManager {
} }
// Thread-safe // Thread-safe
public boolean getBoardExists(String code) { private Board getBoardByCode(String code) {
return getBoardByCode(code) != null;
}
// Thread-safe
public Board getBoardByCode(String code) {
synchronized (boardsByCode) { synchronized (boardsByCode) {
return boardsByCode.get(code); return boardsByCode.get(code);
} }

@ -22,9 +22,9 @@ import android.text.TextUtils;
import org.floens.chan.core.database.DatabaseFilterManager; import org.floens.chan.core.database.DatabaseFilterManager;
import org.floens.chan.core.database.DatabaseManager; import org.floens.chan.core.database.DatabaseManager;
import org.floens.chan.core.model.Board;
import org.floens.chan.core.model.Filter; import org.floens.chan.core.model.Filter;
import org.floens.chan.core.model.Post; import org.floens.chan.core.model.Post;
import org.floens.chan.core.site.Sites;
import org.floens.chan.utils.Logger; import org.floens.chan.utils.Logger;
import java.util.ArrayList; import java.util.ArrayList;
@ -67,6 +67,21 @@ public class FilterEngine {
} }
} }
// This is messy but required now that we can't know the Board immediately.
public static class SiteIdBoardCode {
public final int siteId;
public final String boardCode;
private SiteIdBoardCode(int site, String board) {
siteId = site;
boardCode = board;
}
public static SiteIdBoardCode fromSiteIdBoardCode(int siteId, String boardCode) {
return new SiteIdBoardCode(siteId, boardCode);
}
}
private final DatabaseManager databaseManager; private final DatabaseManager databaseManager;
private final BoardManager boardManager; private final BoardManager boardManager;
@ -221,15 +236,21 @@ public class FilterEngine {
return pattern; return pattern;
} }
public List<Board> getBoardsForFilter(Filter filter) { public List<SiteIdBoardCode> getBoardsForFilter(Filter filter) {
if (filter.allBoards) { if (filter.allBoards) {
return boardManager.getSavedBoards(); return Collections.emptyList();
} else if (!TextUtils.isEmpty(filter.boards)) { } else if (!TextUtils.isEmpty(filter.boards)) {
List<Board> appliedBoards = new ArrayList<>(); List<SiteIdBoardCode> appliedBoards = new ArrayList<>();
for (String value : filter.boards.split(",")) { for (String value : filter.boards.split(",")) {
Board boardByValue = boardManager.getBoardByCode(value); if (value.contains(";")) {
if (boardByValue != null) { String[] siteAndBoard = value.split(";");
appliedBoards.add(boardByValue); if (siteAndBoard.length == 1) {
appliedBoards.add(SiteIdBoardCode.fromSiteIdBoardCode(Integer.parseInt(siteAndBoard[0]), ""));
} else {
appliedBoards.add(SiteIdBoardCode.fromSiteIdBoardCode(Integer.parseInt(siteAndBoard[0]), siteAndBoard[1]));
}
} else {
appliedBoards.add(SiteIdBoardCode.fromSiteIdBoardCode(Sites.defaultSite().id(), value));
} }
} }
return appliedBoards; return appliedBoards;
@ -238,11 +259,11 @@ public class FilterEngine {
} }
} }
public void saveBoardsToFilter(List<Board> appliedBoards, Filter filter) { public void saveBoardsToFilter(List<SiteIdBoardCode> appliedBoards, Filter filter) {
filter.boards = ""; filter.boards = "";
for (int i = 0; i < appliedBoards.size(); i++) { for (int i = 0; i < appliedBoards.size(); i++) {
Board board = appliedBoards.get(i); SiteIdBoardCode siteAndBoard = appliedBoards.get(i);
filter.boards += board.code; filter.boards += siteAndBoard.siteId + ";" + siteAndBoard.boardCode;
if (i < appliedBoards.size() - 1) { if (i < appliedBoards.size() - 1) {
filter.boards += ","; filter.boards += ",";
} }

@ -106,7 +106,7 @@ public class ReplyPresenter implements CaptchaCallback, ImagePickDelegate.ImageP
callback.setCaptchaVersion(ChanSettings.postNewCaptcha.get()); callback.setCaptchaVersion(ChanSettings.postNewCaptcha.get());
this.board = boardManager.getBoardByCode(loadable.boardCode); this.board = loadable.board;
draft = replyManager.getReply(loadable); draft = replyManager.getReply(loadable);

@ -141,6 +141,10 @@ public class ThreadPresenter implements ChanLoader.ChanLoaderCallback, PostAdapt
} }
} }
public boolean isBound() {
return chanLoader != null;
}
public void requestInitialData() { public void requestInitialData() {
if (chanLoader.getThread() == null) { if (chanLoader.getThread() == null) {
requestData(); requestData();

@ -109,6 +109,8 @@ public interface Site {
*/ */
int id(); int id();
String name();
boolean feature(Feature feature); boolean feature(Feature feature);
boolean boardFeature(BoardFeature boardFeature, Board board); boolean boardFeature(BoardFeature boardFeature, Board board);
@ -129,7 +131,13 @@ public interface Site {
void onBoardsReceived(Boards boards); void onBoardsReceived(Boards boards);
} }
Board board(String name); Board board(String code);
interface BoardListener {
void onBoardReceived(Board board);
void onBoardNonexistent();
}
ChanLoaderRequest loaderRequest(ChanLoaderRequestParams request); ChanLoaderRequest loaderRequest(ChanLoaderRequestParams request);

@ -274,6 +274,11 @@ public class Chan4 implements Site {
return 0; return 0;
} }
@Override
public String name() {
return "4chan";
}
@Override @Override
public boolean feature(Feature feature) { public boolean feature(Feature feature) {
switch (feature) { switch (feature) {
@ -330,10 +335,34 @@ public class Chan4 implements Site {
} }
@Override @Override
public Board board(String name) { public void boards(final BoardsListener listener) {
requestQueue.add(new Chan4BoardsRequest(this, new Response.Listener<List<Board>>() {
@Override
public void onResponse(List<Board> 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<Board> 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<Board> allBoards = getGraph().getBoardManager().getAllBoards(); List<Board> allBoards = getGraph().getBoardManager().getAllBoards();
for (Board board : allBoards) { for (Board board : allBoards) {
if (board.code.equals(name)) { if (board.code.equals(code)) {
return board; return board;
} }
} }
@ -356,30 +385,6 @@ public class Chan4 implements Site {
return authentication; return authentication;
} }
@Override
public void boards(final BoardsListener listener) {
requestQueue.add(new Chan4BoardsRequest(this, new Response.Listener<List<Board>>() {
@Override
public void onResponse(List<Board> 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<Board> 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 @Override
public ChanLoaderRequest loaderRequest(ChanLoaderRequestParams request) { public ChanLoaderRequest loaderRequest(ChanLoaderRequestParams request) {
return new ChanLoaderRequest(new Chan4ReaderRequest(request)); return new ChanLoaderRequest(new Chan4ReaderRequest(request));

@ -28,6 +28,7 @@ import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.util.Pair;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -45,6 +46,8 @@ import org.floens.chan.core.model.Board;
import org.floens.chan.core.model.Loadable; import org.floens.chan.core.model.Loadable;
import org.floens.chan.core.model.Pin; import org.floens.chan.core.model.Pin;
import org.floens.chan.core.settings.ChanSettings; import org.floens.chan.core.settings.ChanSettings;
import org.floens.chan.core.site.Site;
import org.floens.chan.core.site.Sites;
import org.floens.chan.ui.controller.BrowseController; import org.floens.chan.ui.controller.BrowseController;
import org.floens.chan.ui.controller.DoubleNavigationController; import org.floens.chan.ui.controller.DoubleNavigationController;
import org.floens.chan.ui.controller.DrawerController; import org.floens.chan.ui.controller.DrawerController;
@ -53,8 +56,8 @@ import org.floens.chan.ui.controller.StyledToolbarNavigationController;
import org.floens.chan.ui.controller.ThreadSlideController; import org.floens.chan.ui.controller.ThreadSlideController;
import org.floens.chan.ui.controller.ViewThreadController; import org.floens.chan.ui.controller.ViewThreadController;
import org.floens.chan.ui.helper.ImagePickDelegate; import org.floens.chan.ui.helper.ImagePickDelegate;
import org.floens.chan.ui.helper.VersionHandler;
import org.floens.chan.ui.helper.RuntimePermissionsHelper; import org.floens.chan.ui.helper.RuntimePermissionsHelper;
import org.floens.chan.ui.helper.VersionHandler;
import org.floens.chan.ui.state.ChanState; import org.floens.chan.ui.state.ChanState;
import org.floens.chan.ui.theme.ThemeHelper; import org.floens.chan.ui.theme.ThemeHelper;
import org.floens.chan.utils.AndroidUtils; import org.floens.chan.utils.AndroidUtils;
@ -131,16 +134,16 @@ public class StartActivity extends AppCompatActivity implements NfcAdapter.Creat
if (chanState == null) { if (chanState == null) {
Logger.w(TAG, "savedInstanceState was not null, but no ChanState was found!"); Logger.w(TAG, "savedInstanceState was not null, but no ChanState was found!");
} else { } else {
DatabaseLoadableManager loadableManager = databaseManager.getDatabaseLoadableManager(); Pair<Loadable, Loadable> boardThreadPair = resolveChanState(chanState);
chanState.board = loadableManager.get(chanState.board);
chanState.thread = loadableManager.get(chanState.thread);
if (boardThreadPair != null && boardThreadPair.first != null) {
loadDefault = false; loadDefault = false;
Board board = boardManager.getBoardByCode(chanState.board.boardCode);
browseController.loadBoard(board);
if (chanState.thread.mode == Loadable.Mode.THREAD) { browseController.loadBoard(boardThreadPair.first.board);
browseController.showThread(chanState.thread, false);
if (boardThreadPair.second != null) {
browseController.showThread(boardThreadPair.second);
}
} }
} }
} else { } else {
@ -149,8 +152,7 @@ public class StartActivity extends AppCompatActivity implements NfcAdapter.Creat
Loadable fromUri = ChanHelper.getLoadableFromStartUri(data); Loadable fromUri = ChanHelper.getLoadableFromStartUri(data);
if (fromUri != null) { if (fromUri != null) {
loadDefault = false; loadDefault = false;
Board board = boardManager.getBoardByCode(fromUri.boardCode); browseController.loadBoard(fromUri.board);
browseController.loadBoard(board);
if (fromUri.isThreadMode()) { if (fromUri.isThreadMode()) {
browseController.showThread(fromUri, false); browseController.showThread(fromUri, false);
@ -176,6 +178,26 @@ public class StartActivity extends AppCompatActivity implements NfcAdapter.Creat
versionHandler.run(); versionHandler.run();
} }
private Pair<Loadable, Loadable> resolveChanState(ChanState state) {
DatabaseLoadableManager loadableManager = databaseManager.getDatabaseLoadableManager();
Site site = Sites.forId(state.board.siteId);
Board board = site.board(state.board.boardCode);
if (board != null) {
state.board.site = site;
state.board.board = board;
state.thread.site = site;
state.thread.board = board;
Loadable boardLoadable = loadableManager.get(state.board);
Loadable threadLoadable = loadableManager.get(state.thread);
return new Pair<>(boardLoadable, threadLoadable.mode == Loadable.Mode.THREAD ? threadLoadable : null);
}
return null;
}
private void setupLayout() { private void setupLayout() {
mainNavigationController = new StyledToolbarNavigationController(this); mainNavigationController = new StyledToolbarNavigationController(this);

@ -19,13 +19,13 @@ package org.floens.chan.ui.controller;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context; import android.content.Context;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator; import android.view.animation.DecelerateInterpolator;
import android.widget.BaseAdapter; import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import org.floens.chan.R; import org.floens.chan.R;
@ -72,8 +72,6 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte
private PostsFilter.Order order; private PostsFilter.Order order;
private List<FloatingMenuItem> boardItems; private List<FloatingMenuItem> boardItems;
private ProgressDialog waitingForBoardsDialog;
private FloatingMenuItem viewModeMenuItem; private FloatingMenuItem viewModeMenuItem;
private ToolbarMenuItem search; private ToolbarMenuItem search;
private ToolbarMenuItem refresh; private ToolbarMenuItem refresh;
@ -123,20 +121,32 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte
@Override @Override
public void onMenuItemClicked(ToolbarMenuItem item) { public void onMenuItemClicked(ToolbarMenuItem item) {
ThreadPresenter presenter = threadLayout.getPresenter();
switch ((Integer) item.getId()) { switch ((Integer) item.getId()) {
case SEARCH_ID: case SEARCH_ID:
if (presenter.isBound()) {
((ToolbarNavigationController) navigationController).showSearch(); ((ToolbarNavigationController) navigationController).showSearch();
}
break; break;
case REFRESH_ID: case REFRESH_ID:
threadLayout.getPresenter().requestData(); if (presenter.isBound()) {
refresh.getView().setRotation(0f); presenter.requestData();
refresh.getView().animate().rotation(360f).setDuration(500).setInterpolator(new DecelerateInterpolator(2f)); ImageView refreshView = refresh.getView();
refreshView.setRotation(0f);
refreshView.animate()
.rotation(360f)
.setDuration(500)
.setInterpolator(new DecelerateInterpolator(2f));
}
break; break;
} }
} }
@Override @Override
public void onSubMenuItemClicked(ToolbarMenuItem parent, FloatingMenuItem item) { public void onSubMenuItemClicked(ToolbarMenuItem parent, FloatingMenuItem item) {
final ThreadPresenter presenter = threadLayout.getPresenter();
Integer id = (Integer) item.getId(); Integer id = (Integer) item.getId();
switch (id) { switch (id) {
case REPLY_ID: case REPLY_ID:
@ -144,14 +154,15 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte
break; break;
case SHARE_ID: case SHARE_ID:
case OPEN_BROWSER_ID: case OPEN_BROWSER_ID:
String link = ChanUrls.getCatalogUrlDesktop(threadLayout.getPresenter().getLoadable().boardCode); if (presenter.isBound()) {
String link = ChanUrls.getCatalogUrlDesktop(presenter.getLoadable().boardCode);
if (id == SHARE_ID) { if (id == SHARE_ID) {
AndroidUtils.shareLink(link); AndroidUtils.shareLink(link);
} else { } else {
AndroidUtils.openLinkInBrowser((Activity) context, link); AndroidUtils.openLinkInBrowser((Activity) context, link);
} }
}
break; break;
case VIEW_MODE_ID: case VIEW_MODE_ID:
if (postViewMode == ChanSettings.PostViewMode.LIST) { if (postViewMode == ChanSettings.PostViewMode.LIST) {
@ -205,7 +216,7 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte
PostsFilter.Order order = (PostsFilter.Order) item.getId(); PostsFilter.Order order = (PostsFilter.Order) item.getId();
ChanSettings.boardOrder.set(order.name); ChanSettings.boardOrder.set(order.name);
BrowseController.this.order = order; BrowseController.this.order = order;
threadLayout.getPresenter().setOrder(order); presenter.setOrder(order);
} }
@Override @Override
@ -341,19 +352,7 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte
private void loadBoards() { private void loadBoards() {
List<Board> boards = boardManager.getSavedBoards(); List<Board> boards = boardManager.getSavedBoards();
if (boards.isEmpty()) { boolean wasEmpty = boardItems == null;
if (waitingForBoardsDialog == null) {
String title = getString(R.string.thread_fetching_boards_title);
String message = getString(R.string.thread_fetching_boards);
waitingForBoardsDialog = ProgressDialog.show(context, title, message, true, false);
waitingForBoardsDialog.show();
}
} else {
boolean wasWaiting = waitingForBoardsDialog != null;
if (waitingForBoardsDialog != null) {
waitingForBoardsDialog.dismiss();
waitingForBoardsDialog = null;
}
boardItems = new ArrayList<>(); boardItems = new ArrayList<>();
for (Board board : boards) { for (Board board : boards) {
@ -364,11 +363,10 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte
navigationItem.middleMenu.setItems(boardItems); navigationItem.middleMenu.setItems(boardItems);
navigationItem.middleMenu.setAdapter(new BoardsAdapter(context, boardItems)); navigationItem.middleMenu.setAdapter(new BoardsAdapter(context, boardItems));
if (wasWaiting) { if (wasEmpty) {
loadDefault(); loadDefault();
} }
} }
}
private static class FloatingMenuItemBoard extends FloatingMenuItem { private static class FloatingMenuItemBoard extends FloatingMenuItem {
public Board board; public Board board;

@ -31,7 +31,6 @@ import android.widget.CompoundButton;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import org.floens.chan.Chan;
import org.floens.chan.R; import org.floens.chan.R;
import org.floens.chan.controller.Controller; import org.floens.chan.controller.Controller;
import org.floens.chan.core.database.DatabaseHistoryManager; import org.floens.chan.core.database.DatabaseHistoryManager;
@ -47,7 +46,6 @@ import org.floens.chan.ui.toolbar.ToolbarMenuItem;
import org.floens.chan.ui.view.CrossfadeView; import org.floens.chan.ui.view.CrossfadeView;
import org.floens.chan.ui.view.FloatingMenuItem; import org.floens.chan.ui.view.FloatingMenuItem;
import org.floens.chan.ui.view.ThumbnailView; import org.floens.chan.ui.view.ThumbnailView;
import org.floens.chan.utils.Logger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -205,12 +203,8 @@ public class HistoryController extends Controller implements CompoundButton.OnCh
History history = displayList.get(position); History history = displayList.get(position);
holder.thumbnail.setUrl(history.thumbnailUrl, dp(48), dp(48)); holder.thumbnail.setUrl(history.thumbnailUrl, dp(48), dp(48));
if (history.loadable == null) {
Logger.test("null!");
}
holder.text.setText(history.loadable.title); holder.text.setText(history.loadable.title);
Board board = boardManager.getBoardByCode(history.loadable.boardCode); Board board = history.loadable.board;
holder.subtext.setText(board == null ? null : ("/" + board.code + "/ \u2013 " + board.name)); holder.subtext.setText(board == null ? null : ("/" + board.code + "/ \u2013 " + board.name));
} }

@ -33,23 +33,29 @@ import android.util.AttributeSet;
import android.view.Gravity; import android.view.Gravity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.SpinnerAdapter;
import android.widget.TextView; import android.widget.TextView;
import org.floens.chan.R; import org.floens.chan.R;
import org.floens.chan.core.manager.BoardManager; import org.floens.chan.core.manager.BoardManager;
import org.floens.chan.core.manager.FilterEngine; import org.floens.chan.core.manager.FilterEngine;
import org.floens.chan.core.manager.FilterType; import org.floens.chan.core.manager.FilterType;
import org.floens.chan.core.model.Board;
import org.floens.chan.core.model.Filter; import org.floens.chan.core.model.Filter;
import org.floens.chan.core.site.Site;
import org.floens.chan.core.site.Sites;
import org.floens.chan.ui.controller.FiltersController; import org.floens.chan.ui.controller.FiltersController;
import org.floens.chan.ui.dialog.ColorPickerView; import org.floens.chan.ui.dialog.ColorPickerView;
import org.floens.chan.ui.drawable.DropdownArrowDrawable; import org.floens.chan.ui.drawable.DropdownArrowDrawable;
import org.floens.chan.ui.helper.BoardHelper;
import org.floens.chan.ui.view.FloatingMenu; import org.floens.chan.ui.view.FloatingMenu;
import org.floens.chan.ui.view.FloatingMenuItem; import org.floens.chan.ui.view.FloatingMenuItem;
import org.floens.chan.utils.Logger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -84,7 +90,7 @@ public class FilterLayout extends LinearLayout implements View.OnClickListener {
private FilterLayoutCallback callback; private FilterLayoutCallback callback;
private Filter filter; private Filter filter;
private List<Board> appliedBoards = new ArrayList<>(); private List<FilterEngine.SiteIdBoardCode> appliedBoards = new ArrayList<>();
public FilterLayout(Context context) { public FilterLayout(Context context) {
super(context); super(context);
@ -226,49 +232,75 @@ public class FilterLayout extends LinearLayout implements View.OnClickListener {
}) })
.show(); .show();
} else if (v == boardsSelector) { } else if (v == boardsSelector) {
@SuppressWarnings("unchecked") // TODO(multi-site): fix this crap.
final SelectLayout<Board> selectLayout = (SelectLayout<Board>) LayoutInflater.from(getContext()).inflate(R.layout.layout_select, null); // we need a new proper recyclerview layout where you can individually select each site and board combination
// and if you don't select anything, it becomes a global filter.
final LinearLayout selectLayout = (LinearLayout) LayoutInflater.from(getContext())
.inflate(R.layout.layout_site_board_select, null);
final Spinner spinner = (Spinner) selectLayout.findViewById(R.id.spinner);
List<SelectLayout.SelectItem<Board>> items = new ArrayList<>(); final List<? extends Site> allSites = Sites.ALL_SITES;
List<Board> savedList = boardManager.getSavedBoards();
for (int i = 0; i < savedList.size(); i++) {
Board saved = savedList.get(i);
String name = BoardHelper.getName(saved);
String description = BoardHelper.getDescription(saved);
String search = name + " " + saved.code;
boolean checked = false; final Site[] selectedSite = {allSites.get(0)};
for (int j = 0; j < appliedBoards.size(); j++) {
Board appliedBoard = appliedBoards.get(j); List<String> allSitesNames = new ArrayList<>(allSites.size());
if (appliedBoard.code.equals(saved.code)) { for (int i = 0; i < allSites.size(); i++) {
checked = true; Site site = allSites.get(i);
break; allSitesNames.add(site.name());
} }
SpinnerAdapter adapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_list_item_1, allSitesNames);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
Site site = allSites.get(position);
selectedSite[0] = site;
Logger.test(site.name());
} }
items.add(new SelectLayout.SelectItem<>( @Override
saved, saved.id, name, description, search, checked public void onNothingSelected(AdapterView<?> parent) {
));
} }
});
selectLayout.setItems(items); final EditText editText = (EditText) selectLayout.findViewById(R.id.boards);
String text = "";
for (int i = 0; i < appliedBoards.size(); i++) {
FilterEngine.SiteIdBoardCode siteIdBoardCode = appliedBoards.get(i);
text += siteIdBoardCode.boardCode;
if (i < appliedBoards.size() - 1) {
text += ",";
}
}
editText.setText(text);
new AlertDialog.Builder(getContext()) new AlertDialog.Builder(getContext())
.setView(selectLayout) .setView(selectLayout)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
Site site = selectedSite[0];
appliedBoards.clear(); appliedBoards.clear();
List<SelectLayout.SelectItem<Board>> items = selectLayout.getItems(); String[] codes = editText.getText().toString().split(",");
for (int i = 0; i < items.size(); i++) { if (codes.length == 0) {
SelectLayout.SelectItem<Board> selectItem = items.get(i); filter.allBoards = true;
if (selectItem.checked) { } else {
appliedBoards.add(selectItem.item); filter.allBoards = false;
for (String code : codes) {
appliedBoards.add(FilterEngine.SiteIdBoardCode.fromSiteIdBoardCode(
site.id(), code
));
} }
} }
filter.allBoards = selectLayout.areAllChecked();
updateBoardsSummary(); updateBoardsSummary();
} }
}) })

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?><!--
Clover - 4chan browser https://github.com/Floens/Clover/
Copyright (C) 2014 Floens
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="16dp"
android:paddingRight="16dp">
<Spinner
android:id="@+id/spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<EditText
android:id="@+id/boards"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>

@ -145,8 +145,6 @@ Re-enable this permission in the app settings if you permanently disabled it."</
<string name="image_open_failed">Failed to open image</string> <string name="image_open_failed">Failed to open image</string>
<string name="image_spoiler_filename">Spoiler image</string> <string name="image_spoiler_filename">Spoiler image</string>
<string name="thread_fetching_boards_title">Fetching boards</string>
<string name="thread_fetching_boards">Please wait for the boards to be fetched, this may take up to a minute.</string>
<string name="thread_board_select_add">Add more&#8230;</string> <string name="thread_board_select_add">Add more&#8230;</string>
<string name="thread_load_failed_ssl">HTTPS error</string> <string name="thread_load_failed_ssl">HTTPS error</string>
<string name="thread_load_failed_network">Network error</string> <string name="thread_load_failed_network">Network error</string>

Loading…
Cancel
Save