Merge remote-tracking branch 'Floens/dev' into dev

multisite
Andrea Bergamasco 10 years ago
commit 0365cafaa9
  1. 2
      Clover/app/src/main/java/org/floens/chan/chan/ChanLoader.java
  2. 14
      Clover/app/src/main/java/org/floens/chan/chan/ImageSearch.java
  3. 2
      Clover/app/src/main/java/org/floens/chan/controller/Controller.java
  4. 69
      Clover/app/src/main/java/org/floens/chan/controller/NavigationController.java
  5. 50
      Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java
  6. 9
      Clover/app/src/main/java/org/floens/chan/ui/adapter/PinAdapter.java
  7. 24
      Clover/app/src/main/java/org/floens/chan/ui/controller/AdvancedSettingsController.java
  8. 33
      Clover/app/src/main/java/org/floens/chan/ui/controller/BrowseController.java
  9. 141
      Clover/app/src/main/java/org/floens/chan/ui/controller/DrawerController.java
  10. 4
      Clover/app/src/main/java/org/floens/chan/ui/controller/FiltersController.java
  11. 4
      Clover/app/src/main/java/org/floens/chan/ui/controller/HistoryController.java
  12. 7
      Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerNavigationController.java
  13. 79
      Clover/app/src/main/java/org/floens/chan/ui/controller/PopupController.java
  14. 101
      Clover/app/src/main/java/org/floens/chan/ui/controller/SplitNavigationController.java
  15. 100
      Clover/app/src/main/java/org/floens/chan/ui/controller/StyledToolbarNavigationController.java
  16. 23
      Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java
  17. 103
      Clover/app/src/main/java/org/floens/chan/ui/controller/ToolbarNavigationController.java
  18. 48
      Clover/app/src/main/java/org/floens/chan/ui/controller/ViewThreadController.java
  19. 49
      Clover/app/src/main/java/org/floens/chan/ui/layout/PostRepliesContainer.java
  20. 7
      Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadLayout.java
  21. 33
      Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadListLayout.java
  22. 8
      Clover/app/src/main/java/org/floens/chan/ui/toolbar/Toolbar.java
  23. 18
      Clover/app/src/main/res/layout/controller_navigation_drawer.xml
  24. 33
      Clover/app/src/main/res/layout/controller_navigation_toolbar.xml
  25. 32
      Clover/app/src/main/res/layout/layout_controller_popup.xml
  26. 4
      Clover/app/src/main/res/layout/layout_post_replies.xml
  27. 4
      Clover/app/src/main/res/layout/layout_post_replies_bottombuttons.xml
  28. 32
      Clover/app/src/main/res/layout/layout_split_empty.xml
  29. 1
      Clover/app/src/main/res/values/strings.xml
  30. 1
      Clover/app/src/main/res/values/styles.xml

@ -301,7 +301,7 @@ public class ChanLoader implements Response.ErrorListener, Response.Listener<Cha
} }
}; };
Logger.d(TAG, "Scheduled reload in " + watchTimeouts[currentTimeout] * 1000L); Logger.d(TAG, "Scheduled reload in " + watchTimeouts[currentTimeout] + "s");
pendingFuture = executor.schedule(pendingRunnable, watchTimeouts[currentTimeout], TimeUnit.SECONDS); pendingFuture = executor.schedule(pendingRunnable, watchTimeouts[currentTimeout], TimeUnit.SECONDS);
} }
} }

@ -57,5 +57,19 @@ public abstract class ImageSearch {
return "http://iqdb.org/?url=" + imageUrl; return "http://iqdb.org/?url=" + imageUrl;
} }
}); });
engines.add(new ImageSearch() {
public int getId() {
return 2;
}
public String getName() {
return "TinEye";
}
public String getUrl(String imageUrl) {
return "http://tineye.com/search/?url=" + imageUrl;
}
});
} }
} }

@ -34,6 +34,8 @@ public abstract class Controller {
public NavigationItem navigationItem = new NavigationItem(); public NavigationItem navigationItem = new NavigationItem();
public Controller parentController;
// NavigationControllers members // NavigationControllers members
public Controller previousSiblingController; public Controller previousSiblingController;
public NavigationController navigationController; public NavigationController navigationController;

@ -20,15 +20,11 @@ package org.floens.chan.controller;
import android.content.Context; import android.content.Context;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.FrameLayout;
import org.floens.chan.ui.toolbar.Toolbar;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public abstract class NavigationController extends Controller implements Toolbar.ToolbarCallback, ControllerTransition.Callback { public abstract class NavigationController extends Controller implements ControllerTransition.Callback {
protected Toolbar toolbar;
protected ViewGroup container; protected ViewGroup container;
protected List<Controller> controllerList = new ArrayList<>(); protected List<Controller> controllerList = new ArrayList<>();
@ -60,6 +56,11 @@ public abstract class NavigationController extends Controller implements Toolbar
if (blockingInput) return false; if (blockingInput) return false;
final Controller from = controllerList.size() > 0 ? controllerList.get(controllerList.size() - 1) : null; final Controller from = controllerList.size() > 0 ? controllerList.get(controllerList.size() - 1) : null;
if (from == null && controllerTransition != null) {
throw new IllegalArgumentException("Cannot animate push when from is null");
}
to.navigationController = this; to.navigationController = this;
to.previousSiblingController = from; to.previousSiblingController = from;
@ -111,12 +112,6 @@ public abstract class NavigationController extends Controller implements Toolbar
} }
if (to != null) { if (to != null) {
if (toolbar != null) {
toolbar.setNavigationItem(controllerTransition != null, pushing, to.navigationItem);
}
updateToolbarCollapse(to, controllerTransition != null);
if (pushing) { if (pushing) {
controllerPushed(to); controllerPushed(to);
} else { } else {
@ -158,17 +153,9 @@ public abstract class NavigationController extends Controller implements Toolbar
return controllerList; return controllerList;
} }
public Toolbar getToolbar() {
return toolbar;
}
public boolean onBack() { public boolean onBack() {
if (blockingInput) return true; if (blockingInput) return true;
if (toolbar != null && toolbar.closeSearch()) {
return true;
}
if (controllerList.size() > 0) { if (controllerList.size() > 0) {
Controller top = controllerList.get(controllerList.size() - 1); Controller top = controllerList.get(controllerList.size() - 1);
if (top.onBack()) { if (top.onBack()) {
@ -192,48 +179,4 @@ public abstract class NavigationController extends Controller implements Toolbar
controller.onConfigurationChanged(newConfig); controller.onConfigurationChanged(newConfig);
} }
} }
public void onMenuClicked() {
}
public void showSearch() {
if (toolbar != null) {
toolbar.openSearch();
}
}
@Override
public void onMenuOrBackClicked(boolean isArrow) {
if (isArrow) {
onBack();
} else {
onMenuClicked();
}
}
@Override
public void onSearchVisibilityChanged(boolean visible) {
}
@Override
public String getSearchHint() {
return "";
}
@Override
public void onSearchEntered(String entered) {
}
protected void updateToolbarCollapse(Controller controller, boolean animate) {
if (toolbar != null) {
if (!controller.navigationItem.collapseToolbar) {
FrameLayout.LayoutParams toViewParams = (FrameLayout.LayoutParams) controller.view.getLayoutParams();
toViewParams.topMargin = toolbar.getToolbarHeight();
controller.view.setLayoutParams(toViewParams);
}
toolbar.processScrollCollapse(Toolbar.TOOLBAR_COLLAPSE_SHOW, animate);
}
}
} }

@ -27,6 +27,7 @@ import android.nfc.NfcAdapter;
import android.nfc.NfcEvent; import android.nfc.NfcEvent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.ViewGroup; import android.view.ViewGroup;
import org.floens.chan.Chan; import org.floens.chan.Chan;
@ -40,8 +41,9 @@ 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.ui.controller.BrowseController; import org.floens.chan.ui.controller.BrowseController;
import org.floens.chan.ui.controller.DrawerNavigationController; import org.floens.chan.ui.controller.DrawerController;
import org.floens.chan.ui.controller.SplitNavigationController; import org.floens.chan.ui.controller.SplitNavigationController;
import org.floens.chan.ui.controller.StyledToolbarNavigationController;
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.state.ChanState; import org.floens.chan.ui.state.ChanState;
@ -61,7 +63,8 @@ public class StartActivity extends AppCompatActivity implements NfcAdapter.Creat
private List<Controller> stack = new ArrayList<>(); private List<Controller> stack = new ArrayList<>();
private final BoardManager boardManager; private final BoardManager boardManager;
private NavigationController navigationController; private DrawerController drawerController;
private NavigationController threadNavigationController;
private BrowseController browseController; private BrowseController browseController;
private ImagePickDelegate imagePickDelegate; private ImagePickDelegate imagePickDelegate;
@ -80,28 +83,31 @@ public class StartActivity extends AppCompatActivity implements NfcAdapter.Creat
contentView = (ViewGroup) findViewById(android.R.id.content); contentView = (ViewGroup) findViewById(android.R.id.content);
NavigationController mainThreadController; // Setup base controllers, and decide if to use the split layout for tablets
if (AndroidUtils.isTablet(this)) { drawerController = new DrawerController(this);
drawerController.onCreate();
drawerController.onShow();
StyledToolbarNavigationController toolbarNavigationController = new StyledToolbarNavigationController(this);
if (AndroidUtils.isTablet(this) && !ChanSettings.forcePhoneLayout.get()) {
SplitNavigationController splitNavigationController = new SplitNavigationController(this); SplitNavigationController splitNavigationController = new SplitNavigationController(this);
splitNavigationController.onCreate(); splitNavigationController.setEmptyView((ViewGroup) LayoutInflater.from(this).inflate(R.layout.layout_split_empty, null));
splitNavigationController.onShow();
DrawerNavigationController leftController = new DrawerNavigationController(this); drawerController.setChildController(splitNavigationController);
splitNavigationController.setLeftController(leftController);
navigationController = splitNavigationController; splitNavigationController.setLeftController(toolbarNavigationController);
mainThreadController = leftController; threadNavigationController = toolbarNavigationController;
} else { } else {
navigationController = new DrawerNavigationController(this); drawerController.setChildController(toolbarNavigationController);
navigationController.onCreate(); threadNavigationController = toolbarNavigationController;
mainThreadController = navigationController;
} }
setContentView(navigationController.view);
addController(navigationController);
browseController = new BrowseController(this); browseController = new BrowseController(this);
mainThreadController.pushController(browseController, false); toolbarNavigationController.pushController(browseController, false);
mainThreadController.onShow();
setContentView(drawerController.view);
addController(drawerController);
// Prevent overdraw // Prevent overdraw
// Do this after setContentView, or the decor creating will reset the background to a default non-null drawable // Do this after setContentView, or the decor creating will reset the background to a default non-null drawable
@ -171,9 +177,9 @@ public class StartActivity extends AppCompatActivity implements NfcAdapter.Creat
// Handle WatchNotifier clicks // Handle WatchNotifier clicks
if (intent.getExtras() != null) { if (intent.getExtras() != null) {
int pinId = intent.getExtras().getInt("pin_id", -2); int pinId = intent.getExtras().getInt("pin_id", -2);
if (pinId != -2 && navigationController.getTop() instanceof BrowseController) { if (pinId != -2 && threadNavigationController.getTop() instanceof BrowseController) {
if (pinId == -1) { if (pinId == -1) {
navigationController.onMenuClicked(); drawerController.onMenuClicked();
} else { } else {
Pin pin = Chan.getWatchManager().findPinById(pinId); Pin pin = Chan.getWatchManager().findPinById(pinId);
if (pin != null) { if (pin != null) {
@ -193,7 +199,7 @@ public class StartActivity extends AppCompatActivity implements NfcAdapter.Creat
Logger.w(TAG, "Can not save instance state, the board loadable is null"); Logger.w(TAG, "Can not save instance state, the board loadable is null");
} else { } else {
Loadable thread = null; Loadable thread = null;
List<Controller> controllers = navigationController.getControllerList(); List<Controller> controllers = threadNavigationController.getControllerList();
for (Controller controller : controllers) { for (Controller controller : controllers) {
if (controller instanceof ViewThreadController) { if (controller instanceof ViewThreadController) {
thread = ((ViewThreadController) controller).getLoadable(); thread = ((ViewThreadController) controller).getLoadable();
@ -212,7 +218,7 @@ public class StartActivity extends AppCompatActivity implements NfcAdapter.Creat
@Override @Override
public NdefMessage createNdefMessage(NfcEvent event) { public NdefMessage createNdefMessage(NfcEvent event) {
Controller controller = navigationController.getTop(); Controller controller = threadNavigationController.getTop();
if (controller instanceof NfcAdapter.CreateNdefMessageCallback) { if (controller instanceof NfcAdapter.CreateNdefMessageCallback) {
return ((NfcAdapter.CreateNdefMessageCallback) controller).createNdefMessage(event); return ((NfcAdapter.CreateNdefMessageCallback) controller).createNdefMessage(event);
} else { } else {

@ -53,12 +53,17 @@ public class PinAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> im
private final Callback callback; private final Callback callback;
private List<Pin> pins = new ArrayList<>(); private List<Pin> pins = new ArrayList<>();
private Pin highlighted;
public PinAdapter(Callback callback) { public PinAdapter(Callback callback) {
this.callback = callback; this.callback = callback;
setHasStableIds(true); setHasStableIds(true);
} }
public void setPinHighlighted(Pin highlighted) {
this.highlighted = highlighted;
}
@Override @Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) { switch (viewType) {
@ -242,7 +247,7 @@ public class PinAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> im
dp(16), holder.textView.getPaddingBottom()); dp(16), holder.textView.getPaddingBottom());
} }
boolean highlighted = callback.isHighlighted(pin); boolean highlighted = pin == this.highlighted;
if (highlighted && !holder.highlighted) { if (highlighted && !holder.highlighted) {
holder.itemView.setBackgroundColor(0x22000000); holder.itemView.setBackgroundColor(0x22000000);
holder.highlighted = true; holder.highlighted = true;
@ -377,8 +382,6 @@ public class PinAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> im
void onHeaderClicked(HeaderHolder holder); void onHeaderClicked(HeaderHolder holder);
boolean isHighlighted(Pin pin);
void onPinRemoved(Pin pin); void onPinRemoved(Pin pin);
void onPinLongClocked(Pin pin); void onPinLongClocked(Pin pin);

@ -25,10 +25,12 @@ import android.widget.LinearLayout;
import org.floens.chan.R; import org.floens.chan.R;
import org.floens.chan.core.settings.ChanSettings; import org.floens.chan.core.settings.ChanSettings;
import org.floens.chan.ui.activity.StartActivity;
import org.floens.chan.ui.fragment.FolderPickFragment; import org.floens.chan.ui.fragment.FolderPickFragment;
import org.floens.chan.ui.settings.BooleanSettingView; import org.floens.chan.ui.settings.BooleanSettingView;
import org.floens.chan.ui.settings.IntegerSettingView; import org.floens.chan.ui.settings.IntegerSettingView;
import org.floens.chan.ui.settings.LinkSettingView; import org.floens.chan.ui.settings.LinkSettingView;
import org.floens.chan.ui.settings.SettingView;
import org.floens.chan.ui.settings.SettingsController; import org.floens.chan.ui.settings.SettingsController;
import org.floens.chan.ui.settings.SettingsGroup; import org.floens.chan.ui.settings.SettingsGroup;
import org.floens.chan.ui.settings.StringSettingView; import org.floens.chan.ui.settings.StringSettingView;
@ -39,6 +41,8 @@ public class AdvancedSettingsController extends SettingsController {
private static final String TAG = "AdvancedSettingsController"; private static final String TAG = "AdvancedSettingsController";
private LinkSettingView saveLocation; private LinkSettingView saveLocation;
private SettingView forcePhoneLayoutSetting;
private boolean needRestart;
public AdvancedSettingsController(Context context) { public AdvancedSettingsController(Context context) {
super(context); super(context);
@ -58,6 +62,24 @@ public class AdvancedSettingsController extends SettingsController {
buildPreferences(); buildPreferences();
} }
@Override
public void onDestroy() {
super.onDestroy();
if (needRestart) {
((StartActivity) context).restart();
}
}
@Override
public void onPreferenceChange(SettingView item) {
super.onPreferenceChange(item);
if (item == forcePhoneLayoutSetting) {
needRestart = true;
}
}
private void populatePreferences() { private void populatePreferences() {
SettingsGroup settings = new SettingsGroup(string(R.string.settings_group_advanced)); SettingsGroup settings = new SettingsGroup(string(R.string.settings_group_advanced));
@ -86,7 +108,7 @@ public class AdvancedSettingsController extends SettingsController {
settings.add(new BooleanSettingView(this, ChanSettings.saveOriginalFilename, string(R.string.setting_save_original_filename), null)); settings.add(new BooleanSettingView(this, ChanSettings.saveOriginalFilename, string(R.string.setting_save_original_filename), null));
settings.add(new BooleanSettingView(this, ChanSettings.shareUrl, string(R.string.setting_share_url), string(R.string.setting_share_url_description))); settings.add(new BooleanSettingView(this, ChanSettings.shareUrl, string(R.string.setting_share_url), string(R.string.setting_share_url_description)));
settings.add(new BooleanSettingView(this, ChanSettings.networkHttps, string(R.string.setting_network_https), string(R.string.setting_network_https_description))); settings.add(new BooleanSettingView(this, ChanSettings.networkHttps, string(R.string.setting_network_https), string(R.string.setting_network_https_description)));
settings.add(new BooleanSettingView(this, ChanSettings.forcePhoneLayout, string(R.string.setting_force_phone_layout), null)); forcePhoneLayoutSetting = settings.add(new BooleanSettingView(this, ChanSettings.forcePhoneLayout, string(R.string.setting_force_phone_layout), null));
settings.add(new BooleanSettingView(this, ChanSettings.anonymize, string(R.string.setting_anonymize), null)); settings.add(new BooleanSettingView(this, ChanSettings.anonymize, string(R.string.setting_anonymize), null));
settings.add(new BooleanSettingView(this, ChanSettings.anonymizeIds, string(R.string.setting_anonymize_ids), null)); settings.add(new BooleanSettingView(this, ChanSettings.anonymizeIds, string(R.string.setting_anonymize_ids), null));
settings.add(new BooleanSettingView(this, ChanSettings.repliesButtonsBottom, string(R.string.setting_buttons_bottom), null)); settings.add(new BooleanSettingView(this, ChanSettings.repliesButtonsBottom, string(R.string.setting_buttons_bottom), null));

@ -29,7 +29,6 @@ import android.widget.TextView;
import org.floens.chan.Chan; import org.floens.chan.Chan;
import org.floens.chan.R; import org.floens.chan.R;
import org.floens.chan.chan.ChanUrls; import org.floens.chan.chan.ChanUrls;
import org.floens.chan.controller.Controller;
import org.floens.chan.core.manager.BoardManager; import org.floens.chan.core.manager.BoardManager;
import org.floens.chan.core.model.Board; import org.floens.chan.core.model.Board;
import org.floens.chan.core.model.Loadable; import org.floens.chan.core.model.Loadable;
@ -117,7 +116,7 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte
Integer id = (Integer) item.getId(); Integer id = (Integer) item.getId();
switch (id) { switch (id) {
case SEARCH_ID: case SEARCH_ID:
navigationController.showSearch(); ((ToolbarNavigationController) navigationController).showSearch();
break; break;
case SHARE_ID: case SHARE_ID:
case OPEN_BROWSER_ID: case OPEN_BROWSER_ID:
@ -200,7 +199,7 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte
if (menu == navigationItem.middleMenu) { if (menu == navigationItem.middleMenu) {
if (item instanceof FloatingMenuItemBoard) { if (item instanceof FloatingMenuItemBoard) {
loadBoard(((FloatingMenuItemBoard) item).board); loadBoard(((FloatingMenuItemBoard) item).board);
navigationController.getToolbar().updateNavigation(); ((ToolbarNavigationController) navigationController).getToolbar().updateNavigation();
} else { } else {
navigationController.pushController(new BoardEditController(context)); navigationController.pushController(new BoardEditController(context));
menu.dismiss(); menu.dismiss();
@ -212,6 +211,11 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte
public void onFloatingMenuDismissed(FloatingMenu menu) { public void onFloatingMenuDismissed(FloatingMenu menu) {
} }
@Override
public void openPin(Pin pin) {
showThread(pin.loadable);
}
@Override @Override
public void showThread(Loadable threadLoadable) { public void showThread(Loadable threadLoadable) {
showThread(threadLoadable, true); showThread(threadLoadable, true);
@ -221,13 +225,18 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte
if (navigationController.navigationController instanceof SplitNavigationController) { if (navigationController.navigationController instanceof SplitNavigationController) {
SplitNavigationController splitNavigationController = (SplitNavigationController) navigationController.navigationController; SplitNavigationController splitNavigationController = (SplitNavigationController) navigationController.navigationController;
Controller controller = splitNavigationController.rightController; if (splitNavigationController.rightController instanceof StyledToolbarNavigationController) {
if (controller instanceof ViewThreadController) { StyledToolbarNavigationController navigationController = (StyledToolbarNavigationController) splitNavigationController.rightController;
((ViewThreadController) controller).loadLoadable(threadLoadable);
if (navigationController.getTop() instanceof ViewThreadController) {
((ViewThreadController) navigationController.getTop()).loadThread(threadLoadable);
}
} else { } else {
StyledToolbarNavigationController navigationController = new StyledToolbarNavigationController(context);
splitNavigationController.setRightController(navigationController);
ViewThreadController viewThreadController = new ViewThreadController(context); ViewThreadController viewThreadController = new ViewThreadController(context);
viewThreadController.setLoadable(threadLoadable); viewThreadController.setLoadable(threadLoadable);
splitNavigationController.setRightController(viewThreadController); navigationController.pushController(viewThreadController, false);
} }
} else { } else {
ViewThreadController viewThreadController = new ViewThreadController(context); ViewThreadController viewThreadController = new ViewThreadController(context);
@ -240,16 +249,6 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte
loadBoards(); loadBoards();
} }
@Override
public void onPinClicked(Pin pin) {
showThread(pin.loadable);
}
@Override
public boolean isPinCurrent(Pin pin) {
return false;
}
public void loadBoard(Board board) { public void loadBoard(Board board) {
Loadable loadable = new Loadable(board.value); Loadable loadable = new Loadable(board.value);
loadable.mode = Loadable.Mode.CATALOG; loadable.mode = Loadable.Mode.CATALOG;

@ -27,8 +27,8 @@ import android.support.v7.widget.RecyclerView;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.Gravity; import android.view.Gravity;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText; import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
@ -36,14 +36,12 @@ import android.widget.TextView;
import org.floens.chan.Chan; 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.controller.ControllerTransition; import org.floens.chan.controller.ControllerLogic;
import org.floens.chan.controller.NavigationController; import org.floens.chan.controller.NavigationController;
import org.floens.chan.core.manager.WatchManager; import org.floens.chan.core.manager.WatchManager;
import org.floens.chan.core.model.Pin; import org.floens.chan.core.model.Pin;
import org.floens.chan.ui.adapter.PinAdapter; import org.floens.chan.ui.adapter.PinAdapter;
import org.floens.chan.ui.helper.SwipeListener; import org.floens.chan.ui.helper.SwipeListener;
import org.floens.chan.ui.theme.ThemeHelper;
import org.floens.chan.ui.toolbar.Toolbar;
import org.floens.chan.utils.AndroidUtils; import org.floens.chan.utils.AndroidUtils;
import java.util.List; import java.util.List;
@ -55,16 +53,19 @@ import static org.floens.chan.utils.AndroidUtils.ROBOTO_MEDIUM;
import static org.floens.chan.utils.AndroidUtils.dp; import static org.floens.chan.utils.AndroidUtils.dp;
import static org.floens.chan.utils.AndroidUtils.fixSnackbarText; import static org.floens.chan.utils.AndroidUtils.fixSnackbarText;
public class DrawerNavigationController extends NavigationController implements PinAdapter.Callback, View.OnClickListener { public class DrawerController extends Controller implements PinAdapter.Callback, View.OnClickListener {
private WatchManager watchManager; private WatchManager watchManager;
protected FrameLayout container;
protected DrawerLayout drawerLayout; protected DrawerLayout drawerLayout;
protected LinearLayout drawer; protected LinearLayout drawer;
protected RecyclerView recyclerView; protected RecyclerView recyclerView;
protected LinearLayout settings; protected LinearLayout settings;
protected PinAdapter pinAdapter; protected PinAdapter pinAdapter;
public DrawerNavigationController(Context context) { private NavigationController childController;
public DrawerController(Context context) {
super(context); super(context);
} }
@ -77,8 +78,7 @@ public class DrawerNavigationController extends NavigationController implements
EventBus.getDefault().register(this); EventBus.getDefault().register(this);
view = inflateRes(R.layout.controller_navigation_drawer); view = inflateRes(R.layout.controller_navigation_drawer);
container = (ViewGroup) view.findViewById(R.id.container); container = (FrameLayout) view.findViewById(R.id.container);
toolbar = (Toolbar) view.findViewById(R.id.toolbar);
drawerLayout = (DrawerLayout) view.findViewById(R.id.drawer_layout); drawerLayout = (DrawerLayout) view.findViewById(R.id.drawer_layout);
drawerLayout.setDrawerShadow(R.drawable.drawer_shadow, Gravity.LEFT); drawerLayout.setDrawerShadow(R.drawable.drawer_shadow, Gravity.LEFT);
drawer = (LinearLayout) view.findViewById(R.id.drawer); drawer = (LinearLayout) view.findViewById(R.id.drawer);
@ -89,8 +89,6 @@ public class DrawerNavigationController extends NavigationController implements
theme().settingsDrawable.apply((ImageView) settings.findViewById(R.id.image)); theme().settingsDrawable.apply((ImageView) settings.findViewById(R.id.image));
((TextView) settings.findViewById(R.id.text)).setTypeface(ROBOTO_MEDIUM); ((TextView) settings.findViewById(R.id.text)).setTypeface(ROBOTO_MEDIUM);
toolbar.setBackgroundColor(ThemeHelper.getInstance().getTheme().primaryColor.color);
pinAdapter = new PinAdapter(this); pinAdapter = new PinAdapter(this);
recyclerView.setAdapter(pinAdapter); recyclerView.setAdapter(pinAdapter);
@ -98,8 +96,6 @@ public class DrawerNavigationController extends NavigationController implements
pinAdapter.onPinsChanged(watchManager.getPins()); pinAdapter.onPinsChanged(watchManager.getPins());
toolbar.setCallback(this);
updateBadge(); updateBadge();
AndroidUtils.waitForMeasure(drawer, new AndroidUtils.OnMeasuredCallback() { AndroidUtils.waitForMeasure(drawer, new AndroidUtils.OnMeasuredCallback() {
@ -114,9 +110,19 @@ public class DrawerNavigationController extends NavigationController implements
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
if (childController != null) {
childController.onDestroy();
}
EventBus.getDefault().unregister(this); EventBus.getDefault().unregister(this);
} }
public void setChildController(NavigationController childController) {
childController.parentController = this;
ControllerLogic.transition(this.childController, childController, true, true, container);
this.childController = childController;
}
@Override @Override
public void onConfigurationChanged(Configuration newConfig) { public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig); super.onConfigurationChanged(newConfig);
@ -132,14 +138,11 @@ public class DrawerNavigationController extends NavigationController implements
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if (v == settings) { if (v == settings) {
pushController(new MainSettingsController(context)); openController(new MainSettingsController(context));
} }
} }
@Override
public void onMenuClicked() { public void onMenuClicked() {
super.onMenuClicked();
drawerLayout.openDrawer(drawer); drawerLayout.openDrawer(drawer);
} }
@ -148,49 +151,31 @@ public class DrawerNavigationController extends NavigationController implements
if (drawerLayout.isDrawerOpen(drawer)) { if (drawerLayout.isDrawerOpen(drawer)) {
drawerLayout.closeDrawer(drawer); drawerLayout.closeDrawer(drawer);
return true; return true;
} else if (childController != null && childController.onBack()) {
return true;
} else { } else {
return super.onBack(); return super.onBack();
} }
} }
@Override
protected void controllerPushed(Controller controller) {
super.controllerPushed(controller);
setDrawerEnabled(controller.navigationItem.hasDrawer);
}
@Override
protected void controllerPopped(Controller controller) {
super.controllerPopped(controller);
setDrawerEnabled(controller.navigationItem.hasDrawer);
}
@Override
public void onControllerTransitionCompleted(ControllerTransition transition) {
super.onControllerTransitionCompleted(transition);
updateHighlighted();
}
public void updateHighlighted() {
pinAdapter.updateHighlighted(recyclerView);
}
@Override @Override
public void onPinClicked(Pin pin) { public void onPinClicked(Pin pin) {
Controller top = getTop(); drawerLayout.closeDrawer(Gravity.LEFT);
if (top instanceof DrawerCallback) {
((DrawerCallback) top).onPinClicked(pin);
drawerLayout.closeDrawer(Gravity.LEFT);
pinAdapter.updateHighlighted(recyclerView);
}
}
public boolean isHighlighted(Pin pin) { if (childController instanceof StyledToolbarNavigationController) {
Controller top = getTop(); if (childController.getTop() instanceof ThreadController) {
if (top instanceof DrawerCallback) { ((ThreadController) childController.getTop()).openPin(pin);
return ((DrawerCallback) top).isPinCurrent(pin); }
} else if (childController instanceof SplitNavigationController) {
SplitNavigationController splitNavigationController = (SplitNavigationController) childController;
if (splitNavigationController.leftController instanceof NavigationController) {
NavigationController navigationController = (NavigationController) splitNavigationController.leftController;
if (navigationController.getTop() instanceof ThreadController) {
ThreadController threadController = (ThreadController) navigationController.getTop();
threadController.openPin(pin);
}
}
} }
return false;
} }
@Override @Override
@ -200,7 +185,7 @@ public class DrawerNavigationController extends NavigationController implements
@Override @Override
public void onHeaderClicked(PinAdapter.HeaderHolder holder) { public void onHeaderClicked(PinAdapter.HeaderHolder holder) {
pushController(new WatchSettingsController(context)); openController(new WatchSettingsController(context));
} }
@Override @Override
@ -251,12 +236,17 @@ public class DrawerNavigationController extends NavigationController implements
@Override @Override
public void openBoardEditor() { public void openBoardEditor() {
pushController(new BoardEditController(context)); openController(new BoardEditController(context));
} }
@Override @Override
public void openHistory() { public void openHistory() {
pushController(new HistoryController(context)); openController(new HistoryController(context));
}
public void setPinHighlighted(Pin pin) {
pinAdapter.setPinHighlighted(pin);
pinAdapter.updateHighlighted(recyclerView);
} }
public void onEvent(WatchManager.PinAddedMessage message) { public void onEvent(WatchManager.PinAddedMessage message) {
@ -275,7 +265,7 @@ public class DrawerNavigationController extends NavigationController implements
updateBadge(); updateBadge();
} }
private void setDrawerEnabled(boolean enabled) { public void setDrawerEnabled(boolean enabled) {
drawerLayout.setDrawerLockMode(enabled ? DrawerLayout.LOCK_MODE_UNLOCKED : DrawerLayout.LOCK_MODE_LOCKED_CLOSED, Gravity.LEFT); drawerLayout.setDrawerLockMode(enabled ? DrawerLayout.LOCK_MODE_UNLOCKED : DrawerLayout.LOCK_MODE_LOCKED_CLOSED, Gravity.LEFT);
} }
@ -292,7 +282,14 @@ public class DrawerNavigationController extends NavigationController implements
} }
} }
toolbar.getArrowMenuDrawable().setBadge(count, color); if (childController instanceof StyledToolbarNavigationController) {
((StyledToolbarNavigationController) childController).toolbar.getArrowMenuDrawable().setBadge(count, color);
} else if (childController instanceof SplitNavigationController) {
SplitNavigationController splitNavigationController = (SplitNavigationController) childController;
if (splitNavigationController.leftController instanceof StyledToolbarNavigationController) {
((StyledToolbarNavigationController) splitNavigationController.leftController).toolbar.getArrowMenuDrawable().setBadge(count, color);
}
}
} }
private boolean setDrawerWidth() { private boolean setDrawerWidth() {
@ -306,36 +303,8 @@ public class DrawerNavigationController extends NavigationController implements
} }
} }
@Override private void openController(Controller controller) {
public String getSearchHint() { childController.pushController(controller);
return context.getString(R.string.search_hint); drawerLayout.closeDrawer(Gravity.LEFT);
}
@Override
public void onSearchVisibilityChanged(boolean visible) {
Controller top = getTop();
if (top instanceof ToolbarSearchCallback) {
((ToolbarSearchCallback) top).onSearchVisibilityChanged(visible);
}
}
@Override
public void onSearchEntered(String entered) {
Controller top = getTop();
if (top instanceof ToolbarSearchCallback) {
((ToolbarSearchCallback) top).onSearchEntered(entered);
}
}
public interface DrawerCallback {
void onPinClicked(Pin pin);
boolean isPinCurrent(Pin pin);
}
public interface ToolbarSearchCallback {
void onSearchVisibilityChanged(boolean visible);
void onSearchEntered(String entered);
} }
} }

@ -50,7 +50,7 @@ import static org.floens.chan.ui.theme.ThemeHelper.theme;
import static org.floens.chan.utils.AndroidUtils.getAttrColor; import static org.floens.chan.utils.AndroidUtils.getAttrColor;
import static org.floens.chan.utils.AndroidUtils.getString; import static org.floens.chan.utils.AndroidUtils.getString;
public class FiltersController extends Controller implements ToolbarMenuItem.ToolbarMenuItemCallback, DrawerNavigationController.ToolbarSearchCallback, View.OnClickListener { public class FiltersController extends Controller implements ToolbarMenuItem.ToolbarMenuItemCallback, ToolbarNavigationController.ToolbarSearchCallback, View.OnClickListener {
private static final int SEARCH_ID = 1; private static final int SEARCH_ID = 1;
private static final int CLEAR_ID = 101; private static final int CLEAR_ID = 101;
@ -127,7 +127,7 @@ public class FiltersController extends Controller implements ToolbarMenuItem.Too
@Override @Override
public void onMenuItemClicked(ToolbarMenuItem item) { public void onMenuItemClicked(ToolbarMenuItem item) {
if ((Integer) item.getId() == SEARCH_ID) { if ((Integer) item.getId() == SEARCH_ID) {
navigationController.showSearch(); ((ToolbarNavigationController) navigationController).showSearch();
} }
} }

@ -50,7 +50,7 @@ import java.util.Locale;
import static org.floens.chan.ui.theme.ThemeHelper.theme; import static org.floens.chan.ui.theme.ThemeHelper.theme;
import static org.floens.chan.utils.AndroidUtils.dp; import static org.floens.chan.utils.AndroidUtils.dp;
public class HistoryController extends Controller implements CompoundButton.OnCheckedChangeListener, ToolbarMenuItem.ToolbarMenuItemCallback, DrawerNavigationController.ToolbarSearchCallback { public class HistoryController extends Controller implements CompoundButton.OnCheckedChangeListener, ToolbarMenuItem.ToolbarMenuItemCallback, ToolbarNavigationController.ToolbarSearchCallback {
private static final int SEARCH_ID = 1; private static final int SEARCH_ID = 1;
private static final int CLEAR_ID = 101; private static final int CLEAR_ID = 101;
@ -94,7 +94,7 @@ public class HistoryController extends Controller implements CompoundButton.OnCh
@Override @Override
public void onMenuItemClicked(ToolbarMenuItem item) { public void onMenuItemClicked(ToolbarMenuItem item) {
if ((Integer) item.getId() == SEARCH_ID) { if ((Integer) item.getId() == SEARCH_ID) {
navigationController.showSearch(); ((ToolbarNavigationController) navigationController).showSearch();
} }
} }

@ -18,17 +18,19 @@
package org.floens.chan.ui.controller; package org.floens.chan.ui.controller;
import android.content.Context; import android.content.Context;
import android.view.ViewGroup;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import org.floens.chan.R; import org.floens.chan.R;
import org.floens.chan.controller.NavigationController; import org.floens.chan.controller.NavigationController;
import org.floens.chan.core.model.Loadable; import org.floens.chan.core.model.Loadable;
import org.floens.chan.core.model.PostImage; import org.floens.chan.core.model.PostImage;
import org.floens.chan.ui.theme.ThemeHelper;
import org.floens.chan.ui.toolbar.Toolbar; import org.floens.chan.ui.toolbar.Toolbar;
import java.util.List; import java.util.List;
public class ImageViewerNavigationController extends NavigationController { public class ImageViewerNavigationController extends ToolbarNavigationController {
private ImageViewerController imageViewerController; private ImageViewerController imageViewerController;
public ImageViewerNavigationController(Context context) { public ImageViewerNavigationController(Context context) {
@ -40,9 +42,8 @@ public class ImageViewerNavigationController extends NavigationController {
super.onCreate(); super.onCreate();
view = inflateRes(R.layout.controller_navigation_image_viewer); view = inflateRes(R.layout.controller_navigation_image_viewer);
container = (ViewGroup) view.findViewById(R.id.container);
toolbar = (Toolbar) view.findViewById(R.id.toolbar); toolbar = (Toolbar) view.findViewById(R.id.toolbar);
container = (FrameLayout) view.findViewById(R.id.container);
toolbar.setCallback(this); toolbar.setCallback(this);
imageViewerController = new ImageViewerController(context, toolbar); imageViewerController = new ImageViewerController(context, toolbar);

@ -0,0 +1,79 @@
/*
* Clover - 4chan browser https://github.com/Floens/Clover/
* Copyright (C) 2014 Floens
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.floens.chan.ui.controller;
import android.content.Context;
import android.view.View;
import android.widget.FrameLayout;
import org.floens.chan.R;
import org.floens.chan.controller.Controller;
import org.floens.chan.controller.ControllerLogic;
import org.floens.chan.controller.NavigationController;
public class PopupController extends Controller implements View.OnClickListener {
private FrameLayout topView;
private FrameLayout container;
private NavigationController childController;
public PopupController(Context context) {
super(context);
}
@Override
public void onCreate() {
super.onCreate();
view = inflateRes(R.layout.layout_controller_popup);
topView = (FrameLayout) view.findViewById(R.id.top_view);
topView.setOnClickListener(this);
container = (FrameLayout) view.findViewById(R.id.container);
}
@Override
public void onDestroy() {
super.onDestroy();
if (childController != null) {
childController.onDestroy();
}
}
public void setChildController(NavigationController childController) {
childController.parentController = this;
ControllerLogic.transition(this.childController, childController, true, true, container);
this.childController = childController;
}
@Override
public boolean onBack() {
return childController != null && childController.onBack();
}
@Override
public void onClick(View v) {
dismiss();
}
public void dismiss() {
if (presentingController instanceof SplitNavigationController) {
((SplitNavigationController) presentingController).popAll();
}
}
}

@ -20,6 +20,7 @@ package org.floens.chan.ui.controller;
import android.content.Context; import android.content.Context;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.LinearLayout; import android.widget.LinearLayout;
@ -40,6 +41,10 @@ public class SplitNavigationController extends NavigationController implements A
private FrameLayout leftControllerView; private FrameLayout leftControllerView;
private FrameLayout rightControllerView; private FrameLayout rightControllerView;
private View dividerView; private View dividerView;
private ViewGroup emptyView;
private PopupController popup;
private StyledToolbarNavigationController popupChild;
public SplitNavigationController(Context context) { public SplitNavigationController(Context context) {
super(context); super(context);
@ -62,9 +67,27 @@ public class SplitNavigationController extends NavigationController implements A
rightControllerView = new FrameLayout(context); rightControllerView = new FrameLayout(context);
wrap.addView(rightControllerView, new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, 1f)); wrap.addView(rightControllerView, new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, 1f));
setRightController(null);
AndroidUtils.waitForMeasure(view, this); AndroidUtils.waitForMeasure(view, this);
} }
@Override
public void onDestroy() {
super.onDestroy();
if (leftController != null) {
leftController.onDestroy();
}
if (rightController != null) {
rightController.onDestroy();
}
}
public void setEmptyView(ViewGroup emptyView) {
this.emptyView = emptyView;
}
public void setLeftController(Controller leftController) { public void setLeftController(Controller leftController) {
leftController.navigationController = this; leftController.navigationController = this;
ControllerLogic.transition(this.leftController, leftController, true, true, leftControllerView); ControllerLogic.transition(this.leftController, leftController, true, true, leftControllerView);
@ -72,57 +95,67 @@ public class SplitNavigationController extends NavigationController implements A
} }
public void setRightController(Controller rightController) { public void setRightController(Controller rightController) {
rightController.navigationController = this; if (rightController != null) {
rightController.navigationController = this;
} else {
rightControllerView.removeAllViews();
}
ControllerLogic.transition(this.rightController, rightController, true, true, rightControllerView); ControllerLogic.transition(this.rightController, rightController, true, true, rightControllerView);
this.rightController = rightController; this.rightController = rightController;
}
@Override
public void transition(Controller from, Controller to, boolean pushing, ControllerTransition controllerTransition) {
if (this.controllerTransition != null) {
throw new IllegalArgumentException("Cannot transition while another transition is in progress.");
}
if (!pushing && controllerList.size() == 0) { if (rightController == null) {
throw new IllegalArgumentException("Cannot pop with no controllers left"); rightControllerView.addView(emptyView);
} }
}
if (controllerTransition != null) { @Override
blockingInput = true; public boolean pushController(Controller to, ControllerTransition controllerTransition) {
this.controllerTransition = controllerTransition; if (popup == null) {
controllerTransition.setCallback(this); popup = new PopupController(context);
ControllerLogic.startTransition(from, to, pushing, leftControllerView, controllerTransition); presentController(popup);
popupChild = new StyledToolbarNavigationController(context);
popup.setChildController(popupChild);
popupChild.pushController(to, false);
} else { } else {
ControllerLogic.transition(from, to, pushing, leftControllerView); popupChild.pushController(to, controllerTransition);
if (!pushing) {
controllerList.remove(from);
}
} }
if (to != null) { return true;
toolbar.setNavigationItem(controllerTransition != null, false, to.navigationItem); }
updateToolbarCollapse(to, controllerTransition != null);
if (pushing) { @Override
controllerPushed(to); public boolean popController(ControllerTransition controllerTransition) {
if (popup != null) {
if (popupChild.getControllerList().size() == 1) {
presentedController.stopPresenting();
popup = null;
popupChild = null;
} else { } else {
controllerPopped(to); popupChild.popController(controllerTransition);
} }
return true;
} else {
return false;
}
}
public void popAll() {
if (popup != null) {
presentedController.stopPresenting();
popup = null;
popupChild = null;
} }
} }
@Override @Override
public boolean onBack() { public boolean onBack() {
if (!super.onBack()) { if (leftController != null && leftController.onBack()) {
if (rightController != null && rightController.onBack()) { return true;
return true; } else if (rightController != null && rightController.onBack()) {
} return true;
if (leftController != null && leftController.onBack()) {
return true;
}
} }
return false; return super.onBack();
} }
@Override @Override

@ -0,0 +1,100 @@
/*
* Clover - 4chan browser https://github.com/Floens/Clover/
* Copyright (C) 2014 Floens
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.floens.chan.ui.controller;
import android.content.Context;
import android.view.ViewGroup;
import org.floens.chan.R;
import org.floens.chan.controller.Controller;
import org.floens.chan.controller.ControllerTransition;
import org.floens.chan.ui.theme.ThemeHelper;
import org.floens.chan.ui.toolbar.Toolbar;
public class StyledToolbarNavigationController extends ToolbarNavigationController {
public StyledToolbarNavigationController(Context context) {
super(context);
}
@Override
public void onCreate() {
super.onCreate();
view = inflateRes(R.layout.controller_navigation_toolbar);
container = (ViewGroup) view.findViewById(R.id.container);
toolbar = (Toolbar) view.findViewById(R.id.toolbar);
toolbar.setBackgroundColor(ThemeHelper.getInstance().getTheme().primaryColor.color);
toolbar.setCallback(this);
}
@Override
public void transition(Controller from, Controller to, boolean pushing, ControllerTransition controllerTransition) {
super.transition(from, to, pushing, controllerTransition);
if (to != null) {
DrawerController drawerController = getDrawerController();
if (drawerController != null) {
drawerController.setDrawerEnabled(to.navigationItem.hasDrawer);
}
}
}
@Override
public boolean onBack() {
if (super.onBack()) {
return true;
} else if (parentController instanceof PopupController && controllerList.size() == 1) {
((PopupController) parentController).dismiss();
return true;
} else if (navigationController instanceof SplitNavigationController && controllerList.size() == 1) {
SplitNavigationController splitNavigationController = (SplitNavigationController) navigationController;
if (splitNavigationController.rightController == this) {
splitNavigationController.setRightController(null);
return true;
} else {
return false;
}
} else {
return false;
}
}
@Override
public void onMenuOrBackClicked(boolean isArrow) {
if (isArrow) {
onBack();
} else {
DrawerController drawerController = getDrawerController();
if (drawerController != null) {
drawerController.onMenuClicked();
}
}
}
private DrawerController getDrawerController() {
if (parentController instanceof DrawerController) {
return (DrawerController) parentController;
} else if (navigationController instanceof SplitNavigationController) {
SplitNavigationController splitNavigationController = (SplitNavigationController) navigationController;
if (splitNavigationController.parentController instanceof DrawerController) {
return (DrawerController) splitNavigationController.parentController;
}
}
return null;
}
}

@ -30,6 +30,7 @@ import org.floens.chan.R;
import org.floens.chan.chan.ChanUrls; import org.floens.chan.chan.ChanUrls;
import org.floens.chan.controller.Controller; import org.floens.chan.controller.Controller;
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.PostImage; import org.floens.chan.core.model.PostImage;
import org.floens.chan.ui.helper.RefreshUIMessage; import org.floens.chan.ui.helper.RefreshUIMessage;
import org.floens.chan.ui.layout.ThreadLayout; import org.floens.chan.ui.layout.ThreadLayout;
@ -42,8 +43,9 @@ import java.util.List;
import de.greenrobot.event.EventBus; import de.greenrobot.event.EventBus;
import static org.floens.chan.utils.AndroidUtils.dp; import static org.floens.chan.utils.AndroidUtils.dp;
import static org.floens.chan.utils.AndroidUtils.isTablet;
public abstract class ThreadController extends Controller implements ThreadLayout.ThreadLayoutCallback, ImageViewerController.PreviewCallback, DrawerNavigationController.DrawerCallback, SwipeRefreshLayout.OnRefreshListener, DrawerNavigationController.ToolbarSearchCallback, NfcAdapter.CreateNdefMessageCallback { public abstract class ThreadController extends Controller implements ThreadLayout.ThreadLayoutCallback, ImageViewerController.PreviewCallback, SwipeRefreshLayout.OnRefreshListener, ToolbarNavigationController.ToolbarSearchCallback, NfcAdapter.CreateNdefMessageCallback {
private static final String TAG = "ThreadController"; private static final String TAG = "ThreadController";
protected ThreadLayout threadLayout; protected ThreadLayout threadLayout;
@ -59,7 +61,7 @@ public abstract class ThreadController extends Controller implements ThreadLayou
EventBus.getDefault().register(this); EventBus.getDefault().register(this);
navigationItem.collapseToolbar = true; navigationItem.collapseToolbar = !isTablet(context);
threadLayout = (ThreadLayout) LayoutInflater.from(context).inflate(R.layout.layout_thread, null); threadLayout = (ThreadLayout) LayoutInflater.from(context).inflate(R.layout.layout_thread, null);
threadLayout.setCallback(this); threadLayout.setCallback(this);
@ -73,8 +75,12 @@ public abstract class ThreadController extends Controller implements ThreadLayou
swipeRefreshLayout.addView(threadLayout); swipeRefreshLayout.addView(threadLayout);
swipeRefreshLayout.setOnRefreshListener(this); swipeRefreshLayout.setOnRefreshListener(this);
int toolbarHeight = navigationController.getToolbar() == null ? 0 : navigationController.getToolbar().getToolbarHeight(); ToolbarNavigationController toolbarNavigationController = (ToolbarNavigationController) navigationController;
swipeRefreshLayout.setProgressViewOffset(false, toolbarHeight - dp(40), toolbarHeight + dp(64 - 40));
if (collapseToolbar()) {
int toolbarHeight = getToolbar().getToolbarHeight();
swipeRefreshLayout.setProgressViewOffset(false, toolbarHeight - dp(40), toolbarHeight + dp(64 - 40));
}
view = swipeRefreshLayout; view = swipeRefreshLayout;
} }
@ -88,6 +94,8 @@ public abstract class ThreadController extends Controller implements ThreadLayou
EventBus.getDefault().unregister(this); EventBus.getDefault().unregister(this);
} }
public abstract void openPin(Pin pin);
/* /*
* Used to save instance state * Used to save instance state
*/ */
@ -186,7 +194,12 @@ public abstract class ThreadController extends Controller implements ThreadLayou
@Override @Override
public Toolbar getToolbar() { public Toolbar getToolbar() {
return navigationController.getToolbar(); return ((ToolbarNavigationController) navigationController).getToolbar();
}
@Override
public boolean collapseToolbar() {
return navigationItem.collapseToolbar;
} }
@Override @Override

@ -0,0 +1,103 @@
/*
* Clover - 4chan browser https://github.com/Floens/Clover/
* Copyright (C) 2014 Floens
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.floens.chan.ui.controller;
import android.content.Context;
import android.widget.FrameLayout;
import org.floens.chan.R;
import org.floens.chan.controller.Controller;
import org.floens.chan.controller.ControllerTransition;
import org.floens.chan.controller.NavigationController;
import org.floens.chan.ui.toolbar.Toolbar;
public abstract class ToolbarNavigationController extends NavigationController implements Toolbar.ToolbarCallback {
protected Toolbar toolbar;
public ToolbarNavigationController(Context context) {
super(context);
}
public Toolbar getToolbar() {
return toolbar;
}
public void showSearch() {
toolbar.openSearch();
}
@Override
public void transition(Controller from, Controller to, boolean pushing, ControllerTransition controllerTransition) {
super.transition(from, to, pushing, controllerTransition);
if (to != null) {
toolbar.setNavigationItem(controllerTransition != null, pushing, to.navigationItem);
updateToolbarCollapse(to, controllerTransition != null);
}
}
@Override
public void onMenuOrBackClicked(boolean isArrow) {
}
@Override
public boolean onBack() {
return toolbar.closeSearch() || super.onBack();
}
@Override
public String getSearchHint() {
return context.getString(R.string.search_hint);
}
@Override
public void onSearchVisibilityChanged(boolean visible) {
Controller top = getTop();
if (top instanceof ToolbarSearchCallback) {
((ToolbarSearchCallback) top).onSearchVisibilityChanged(visible);
}
}
@Override
public void onSearchEntered(String entered) {
Controller top = getTop();
if (top instanceof ToolbarSearchCallback) {
((ToolbarSearchCallback) top).onSearchEntered(entered);
}
}
protected void updateToolbarCollapse(Controller controller, boolean animate) {
if (!controller.navigationItem.collapseToolbar) {
FrameLayout.LayoutParams toViewParams = (FrameLayout.LayoutParams) controller.view.getLayoutParams();
toViewParams.topMargin = toolbar.getToolbarHeight();
controller.view.setLayoutParams(toViewParams);
}
toolbar.processScrollCollapse(Toolbar.TOOLBAR_COLLAPSE_SHOW, animate);
}
public interface ToolbarSearchCallback {
void onSearchVisibilityChanged(boolean visible);
void onSearchEntered(String entered);
}
public interface ToolbarMenuCallback {
void onMenuOrBackClicked(boolean isArrow);
}
}

@ -79,20 +79,18 @@ public class ViewThreadController extends ThreadController implements ThreadLayo
new FloatingMenuItem(DOWN_ID, context.getString(R.string.action_down)) new FloatingMenuItem(DOWN_ID, context.getString(R.string.action_down))
)); ));
loadLoadable(loadable); loadThread(loadable);
} }
@Override @Override
public void onShow() { public void onDestroy() {
super.onShow(); super.onDestroy();
if (navigationController instanceof DrawerNavigationController) { updateDrawerHighlighting(null);
((DrawerNavigationController) navigationController).updateHighlighted();
}
} }
@Override @Override
public void onDestroy() { public void openPin(Pin pin) {
super.onDestroy(); loadThread(pin.loadable);
} }
public void onEvent(WatchManager.PinAddedMessage message) { public void onEvent(WatchManager.PinAddedMessage message) {
@ -114,10 +112,7 @@ public class ViewThreadController extends ThreadController implements ThreadLayo
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(final DialogInterface dialog, final int which) { public void onClick(final DialogInterface dialog, final int which) {
loadLoadable(threadLoadable); loadThread(threadLoadable);
if (navigationController instanceof DrawerNavigationController) {
((DrawerNavigationController) navigationController).updateHighlighted();
}
} }
}) })
.setTitle(R.string.open_thread_confirmation) .setTitle(R.string.open_thread_confirmation)
@ -125,17 +120,7 @@ public class ViewThreadController extends ThreadController implements ThreadLayo
.show(); .show();
} }
@Override public void loadThread(Loadable loadable) {
public void onPinClicked(Pin pin) {
loadLoadable(pin.loadable);
}
@Override
public boolean isPinCurrent(Pin pin) {
return pin.loadable.equals(threadLayout.getPresenter().getLoadable());
}
public void loadLoadable(Loadable loadable) {
if (!loadable.equals(threadLayout.getPresenter().getLoadable())) { if (!loadable.equals(threadLayout.getPresenter().getLoadable())) {
threadLayout.getPresenter().bindLoadable(loadable); threadLayout.getPresenter().bindLoadable(loadable);
this.loadable = threadLayout.getPresenter().getLoadable(); this.loadable = threadLayout.getPresenter().getLoadable();
@ -143,6 +128,8 @@ public class ViewThreadController extends ThreadController implements ThreadLayo
navigationItem.title = loadable.title; navigationItem.title = loadable.title;
navigationItem.updateTitle(); navigationItem.updateTitle();
setPinIconState(threadLayout.getPresenter().isPinned()); setPinIconState(threadLayout.getPresenter().isPinned());
updateDrawerHighlighting(loadable);
} }
} }
@ -172,7 +159,7 @@ public class ViewThreadController extends ThreadController implements ThreadLayo
threadLayout.getPresenter().requestData(); threadLayout.getPresenter().requestData();
break; break;
case SEARCH_ID: case SEARCH_ID:
navigationController.showSearch(); ((ToolbarNavigationController) navigationController).showSearch();
break; break;
case SHARE_ID: case SHARE_ID:
case OPEN_BROWSER_ID: case OPEN_BROWSER_ID:
@ -194,6 +181,19 @@ public class ViewThreadController extends ThreadController implements ThreadLayo
} }
} }
private void updateDrawerHighlighting(Loadable loadable) {
WatchManager wm = Chan.getWatchManager();
Pin pin = loadable == null ? null : wm.findPinByLoadable(loadable);
if (navigationController.parentController instanceof DrawerController) {
((DrawerController) navigationController.parentController).setPinHighlighted(pin);
} else if (navigationController.navigationController instanceof SplitNavigationController) {
if (((SplitNavigationController) navigationController.navigationController).parentController instanceof DrawerController) {
((DrawerController) ((SplitNavigationController) navigationController.navigationController).parentController).setPinHighlighted(pin);
}
}
}
private void setPinIconState() { private void setPinIconState() {
WatchManager wm = Chan.getWatchManager(); WatchManager wm = Chan.getWatchManager();
setPinIconState(wm.findPinByLoadable(loadable) != null); setPinIconState(wm.findPinByLoadable(loadable) != null);

@ -0,0 +1,49 @@
/*
* Clover - 4chan browser https://github.com/Floens/Clover/
* Copyright (C) 2014 Floens
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.floens.chan.ui.layout;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.LinearLayout;
import static org.floens.chan.utils.AndroidUtils.dp;
public class PostRepliesContainer extends LinearLayout {
public PostRepliesContainer(Context context) {
super(context);
}
public PostRepliesContainer(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PostRepliesContainer(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int maxWidth = dp(600);
if (MeasureSpec.getSize(widthMeasureSpec) > maxWidth) {
widthMeasureSpec = MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.getMode(widthMeasureSpec));
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}

@ -183,6 +183,11 @@ public class ThreadLayout extends CoordinatorLayout implements ThreadPresenter.T
return callback.getToolbar(); return callback.getToolbar();
} }
@Override
public boolean collapseToolbar() {
return callback.collapseToolbar();
}
@Override @Override
public void showPosts(ChanThread thread, PostsFilter filter) { public void showPosts(ChanThread thread, PostsFilter filter) {
threadListLayout.showPosts(thread, filter, visible != Visible.THREAD); threadListLayout.showPosts(thread, filter, visible != Visible.THREAD);
@ -496,5 +501,7 @@ public class ThreadLayout extends CoordinatorLayout implements ThreadPresenter.T
void hideSwipeRefreshLayout(); void hideSwipeRefreshLayout();
Toolbar getToolbar(); Toolbar getToolbar();
boolean collapseToolbar();
} }
} }

@ -66,7 +66,6 @@ public class ThreadListLayout extends LinearLayout implements ReplyLayout.ReplyL
private PostCellInterface.PostViewMode postViewMode; private PostCellInterface.PostViewMode postViewMode;
private int spanCount = 2; private int spanCount = 2;
private int background; private int background;
private Toolbar toolbar;
private boolean searchOpen; private boolean searchOpen;
public ThreadListLayout(Context context, AttributeSet attrs) { public ThreadListLayout(Context context, AttributeSet attrs) {
@ -100,19 +99,17 @@ public class ThreadListLayout extends LinearLayout implements ReplyLayout.ReplyL
// onScrolled can be called after cleanup() // onScrolled can be called after cleanup()
if (showingThread != null) { if (showingThread != null) {
int index = Math.max(0, getTopAdapterPosition()); int index = Math.max(0, getTopAdapterPosition());
int top = recyclerView.getLayoutManager().getChildAt(0).getTop(); // int top = recyclerView.getLayoutManager().getChildAt(0).getTop();
showingThread.loadable.listViewIndex = index; showingThread.loadable.listViewIndex = index;
// showingThread.loadable.listViewTop = top; // showingThread.loadable.listViewTop = top;
} }
} }
}); });
toolbar = threadListLayoutCallback.getToolbar();
attachToolbarScroll(true); attachToolbarScroll(true);
int toolbarHeight = toolbar == null ? 0 : toolbar.getToolbarHeight(); reply.setPadding(0, topSpacing(), 0, 0);
reply.setPadding(0, toolbarHeight, 0, 0); searchStatus.setPadding(searchStatus.getPaddingLeft(), searchStatus.getPaddingTop() + topSpacing(),
searchStatus.setPadding(searchStatus.getPaddingLeft(), searchStatus.getPaddingTop() + toolbarHeight,
searchStatus.getPaddingRight(), searchStatus.getPaddingBottom()); searchStatus.getPaddingRight(), searchStatus.getPaddingBottom());
} }
@ -139,11 +136,10 @@ public class ThreadListLayout extends LinearLayout implements ReplyLayout.ReplyL
layoutManager = null; layoutManager = null;
int toolbarHeight = toolbar == null ? 0 : toolbar.getToolbarHeight();
switch (postViewMode) { switch (postViewMode) {
case LIST: case LIST:
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext()); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
recyclerView.setPadding(0, toolbarHeight, 0, 0); recyclerView.setPadding(0, topSpacing(), 0, 0);
recyclerView.setLayoutManager(linearLayoutManager); recyclerView.setLayoutManager(linearLayoutManager);
layoutManager = linearLayoutManager; layoutManager = linearLayoutManager;
@ -156,7 +152,7 @@ public class ThreadListLayout extends LinearLayout implements ReplyLayout.ReplyL
case CARD: case CARD:
GridLayoutManager gridLayoutManager = new GridLayoutManager(null, spanCount, GridLayoutManager.VERTICAL, false); GridLayoutManager gridLayoutManager = new GridLayoutManager(null, spanCount, GridLayoutManager.VERTICAL, false);
// The cards have a 4dp padding, this way there is always 8dp between the edges // The cards have a 4dp padding, this way there is always 8dp between the edges
recyclerView.setPadding(dp(4), dp(4) + toolbarHeight, dp(4), dp(4)); recyclerView.setPadding(dp(4), dp(4) + topSpacing(), dp(4), dp(4));
recyclerView.setLayoutManager(gridLayoutManager); recyclerView.setLayoutManager(gridLayoutManager);
layoutManager = gridLayoutManager; layoutManager = gridLayoutManager;
@ -276,18 +272,17 @@ public class ThreadListLayout extends LinearLayout implements ReplyLayout.ReplyL
return true; return true;
} }
int toolbarHeight = toolbar == null ? 0 : toolbar.getToolbarHeight();
switch (postViewMode) { switch (postViewMode) {
case LIST: case LIST:
if (getTopAdapterPosition() == 0) { if (getTopAdapterPosition() == 0) {
View top = layoutManager.findViewByPosition(0); View top = layoutManager.findViewByPosition(0);
return top.getTop() != toolbarHeight; return top.getTop() != topSpacing();
} }
break; break;
case CARD: case CARD:
if (getTopAdapterPosition() == 0) { if (getTopAdapterPosition() == 0) {
View top = layoutManager.findViewByPosition(0); View top = layoutManager.findViewByPosition(0);
return top.getTop() != dp(8) + toolbarHeight; // 4dp for the cards, 4dp for this layout return top.getTop() != dp(8) + topSpacing(); // 4dp for the cards, 4dp for this layout
} }
break; break;
} }
@ -400,7 +395,8 @@ public class ThreadListLayout extends LinearLayout implements ReplyLayout.ReplyL
} }
private void attachToolbarScroll(boolean attach) { private void attachToolbarScroll(boolean attach) {
if (toolbar != null) { Toolbar toolbar = threadListLayoutCallback.getToolbar();
if (toolbar != null && threadListLayoutCallback.collapseToolbar()) {
if (attach) { if (attach) {
toolbar.attachRecyclerViewScrollStateListener(recyclerView); toolbar.attachRecyclerViewScrollStateListener(recyclerView);
} else { } else {
@ -410,6 +406,15 @@ public class ThreadListLayout extends LinearLayout implements ReplyLayout.ReplyL
} }
} }
private int topSpacing() {
Toolbar toolbar = threadListLayoutCallback.getToolbar();
if (toolbar != null && threadListLayoutCallback.collapseToolbar()) {
return toolbar.getToolbarHeight();
} else {
return 0;
}
}
private int getTopAdapterPosition() { private int getTopAdapterPosition() {
switch (postViewMode) { switch (postViewMode) {
case LIST: case LIST:
@ -440,5 +445,7 @@ public class ThreadListLayout extends LinearLayout implements ReplyLayout.ReplyL
void replyLayoutOpen(boolean open); void replyLayoutOpen(boolean open);
Toolbar getToolbar(); Toolbar getToolbar();
boolean collapseToolbar();
} }
} }

@ -141,6 +141,10 @@ public class Toolbar extends LinearLayout implements View.OnClickListener, LoadV
setNavigationItem(false, false, navigationItem); setNavigationItem(false, false, navigationItem);
} }
public NavigationItem getNavigationItem() {
return navigationItem;
}
public boolean openSearch() { public boolean openSearch() {
return openSearchInternal(); return openSearchInternal();
} }
@ -223,7 +227,7 @@ public class Toolbar extends LinearLayout implements View.OnClickListener, LoadV
} }
private boolean openSearchInternal() { private boolean openSearchInternal() {
if (!navigationItem.search) { if (navigationItem != null && !navigationItem.search) {
navigationItem.search = true; navigationItem.search = true;
openKeyboardAfterSearchViewCreated = true; openKeyboardAfterSearchViewCreated = true;
setNavigationItem(true, true, navigationItem); setNavigationItem(true, true, navigationItem);
@ -236,7 +240,7 @@ public class Toolbar extends LinearLayout implements View.OnClickListener, LoadV
} }
private boolean closeSearchInternal() { private boolean closeSearchInternal() {
if (navigationItem.search) { if (navigationItem != null && navigationItem.search) {
navigationItem.search = false; navigationItem.search = false;
navigationItem.searchText = null; navigationItem.searchText = null;
setNavigationItemInternal(true, false, navigationItem); setNavigationItemInternal(true, false, navigationItem);

@ -22,23 +22,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
android:layout_height="match_parent"> android:layout_height="match_parent">
<FrameLayout <FrameLayout
android:id="@+id/root_layout" android:id="@+id/container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent" />
android:background="?backcolor">
<org.floens.chan.ui.toolbar.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height"
tools:ignore="UnusedAttribute" />
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<LinearLayout <LinearLayout
android:id="@+id/drawer" android:id="@+id/drawer"

@ -0,0 +1,33 @@
<?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/>.
-->
<org.floens.chan.ui.view.TouchBlockingFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?backcolor">
<org.floens.chan.ui.toolbar.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height" />
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</org.floens.chan.ui.view.TouchBlockingFrameLayout>

@ -0,0 +1,32 @@
<?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/>.
-->
<FrameLayout
android:id="@+id/top_view"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#88000000">
<FrameLayout
android:id="@+id/container"
android:layout_width="600dp"
android:layout_height="600dp"
android:layout_gravity="center"
android:background="@drawable/dialog_full_light"/>
</FrameLayout>

@ -21,7 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<LinearLayout <org.floens.chan.ui.layout.PostRepliesContainer
android:id="@+id/container" android:id="@+id/container"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -86,6 +86,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent" />
</LinearLayout> </org.floens.chan.ui.layout.PostRepliesContainer>
</FrameLayout> </FrameLayout>

@ -21,7 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<LinearLayout <org.floens.chan.ui.layout.PostRepliesContainer
android:id="@+id/container" android:id="@+id/container"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -87,6 +87,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</FrameLayout> </FrameLayout>
</LinearLayout> </LinearLayout>
</LinearLayout> </org.floens.chan.ui.layout.PostRepliesContainer>
</FrameLayout> </FrameLayout>

@ -0,0 +1,32 @@
<?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/>.
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?backcolor">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/thread_empty_select"
android:textColor="?text_color_secondary"
android:textSize="16sp"/>
</FrameLayout>

@ -113,6 +113,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<string name="thread_closed">Closed</string> <string name="thread_closed">Closed</string>
<string name="thread_new_posts">%1$d new %2$s</string> <string name="thread_new_posts">%1$d new %2$s</string>
<string name="thread_new_posts_goto">View</string> <string name="thread_new_posts_goto">View</string>
<string name="thread_empty_select">Please select a thread</string>
<string name="board_edit">Board editor</string> <string name="board_edit">Board editor</string>
<string name="board_edit_header">Add, remove and reorder your boards here.\nThe topmost board will be loaded automatically.</string> <string name="board_edit_header">Add, remove and reorder your boards here.\nThe topmost board will be loaded automatically.</string>

@ -81,6 +81,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<item name="text_color_hint">#4cffffff</item> <item name="text_color_hint">#4cffffff</item>
<item name="divider_color">#1effffff</item> <item name="divider_color">#1effffff</item>
<item name="divider_split_color">#ff3d3d3d</item>
<item name="post_saved_reply_color">#ff5C5C5C</item> <item name="post_saved_reply_color">#ff5C5C5C</item>
<item name="post_highlighted_color">#ff444444</item> <item name="post_highlighted_color">#ff444444</item>

Loading…
Cancel
Save