Add the sliding pane layout as a new layout option

Closes #147
multisite
Floens 9 years ago
parent f9fe6026d1
commit ef9b1c3392
  1. 3
      Clover/app/proguard.cfg
  2. 11
      Clover/app/src/main/java/org/floens/chan/controller/Controller.java
  3. 1
      Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java
  4. 85
      Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java
  5. 2
      Clover/app/src/main/java/org/floens/chan/ui/controller/AlbumDownloadController.java
  6. 16
      Clover/app/src/main/java/org/floens/chan/ui/controller/AlbumViewController.java
  7. 47
      Clover/app/src/main/java/org/floens/chan/ui/controller/BrowseController.java
  8. 49
      Clover/app/src/main/java/org/floens/chan/ui/controller/DoubleNavigationController.java
  9. 44
      Clover/app/src/main/java/org/floens/chan/ui/controller/DrawerController.java
  10. 4
      Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerController.java
  11. 3
      Clover/app/src/main/java/org/floens/chan/ui/controller/MainSettingsController.java
  12. 2
      Clover/app/src/main/java/org/floens/chan/ui/controller/PopupController.java
  13. 28
      Clover/app/src/main/java/org/floens/chan/ui/controller/SplitNavigationController.java
  14. 13
      Clover/app/src/main/java/org/floens/chan/ui/controller/StyledToolbarNavigationController.java
  15. 28
      Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java
  16. 281
      Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadSlideController.java
  17. 2
      Clover/app/src/main/java/org/floens/chan/ui/controller/ToolbarNavigationController.java
  18. 28
      Clover/app/src/main/java/org/floens/chan/ui/controller/ViewThreadController.java
  19. 7
      Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadLayout.java
  20. 4
      Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadListLayout.java
  21. 88
      Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadSlidingPaneLayout.java
  22. 11
      Clover/app/src/main/java/org/floens/chan/ui/toolbar/NavigationItem.java
  23. 56
      Clover/app/src/main/java/org/floens/chan/ui/toolbar/Toolbar.java
  24. 6
      Clover/app/src/main/java/org/floens/chan/utils/AndroidUtils.java
  25. BIN
      Clover/app/src/main/res/drawable-hdpi/panel_shadow.9.png
  26. BIN
      Clover/app/src/main/res/drawable-mdpi/panel_shadow.9.png
  27. BIN
      Clover/app/src/main/res/drawable-xhdpi/panel_shadow.9.png
  28. BIN
      Clover/app/src/main/res/drawable-xxhdpi/panel_shadow.9.png
  29. 34
      Clover/app/src/main/res/layout/controller_thread_slide.xml
  30. 1
      Clover/app/src/main/res/values/strings.xml

@ -103,5 +103,6 @@
#-keep public class * extends android.support.design.** #-keep public class * extends android.support.design.**
# Some reflection is used on RecyclerView # Some reflection is used on RecyclerView and SlidingPaneLayout
-keep public class android.support.v7.widget.RecyclerView -keep public class android.support.v7.widget.RecyclerView
-keep public class android.support.v4.widget.SlidingPaneLayout

@ -27,7 +27,7 @@ import android.view.ViewGroup;
import org.floens.chan.controller.transition.FadeInTransition; import org.floens.chan.controller.transition.FadeInTransition;
import org.floens.chan.controller.transition.FadeOutTransition; import org.floens.chan.controller.transition.FadeOutTransition;
import org.floens.chan.ui.activity.StartActivity; import org.floens.chan.ui.activity.StartActivity;
import org.floens.chan.ui.controller.SplitNavigationController; import org.floens.chan.ui.controller.DoubleNavigationController;
import org.floens.chan.ui.toolbar.NavigationItem; import org.floens.chan.ui.toolbar.NavigationItem;
import org.floens.chan.utils.AndroidUtils; import org.floens.chan.utils.AndroidUtils;
import org.floens.chan.utils.Logger; import org.floens.chan.utils.Logger;
@ -51,7 +51,7 @@ public abstract class Controller {
public Controller previousSiblingController; public Controller previousSiblingController;
public NavigationController navigationController; public NavigationController navigationController;
public SplitNavigationController splitNavigationController; public DoubleNavigationController doubleNavigationController;
/** /**
* Controller that this controller is presented by. * Controller that this controller is presented by.
@ -127,7 +127,12 @@ public abstract class Controller {
public void addChildController(Controller controller) { public void addChildController(Controller controller) {
childControllers.add(controller); childControllers.add(controller);
controller.parentController = this; controller.parentController = this;
controller.splitNavigationController = splitNavigationController; if (doubleNavigationController != null) {
controller.doubleNavigationController = doubleNavigationController;
}
if (navigationController != null) {
controller.navigationController = navigationController;
}
controller.onCreate(); controller.onCreate();
} }

@ -71,6 +71,7 @@ public class ChanSettings {
public enum LayoutMode implements OptionSettingItem { public enum LayoutMode implements OptionSettingItem {
AUTO("auto"), AUTO("auto"),
PHONE("phone"), PHONE("phone"),
SLIDE("slide"),
SPLIT("split"); SPLIT("split");
String name; String name;

@ -44,9 +44,11 @@ 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.DoubleNavigationController;
import org.floens.chan.ui.controller.DrawerController; 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.StyledToolbarNavigationController;
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.PreviousVersionHandler; import org.floens.chan.ui.helper.PreviousVersionHandler;
@ -95,35 +97,7 @@ public class StartActivity extends AppCompatActivity implements NfcAdapter.Creat
drawerController.onCreate(); drawerController.onCreate();
drawerController.onShow(); drawerController.onShow();
StyledToolbarNavigationController toolbarNavigationController = new StyledToolbarNavigationController(this); setupLayout();
ChanSettings.LayoutMode layoutMode = ChanSettings.layoutMode.get();
if (layoutMode == ChanSettings.LayoutMode.AUTO) {
if (AndroidUtils.isTablet(this)) {
layoutMode = ChanSettings.LayoutMode.SPLIT;
} else {
layoutMode = ChanSettings.LayoutMode.PHONE;
}
}
switch (layoutMode) {
case SPLIT:
SplitNavigationController splitNavigationController = new SplitNavigationController(this);
splitNavigationController.setEmptyView((ViewGroup) LayoutInflater.from(this).inflate(R.layout.layout_split_empty, null));
drawerController.setChildController(splitNavigationController);
splitNavigationController.setLeftController(toolbarNavigationController);
mainNavigationController = toolbarNavigationController;
break;
case PHONE:
drawerController.setChildController(toolbarNavigationController);
mainNavigationController = toolbarNavigationController;
break;
}
browseController = new BrowseController(this);
mainNavigationController.pushController(browseController, false);
setContentView(drawerController.view); setContentView(drawerController.view);
addController(drawerController); addController(drawerController);
@ -190,6 +164,45 @@ public class StartActivity extends AppCompatActivity implements NfcAdapter.Creat
previousVersionHandler.run(this); previousVersionHandler.run(this);
} }
private void setupLayout() {
mainNavigationController = new StyledToolbarNavigationController(this);
ChanSettings.LayoutMode layoutMode = ChanSettings.layoutMode.get();
if (layoutMode == ChanSettings.LayoutMode.AUTO) {
if (AndroidUtils.isTablet(this)) {
layoutMode = ChanSettings.LayoutMode.SPLIT;
} else {
layoutMode = ChanSettings.LayoutMode.PHONE;
}
}
switch (layoutMode) {
case SPLIT:
SplitNavigationController split = new SplitNavigationController(this);
split.setEmptyView((ViewGroup) LayoutInflater.from(this).inflate(R.layout.layout_split_empty, null));
drawerController.setChildController(split);
split.setLeftController(mainNavigationController);
break;
case PHONE:
case SLIDE:
drawerController.setChildController(mainNavigationController);
break;
}
browseController = new BrowseController(this);
if (layoutMode == ChanSettings.LayoutMode.SLIDE) {
ThreadSlideController slideController = new ThreadSlideController(this);
slideController.setEmptyView((ViewGroup) LayoutInflater.from(this).inflate(R.layout.layout_split_empty, null));
mainNavigationController.pushController(slideController, false);
slideController.setLeftController(browseController);
} else {
mainNavigationController.pushController(browseController, false);
}
}
public void restart() { public void restart() {
Intent intent = getIntent(); Intent intent = getIntent();
finish(); finish();
@ -237,9 +250,9 @@ public class StartActivity extends AppCompatActivity implements NfcAdapter.Creat
Loadable thread = null; Loadable thread = null;
if (drawerController.childControllers.get(0) instanceof SplitNavigationController) { if (drawerController.childControllers.get(0) instanceof SplitNavigationController) {
SplitNavigationController splitNavigationController = (SplitNavigationController) drawerController.childControllers.get(0); SplitNavigationController doubleNav = (SplitNavigationController) drawerController.childControllers.get(0);
if (splitNavigationController.rightController instanceof NavigationController) { if (doubleNav.getRightController() instanceof NavigationController) {
NavigationController rightNavigationController = (NavigationController) splitNavigationController.rightController; NavigationController rightNavigationController = (NavigationController) doubleNav.getRightController();
for (Controller controller : rightNavigationController.childControllers) { for (Controller controller : rightNavigationController.childControllers) {
if (controller instanceof ViewThreadController) { if (controller instanceof ViewThreadController) {
thread = ((ViewThreadController) controller).getLoadable(); thread = ((ViewThreadController) controller).getLoadable();
@ -254,6 +267,12 @@ public class StartActivity extends AppCompatActivity implements NfcAdapter.Creat
if (controller instanceof ViewThreadController) { if (controller instanceof ViewThreadController) {
thread = ((ViewThreadController) controller).getLoadable(); thread = ((ViewThreadController) controller).getLoadable();
break; break;
} else if (controller instanceof ThreadSlideController) {
ThreadSlideController slideNav = (ThreadSlideController) controller;
if (slideNav.getRightController() instanceof ViewThreadController) {
thread = ((ViewThreadController) slideNav.getRightController()).getLoadable();
break;
}
} }
} }
} }
@ -270,7 +289,7 @@ public class StartActivity extends AppCompatActivity implements NfcAdapter.Creat
@Override @Override
public NdefMessage createNdefMessage(NfcEvent event) { public NdefMessage createNdefMessage(NfcEvent event) {
Controller threadController = null; Controller threadController = null;
if (drawerController.childControllers.get(0) instanceof SplitNavigationController) { if (drawerController.childControllers.get(0) instanceof DoubleNavigationController) {
SplitNavigationController splitNavigationController = (SplitNavigationController) drawerController.childControllers.get(0); SplitNavigationController splitNavigationController = (SplitNavigationController) drawerController.childControllers.get(0);
if (splitNavigationController.rightController instanceof NavigationController) { if (splitNavigationController.rightController instanceof NavigationController) {
NavigationController rightNavigationController = (NavigationController) splitNavigationController.rightController; NavigationController rightNavigationController = (NavigationController) splitNavigationController.rightController;

@ -168,7 +168,7 @@ public class AlbumDownloadController extends Controller implements ToolbarMenuIt
private void updateTitle() { private void updateTitle() {
navigationItem.title = context.getString(R.string.album_download_screen, getCheckCount(), items.size()); navigationItem.title = context.getString(R.string.album_download_screen, getCheckCount(), items.size());
navigationItem.updateTitle(); ((ToolbarNavigationController) navigationController).toolbar.updateTitle(navigationItem);
} }
private void updateAllChecked() { private void updateAllChecked() {

@ -135,11 +135,21 @@ public class AlbumViewController extends Controller implements ImageViewerContro
@Override @Override
public ImageViewerController.ImageViewerCallback goToPost(PostImage postImage) { public ImageViewerController.ImageViewerCallback goToPost(PostImage postImage) {
ThreadController threadController = null;
if (previousSiblingController instanceof ThreadController) { if (previousSiblingController instanceof ThreadController) {
ThreadController sibling = (ThreadController) previousSiblingController; threadController = (ThreadController) previousSiblingController;
sibling.selectPostImage(postImage); } else if (previousSiblingController instanceof DoubleNavigationController) {
DoubleNavigationController doubleNav = (DoubleNavigationController) previousSiblingController;
if (doubleNav.getRightController() instanceof ThreadController) {
threadController = (ThreadController) doubleNav.getRightController();
}
}
if (threadController != null) {
threadController.selectPostImage(postImage);
navigationController.popController(false); navigationController.popController(false);
return sibling; return threadController;
} else { } else {
return null; return null;
} }

@ -216,8 +216,8 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte
loadBoard(((FloatingMenuItemBoard) item).board); loadBoard(((FloatingMenuItemBoard) item).board);
} else { } else {
BoardEditController boardEditController = new BoardEditController(context); BoardEditController boardEditController = new BoardEditController(context);
if (splitNavigationController != null) { if (doubleNavigationController != null) {
splitNavigationController.pushController(boardEditController); doubleNavigationController.pushController(boardEditController);
} else { } else {
navigationController.pushController(boardEditController); navigationController.pushController(boardEditController);
} }
@ -240,22 +240,55 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte
showThread(threadLoadable, true); showThread(threadLoadable, true);
} }
// Creates or updates the target ThreadViewController
// This controller can be in various places depending on the layout
// We dynamically search for it
public void showThread(Loadable threadLoadable, boolean animated) { public void showThread(Loadable threadLoadable, boolean animated) {
if (splitNavigationController != null) { // The target ThreadViewController is in a split nav
if (splitNavigationController.rightController instanceof StyledToolbarNavigationController) { // (BrowseController -> ToolbarNavigationController -> SplitNavigationController)
StyledToolbarNavigationController navigationController = (StyledToolbarNavigationController) splitNavigationController.rightController; SplitNavigationController splitNav = null;
// The target ThreadViewController is in a slide nav
// (BrowseController -> SlideController -> ToolbarNavigationController)
ThreadSlideController slideNav = null;
if (doubleNavigationController instanceof SplitNavigationController) {
splitNav = (SplitNavigationController) doubleNavigationController;
}
if (doubleNavigationController instanceof ThreadSlideController) {
slideNav = (ThreadSlideController) doubleNavigationController;
}
if (splitNav != null) {
// Create a threadview inside a toolbarnav in the right part of the split layout
if (splitNav.getRightController() instanceof StyledToolbarNavigationController) {
StyledToolbarNavigationController navigationController = (StyledToolbarNavigationController) splitNav.getRightController();
if (navigationController.getTop() instanceof ViewThreadController) { if (navigationController.getTop() instanceof ViewThreadController) {
((ViewThreadController) navigationController.getTop()).loadThread(threadLoadable); ((ViewThreadController) navigationController.getTop()).loadThread(threadLoadable);
} }
} else { } else {
StyledToolbarNavigationController navigationController = new StyledToolbarNavigationController(context); StyledToolbarNavigationController navigationController = new StyledToolbarNavigationController(context);
splitNavigationController.setRightController(navigationController); splitNav.setRightController(navigationController);
ViewThreadController viewThreadController = new ViewThreadController(context); ViewThreadController viewThreadController = new ViewThreadController(context);
viewThreadController.setLoadable(threadLoadable); viewThreadController.setLoadable(threadLoadable);
navigationController.pushController(viewThreadController, false); navigationController.pushController(viewThreadController, false);
} }
splitNav.switchToController(false);
} else if (slideNav != null) {
// Create a threadview in the right part of the slide nav *without* a toolbar
if (slideNav.getRightController() instanceof ViewThreadController) {
((ViewThreadController) slideNav.getRightController()).loadThread(threadLoadable);
} else {
ViewThreadController viewThreadController = new ViewThreadController(context);
viewThreadController.setLoadable(threadLoadable);
slideNav.setRightController(viewThreadController);
}
slideNav.switchToController(false);
} else { } else {
// the target ThreadNav must be pushed to the parent nav controller
// (BrowseController -> ToolbarNavigationController)
ViewThreadController viewThreadController = new ViewThreadController(context); ViewThreadController viewThreadController = new ViewThreadController(context);
viewThreadController.setLoadable(threadLoadable); viewThreadController.setLoadable(threadLoadable);
navigationController.pushController(viewThreadController, animated); navigationController.pushController(viewThreadController, animated);
@ -282,7 +315,7 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte
break; break;
} }
} }
navigationItem.updateTitle(); ((ToolbarNavigationController) navigationController).toolbar.updateTitle(navigationItem);
} }
private void loadBoards() { private void loadBoards() {

@ -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.controller;
import android.view.ViewGroup;
import org.floens.chan.controller.Controller;
import org.floens.chan.controller.ControllerTransition;
public interface DoubleNavigationController {
void setEmptyView(ViewGroup emptyView);
void setLeftController(Controller leftController);
void setRightController(Controller rightController);
Controller getLeftController();
Controller getRightController();
void switchToController(boolean leftController);
boolean pushController(Controller to);
boolean pushController(Controller to, boolean animated);
boolean pushController(Controller to, ControllerTransition controllerTransition);
boolean popController();
boolean popController(boolean animated);
boolean popController(ControllerTransition controllerTransition);
}

@ -120,7 +120,7 @@ public class DrawerController extends Controller implements PinAdapter.Callback,
} }
public void onMenuClicked() { public void onMenuClicked() {
if (getStyledToolbarNavigationController().getTop().navigationItem.hasDrawer) { if (getMainToolbarNavigationController().getTop().navigationItem.hasDrawer) {
drawerLayout.openDrawer(drawer); drawerLayout.openDrawer(drawer);
} }
} }
@ -138,12 +138,8 @@ public class DrawerController extends Controller implements PinAdapter.Callback,
@Override @Override
public void onPinClicked(Pin pin) { public void onPinClicked(Pin pin) {
drawerLayout.closeDrawer(Gravity.LEFT); drawerLayout.closeDrawer(Gravity.LEFT);
ThreadController threadController = getTopThreadController();
StyledToolbarNavigationController navigationController = getStyledToolbarNavigationController(); threadController.openPin(pin);
if (navigationController.getTop() instanceof ThreadController) {
ThreadController threadController = (ThreadController) navigationController.getTop();
threadController.openPin(pin);
}
} }
@Override @Override
@ -277,7 +273,7 @@ public class DrawerController extends Controller implements PinAdapter.Callback,
} }
if (getTop() != null) { if (getTop() != null) {
getStyledToolbarNavigationController().toolbar.getArrowMenuDrawable().setBadge(count, color); getMainToolbarNavigationController().toolbar.getArrowMenuDrawable().setBadge(count, color);
} }
} }
@ -285,29 +281,45 @@ public class DrawerController extends Controller implements PinAdapter.Callback,
Controller top = getTop(); Controller top = getTop();
if (top instanceof NavigationController) { if (top instanceof NavigationController) {
((NavigationController) top).pushController(controller); ((NavigationController) top).pushController(controller);
} else if (top instanceof SplitNavigationController) { } else if (top instanceof DoubleNavigationController) {
((SplitNavigationController) top).pushController(controller); ((DoubleNavigationController) top).pushController(controller);
} }
drawerLayout.closeDrawer(Gravity.LEFT); drawerLayout.closeDrawer(Gravity.LEFT);
} }
private StyledToolbarNavigationController getStyledToolbarNavigationController() { private ThreadController getTopThreadController() {
StyledToolbarNavigationController navigationController = null; ToolbarNavigationController nav = getMainToolbarNavigationController();
if (nav.getTop() instanceof ThreadController) {
return (ThreadController) nav.getTop();
} else if (nav.getTop() instanceof ThreadSlideController) {
ThreadSlideController slideNav = (ThreadSlideController) nav.getTop();
if (slideNav.leftController instanceof ThreadController) {
return (ThreadController) slideNav.leftController;
}
}
throw new IllegalStateException();
}
private ToolbarNavigationController getMainToolbarNavigationController() {
ToolbarNavigationController navigationController = null;
Controller top = getTop(); Controller top = getTop();
if (top instanceof StyledToolbarNavigationController) { if (top instanceof StyledToolbarNavigationController) {
navigationController = (StyledToolbarNavigationController) top; navigationController = (StyledToolbarNavigationController) top;
} else if (top instanceof SplitNavigationController) { } else if (top instanceof SplitNavigationController) {
SplitNavigationController splitNavigationController = (SplitNavigationController) top; SplitNavigationController splitNav = (SplitNavigationController) top;
if (splitNavigationController.leftController instanceof StyledToolbarNavigationController) { if (splitNav.getLeftController() instanceof StyledToolbarNavigationController) {
navigationController = (StyledToolbarNavigationController) splitNavigationController.leftController; navigationController = (StyledToolbarNavigationController) splitNav.getLeftController();
} }
} else if (top instanceof ThreadSlideController) {
ThreadSlideController slideNav = (ThreadSlideController) top;
navigationController = (StyledToolbarNavigationController) slideNav.leftController;
} }
if (navigationController == null) { if (navigationController == null) {
throw new IllegalStateException("The child controller of a DrawerController must either be StyledToolbarNavigationController" + throw new IllegalStateException("The child controller of a DrawerController must either be StyledToolbarNavigationController" +
"or an SplitNavigationController that has a StyledToolbarNavigationController."); "or an DoubleNavigationController that has a ToolbarNavigationController.");
} }
return navigationController; return navigationController;

@ -173,6 +173,8 @@ public class ImageViewerController extends Controller implements ImageViewerPres
return false; return false;
} }
}); });
} else {
presenter.onExit();
} }
break; break;
case SAVE_ID: case SAVE_ID:
@ -281,7 +283,7 @@ public class ImageViewerController extends Controller implements ImageViewerPres
navigationItem.title = postImage.filename + "." + postImage.extension; navigationItem.title = postImage.filename + "." + postImage.extension;
} }
navigationItem.subtitle = (index + 1) + "/" + count; navigationItem.subtitle = (index + 1) + "/" + count;
navigationItem.updateTitle(); ((ToolbarNavigationController) navigationController).toolbar.updateTitle(navigationItem);
} }
public void scrollToImage(PostImage postImage) { public void scrollToImage(PostImage postImage) {

@ -218,6 +218,9 @@ public class MainSettingsController extends SettingsController implements Toolba
case PHONE: case PHONE:
name = R.string.setting_layout_mode_phone; name = R.string.setting_layout_mode_phone;
break; break;
case SLIDE:
name = R.string.setting_layout_mode_slide;
break;
case SPLIT: case SPLIT:
name = R.string.setting_layout_mode_split; name = R.string.setting_layout_mode_split;
break; break;

@ -55,7 +55,7 @@ public class PopupController extends Controller implements View.OnClickListener
} }
public void dismiss() { public void dismiss() {
if (presentingByController instanceof SplitNavigationController) { if (presentingByController instanceof DoubleNavigationController) {
((SplitNavigationController) presentingByController).popAll(); ((SplitNavigationController) presentingByController).popAll();
} }
} }

@ -32,7 +32,7 @@ import org.floens.chan.ui.layout.SplitNavigationControllerLayout;
import static org.floens.chan.utils.AndroidUtils.getAttrColor; import static org.floens.chan.utils.AndroidUtils.getAttrColor;
public class SplitNavigationController extends Controller { public class SplitNavigationController extends Controller implements DoubleNavigationController {
public Controller leftController; public Controller leftController;
public Controller rightController; public Controller rightController;
@ -52,7 +52,7 @@ public class SplitNavigationController extends Controller {
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
splitNavigationController = this; doubleNavigationController = this;
SplitNavigationControllerLayout container = new SplitNavigationControllerLayout(context); SplitNavigationControllerLayout container = new SplitNavigationControllerLayout(context);
view = container; view = container;
@ -72,10 +72,12 @@ public class SplitNavigationController extends Controller {
setRightController(null); setRightController(null);
} }
@Override
public void setEmptyView(ViewGroup emptyView) { public void setEmptyView(ViewGroup emptyView) {
this.emptyView = emptyView; this.emptyView = emptyView;
} }
@Override
public void setLeftController(Controller leftController) { public void setLeftController(Controller leftController) {
if (this.leftController != null) { if (this.leftController != null) {
this.leftController.onHide(); this.leftController.onHide();
@ -91,6 +93,7 @@ public class SplitNavigationController extends Controller {
} }
} }
@Override
public void setRightController(Controller rightController) { public void setRightController(Controller rightController) {
if (this.rightController != null) { if (this.rightController != null) {
this.rightController.onHide(); this.rightController.onHide();
@ -110,14 +113,32 @@ public class SplitNavigationController extends Controller {
} }
} }
@Override
public Controller getLeftController() {
return leftController;
}
@Override
public Controller getRightController() {
return rightController;
}
@Override
public void switchToController(boolean leftController) {
// both are always visible
}
@Override
public boolean pushController(final Controller to) { public boolean pushController(final Controller to) {
return pushController(to, true); return pushController(to, true);
} }
@Override
public boolean pushController(final Controller to, boolean animated) { public boolean pushController(final Controller to, boolean animated) {
return pushController(to, animated ? new PushControllerTransition() : null); return pushController(to, animated ? new PushControllerTransition() : null);
} }
@Override
public boolean pushController(Controller to, ControllerTransition controllerTransition) { public boolean pushController(Controller to, ControllerTransition controllerTransition) {
if (popup == null) { if (popup == null) {
popup = new PopupController(context); popup = new PopupController(context);
@ -132,14 +153,17 @@ public class SplitNavigationController extends Controller {
return true; return true;
} }
@Override
public boolean popController() { public boolean popController() {
return popController(true); return popController(true);
} }
@Override
public boolean popController(boolean animated) { public boolean popController(boolean animated) {
return popController(animated ? new PopControllerTransition() : null); return popController(animated ? new PopControllerTransition() : null);
} }
@Override
public boolean popController(ControllerTransition controllerTransition) { public boolean popController(ControllerTransition controllerTransition) {
if (popup != null) { if (popup != null) {
if (popupChild.childControllers.size() == 1) { if (popupChild.childControllers.size() == 1) {

@ -87,9 +87,9 @@ public class StyledToolbarNavigationController extends ToolbarNavigationControll
} else if (parentController instanceof PopupController && childControllers.size() == 1) { } else if (parentController instanceof PopupController && childControllers.size() == 1) {
((PopupController) parentController).dismiss(); ((PopupController) parentController).dismiss();
return true; return true;
} else if (splitNavigationController != null && childControllers.size() == 1) { } else if (doubleNavigationController != null && childControllers.size() == 1) {
if (splitNavigationController.rightController == this) { if (doubleNavigationController.getRightController() == this) {
splitNavigationController.setRightController(null); doubleNavigationController.setRightController(null);
return true; return true;
} else { } else {
return false; return false;
@ -110,9 +110,10 @@ public class StyledToolbarNavigationController extends ToolbarNavigationControll
private DrawerController getDrawerController() { private DrawerController getDrawerController() {
if (parentController instanceof DrawerController) { if (parentController instanceof DrawerController) {
return (DrawerController) parentController; return (DrawerController) parentController;
} else if (splitNavigationController != null) { } else if (doubleNavigationController != null) {
if (splitNavigationController.parentController instanceof DrawerController) { Controller doubleNav = (Controller) doubleNavigationController;
return (DrawerController) splitNavigationController.parentController; if (doubleNav.parentController instanceof DrawerController) {
return (DrawerController) doubleNav.parentController;
} }
} }
return null; return null;

@ -36,10 +36,12 @@ 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.model.Post; import org.floens.chan.core.model.Post;
import org.floens.chan.core.model.PostImage; import org.floens.chan.core.model.PostImage;
import org.floens.chan.core.settings.ChanSettings;
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;
import org.floens.chan.ui.toolbar.Toolbar; import org.floens.chan.ui.toolbar.Toolbar;
import org.floens.chan.ui.view.ThumbnailView; import org.floens.chan.ui.view.ThumbnailView;
import org.floens.chan.utils.AndroidUtils;
import org.floens.chan.utils.Logger; import org.floens.chan.utils.Logger;
import java.util.List; import java.util.List;
@ -64,7 +66,7 @@ public abstract class ThreadController extends Controller implements ThreadLayou
EventBus.getDefault().register(this); EventBus.getDefault().register(this);
navigationItem.collapseToolbar = true; navigationItem.handlesToolbarInset = true;
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);
@ -79,7 +81,7 @@ public abstract class ThreadController extends Controller implements ThreadLayou
swipeRefreshLayout.setOnRefreshListener(this); swipeRefreshLayout.setOnRefreshListener(this);
if (navigationItem.collapseToolbar) { if (navigationItem.handlesToolbarInset) {
int toolbarHeight = getToolbar().getToolbarHeight(); int toolbarHeight = getToolbar().getToolbarHeight();
swipeRefreshLayout.setProgressViewOffset(false, toolbarHeight - dp(40), toolbarHeight + dp(64 - 40)); swipeRefreshLayout.setProgressViewOffset(false, toolbarHeight - dp(40), toolbarHeight + dp(64 - 40));
} }
@ -207,7 +209,12 @@ public abstract class ThreadController extends Controller implements ThreadLayou
if (threadLayout.getPresenter().getChanThread() != null) { if (threadLayout.getPresenter().getChanThread() != null) {
AlbumViewController albumViewController = new AlbumViewController(context); AlbumViewController albumViewController = new AlbumViewController(context);
albumViewController.setImages(getLoadable(), images, index, navigationItem.title); albumViewController.setImages(getLoadable(), images, index, navigationItem.title);
navigationController.pushController(albumViewController);
if (doubleNavigationController != null) {
doubleNavigationController.pushController(albumViewController);
} else {
navigationController.pushController(albumViewController);
}
} }
} }
@ -222,7 +229,16 @@ public abstract class ThreadController extends Controller implements ThreadLayou
@Override @Override
public Toolbar getToolbar() { public Toolbar getToolbar() {
return ((ToolbarNavigationController) navigationController).getToolbar(); if (navigationController instanceof ToolbarNavigationController) {
return ((ToolbarNavigationController) navigationController).getToolbar();
} else {
return null;
}
}
@Override
public boolean shouldToolbarCollapse() {
return !AndroidUtils.isTablet(context) && !ChanSettings.neverHideToolbar.get();
} }
@Override @Override
@ -238,8 +254,8 @@ public abstract class ThreadController extends Controller implements ThreadLayou
@Override @Override
public void openFilterForTripcode(String tripcode) { public void openFilterForTripcode(String tripcode) {
FiltersController filtersController = new FiltersController(context); FiltersController filtersController = new FiltersController(context);
if (splitNavigationController != null) { if (doubleNavigationController != null) {
splitNavigationController.pushController(filtersController); doubleNavigationController.pushController(filtersController);
} else { } else {
navigationController.pushController(filtersController); navigationController.pushController(filtersController);
} }

@ -0,0 +1,281 @@
/*
* 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.support.v4.widget.SlidingPaneLayout;
import android.view.View;
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.layout.ThreadSlidingPaneLayout;
import org.floens.chan.ui.toolbar.NavigationItem;
import org.floens.chan.ui.toolbar.Toolbar;
import org.floens.chan.utils.Logger;
import java.lang.reflect.Field;
import static org.floens.chan.utils.AndroidUtils.dp;
import static org.floens.chan.utils.AndroidUtils.getAttrColor;
public class ThreadSlideController extends Controller implements DoubleNavigationController, SlidingPaneLayout.PanelSlideListener, ToolbarNavigationController.ToolbarSearchCallback {
private static final String TAG = "ThreadSlideController";
public Controller leftController;
public Controller rightController;
private boolean leftOpen = true;
private ViewGroup emptyView;
private ThreadSlidingPaneLayout slidingPaneLayout;
public ThreadSlideController(Context context) {
super(context);
}
@Override
public void onCreate() {
super.onCreate();
doubleNavigationController = this;
navigationItem.swipeable = false;
navigationItem.handlesToolbarInset = true;
navigationItem.hasDrawer = true;
view = inflateRes(R.layout.controller_thread_slide);
slidingPaneLayout = (ThreadSlidingPaneLayout) view.findViewById(R.id.sliding_pane_layout);
slidingPaneLayout.setThreadSlideController(this);
slidingPaneLayout.setPanelSlideListener(this);
slidingPaneLayout.setParallaxDistance(dp(100));
slidingPaneLayout.setShadowResourceLeft(R.drawable.panel_shadow);
int fadeColor = (getAttrColor(context, R.attr.backcolor) & 0xffffff) + 0xCC000000;
slidingPaneLayout.setSliderFadeColor(fadeColor);
slidingPaneLayout.openPane();
setLeftController(null);
setRightController(null);
}
public void onSlidingPaneLayoutStateRestored() {
// SlidingPaneLayout does some annoying things for state restoring and incorrectly
// tells us if the restored state was open or closed
// We need to use reflection to get the private field that stores this correct state
boolean restoredOpen = false;
try {
Field field = SlidingPaneLayout.class.getDeclaredField("mPreservedOpenState");
field.setAccessible(true);
restoredOpen = field.getBoolean(slidingPaneLayout);
} catch (Exception e) {
Logger.e(TAG, "Error getting restored open state with reflection", e);
}
if (restoredOpen != leftOpen) {
leftOpen = restoredOpen;
slideStateChanged(leftOpen);
}
}
@Override
public void onPanelSlide(View panel, float slideOffset) {
}
@Override
public void onPanelOpened(View panel) {
if (this.leftOpen != leftOpen()) {
this.leftOpen = leftOpen();
slideStateChanged(leftOpen());
}
}
@Override
public void onPanelClosed(View panel) {
if (this.leftOpen != leftOpen()) {
this.leftOpen = leftOpen();
slideStateChanged(leftOpen());
}
}
@Override
public void switchToController(boolean leftController) {
if (leftController != leftOpen()) {
if (leftController) {
slidingPaneLayout.openPane();
} else {
slidingPaneLayout.closePane();
}
Toolbar toolbar = ((ToolbarNavigationController) navigationController).toolbar;
toolbar.processScrollCollapse(Toolbar.TOOLBAR_COLLAPSE_SHOW, true);
}
}
@Override
public void setEmptyView(ViewGroup emptyView) {
this.emptyView = emptyView;
}
public void setLeftController(Controller leftController) {
if (this.leftController != null) {
this.leftController.onHide();
removeChildController(this.leftController);
}
this.leftController = leftController;
if (leftController != null) {
addChildController(leftController);
leftController.attachToParentView(slidingPaneLayout.leftPane);
leftController.onShow();
if (leftOpen()) {
setParentNavigationItem(true);
}
}
}
public void setRightController(Controller rightController) {
if (this.rightController != null) {
this.rightController.onHide();
removeChildController(this.rightController);
} else {
this.slidingPaneLayout.rightPane.removeAllViews();
}
this.rightController = rightController;
if (rightController != null) {
addChildController(rightController);
rightController.attachToParentView(slidingPaneLayout.rightPane);
rightController.onShow();
if (!leftOpen()) {
setParentNavigationItem(false);
}
} else {
slidingPaneLayout.rightPane.addView(emptyView);
}
}
@Override
public Controller getLeftController() {
return leftController;
}
@Override
public Controller getRightController() {
return rightController;
}
@Override
public boolean pushController(Controller to) {
return navigationController.pushController(to);
}
@Override
public boolean pushController(Controller to, boolean animated) {
return navigationController.pushController(to, animated);
}
@Override
public boolean pushController(Controller to, ControllerTransition controllerTransition) {
return navigationController.pushController(to, controllerTransition);
}
@Override
public boolean popController() {
return navigationController.popController();
}
@Override
public boolean popController(boolean animated) {
return navigationController.popController(animated);
}
@Override
public boolean popController(ControllerTransition controllerTransition) {
return navigationController.popController(controllerTransition);
}
@Override
public boolean onBack() {
if (!leftOpen()) {
if (rightController != null && rightController.onBack()) {
return true;
} else {
switchToController(true);
return true;
}
} else {
if (leftController != null && leftController.onBack()) {
return true;
}
}
return super.onBack();
}
@Override
public void onSearchVisibilityChanged(boolean visible) {
if (leftOpen() && leftController != null && leftController instanceof ToolbarNavigationController.ToolbarSearchCallback) {
((ToolbarNavigationController.ToolbarSearchCallback) leftController).onSearchVisibilityChanged(visible);
}
if (!leftOpen() && rightController != null && rightController instanceof ToolbarNavigationController.ToolbarSearchCallback) {
((ToolbarNavigationController.ToolbarSearchCallback) rightController).onSearchVisibilityChanged(visible);
}
}
@Override
public void onSearchEntered(String entered) {
if (leftOpen() && leftController != null && leftController instanceof ToolbarNavigationController.ToolbarSearchCallback) {
((ToolbarNavigationController.ToolbarSearchCallback) leftController).onSearchEntered(entered);
}
if (!leftOpen() && rightController != null && rightController instanceof ToolbarNavigationController.ToolbarSearchCallback) {
((ToolbarNavigationController.ToolbarSearchCallback) rightController).onSearchEntered(entered);
}
}
private boolean leftOpen() {
return slidingPaneLayout.isOpen();
}
private void slideStateChanged(boolean leftOpen) {
setParentNavigationItem(leftOpen);
}
private void setParentNavigationItem(boolean left) {
Toolbar toolbar = ((ToolbarNavigationController) navigationController).toolbar;
NavigationItem item = null;
if (left) {
if (leftController != null) {
item = leftController.navigationItem;
}
} else {
if (rightController != null) {
item = rightController.navigationItem;
}
}
if (item != null) {
navigationItem = item;
navigationItem.swipeable = false;
navigationItem.handlesToolbarInset = true;
navigationItem.hasDrawer = true;
toolbar.setNavigationItem(false, true, navigationItem);
}
}
}

@ -123,7 +123,7 @@ public abstract class ToolbarNavigationController extends NavigationController i
} }
protected void updateToolbarCollapse(Controller controller, boolean animate) { protected void updateToolbarCollapse(Controller controller, boolean animate) {
if (!controller.navigationItem.collapseToolbar) { if (!controller.navigationItem.handlesToolbarInset) {
FrameLayout.LayoutParams toViewParams = (FrameLayout.LayoutParams) controller.view.getLayoutParams(); FrameLayout.LayoutParams toViewParams = (FrameLayout.LayoutParams) controller.view.getLayoutParams();
toViewParams.topMargin = toolbar.getToolbarHeight(); toViewParams.topMargin = toolbar.getToolbarHeight();
controller.view.setLayoutParams(toViewParams); controller.view.setLayoutParams(toViewParams);

@ -145,7 +145,7 @@ public class ViewThreadController extends ThreadController implements ThreadLayo
presenter.bindLoadable(loadable); presenter.bindLoadable(loadable);
this.loadable = presenter.getLoadable(); this.loadable = presenter.getLoadable();
navigationItem.title = loadable.title; navigationItem.title = loadable.title;
navigationItem.updateTitle(); ((ToolbarNavigationController) navigationController).toolbar.updateTitle(navigationItem);
setPinIconState(presenter.isPinned()); setPinIconState(presenter.isPinned());
updateDrawerHighlighting(loadable); updateDrawerHighlighting(loadable);
updateLeftPaneHighlighting(loadable); updateLeftPaneHighlighting(loadable);
@ -165,7 +165,7 @@ public class ViewThreadController extends ThreadController implements ThreadLayo
super.onShowPosts(); super.onShowPosts();
navigationItem.title = loadable.title; navigationItem.title = loadable.title;
navigationItem.updateTitle(); ((ToolbarNavigationController) navigationController).toolbar.updateTitle(navigationItem);
} }
@Override @Override
@ -221,27 +221,31 @@ public class ViewThreadController extends ThreadController implements ThreadLayo
if (navigationController.parentController instanceof DrawerController) { if (navigationController.parentController instanceof DrawerController) {
((DrawerController) navigationController.parentController).setPinHighlighted(pin); ((DrawerController) navigationController.parentController).setPinHighlighted(pin);
} else if (splitNavigationController != null) { } else if (doubleNavigationController != null) {
if (splitNavigationController.parentController instanceof DrawerController) { Controller doubleNav = (Controller) doubleNavigationController;
((DrawerController) splitNavigationController.parentController).setPinHighlighted(pin); if (doubleNav.parentController instanceof DrawerController) {
((DrawerController) doubleNav.parentController).setPinHighlighted(pin);
} }
} }
} }
private void updateLeftPaneHighlighting(Loadable loadable) { private void updateLeftPaneHighlighting(Loadable loadable) {
if (splitNavigationController != null) { if (doubleNavigationController != null) {
if (splitNavigationController.leftController instanceof NavigationController) { ThreadController threadController = null;
NavigationController leftNavigationController = (NavigationController) splitNavigationController.leftController; Controller leftController = doubleNavigationController.getLeftController();
ThreadController threadController = null; if (leftController instanceof ThreadController) {
threadController = (ThreadController) leftController;
} else if (leftController instanceof NavigationController) {
NavigationController leftNavigationController = (NavigationController) leftController;
for (Controller controller : leftNavigationController.childControllers) { for (Controller controller : leftNavigationController.childControllers) {
if (controller instanceof ThreadController) { if (controller instanceof ThreadController) {
threadController = (ThreadController) controller; threadController = (ThreadController) controller;
break; break;
} }
} }
if (threadController != null) { }
threadController.selectPost(loadable != null ? loadable.no : -1); if (threadController != null) {
} threadController.selectPost(loadable != null ? loadable.no : -1);
} }
} }
} }

@ -201,6 +201,11 @@ public class ThreadLayout extends CoordinatorLayout implements ThreadPresenter.T
return callback.getToolbar(); return callback.getToolbar();
} }
@Override
public boolean shouldToolbarCollapse() {
return callback.shouldToolbarCollapse();
}
@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);
@ -565,6 +570,8 @@ public class ThreadLayout extends CoordinatorLayout implements ThreadPresenter.T
Toolbar getToolbar(); Toolbar getToolbar();
boolean shouldToolbarCollapse();
void openFilterForTripcode(String tripcode); void openFilterForTripcode(String tripcode);
} }
} }

@ -454,7 +454,7 @@ public class ThreadListLayout extends FrameLayout implements ReplyLayout.ReplyLa
} }
private void attachToolbarScroll(boolean attach) { private void attachToolbarScroll(boolean attach) {
if (!AndroidUtils.isTablet(getContext()) && !ChanSettings.neverHideToolbar.get()) { if (threadListLayoutCallback.shouldToolbarCollapse()) {
Toolbar toolbar = threadListLayoutCallback.getToolbar(); Toolbar toolbar = threadListLayoutCallback.getToolbar();
if (attach) { if (attach) {
toolbar.attachRecyclerViewScrollStateListener(recyclerView); toolbar.attachRecyclerViewScrollStateListener(recyclerView);
@ -537,5 +537,7 @@ public class ThreadListLayout extends FrameLayout implements ReplyLayout.ReplyLa
void replyLayoutOpen(boolean open); void replyLayoutOpen(boolean open);
Toolbar getToolbar(); Toolbar getToolbar();
boolean shouldToolbarCollapse();
} }
} }

@ -0,0 +1,88 @@
/*
* 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.os.Parcelable;
import android.support.v4.widget.SlidingPaneLayout;
import android.util.AttributeSet;
import android.view.ViewGroup;
import org.floens.chan.R;
import org.floens.chan.ui.controller.ThreadSlideController;
import static org.floens.chan.utils.AndroidUtils.dp;
public class ThreadSlidingPaneLayout extends SlidingPaneLayout {
public ViewGroup leftPane;
public ViewGroup rightPane;
private ThreadSlideController threadSlideController;
public ThreadSlidingPaneLayout(Context context) {
this(context, null);
}
public ThreadSlidingPaneLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ThreadSlidingPaneLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
leftPane = (ViewGroup) findViewById(R.id.left_pane);
rightPane = (ViewGroup) findViewById(R.id.right_pane);
}
public void setThreadSlideController(ThreadSlideController threadSlideController) {
this.threadSlideController = threadSlideController;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
super.onRestoreInstanceState(state);
if (threadSlideController != null) {
threadSlideController.onSlidingPaneLayoutStateRestored();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
ViewGroup.LayoutParams leftParams = leftPane.getLayoutParams();
ViewGroup.LayoutParams rightParams = rightPane.getLayoutParams();
if (width < dp(400)) {
leftParams.width = width - dp(30);
rightParams.width = width;
} else {
leftParams.width = width - dp(60);
rightParams.width = width;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}

@ -19,7 +19,6 @@ package org.floens.chan.ui.toolbar;
import android.content.Context; import android.content.Context;
import android.view.View; import android.view.View;
import android.widget.LinearLayout;
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;
@ -36,13 +35,11 @@ public class NavigationItem {
public FloatingMenu middleMenu; public FloatingMenu middleMenu;
public View rightView; public View rightView;
public boolean hasDrawer = false; public boolean hasDrawer = false;
public boolean collapseToolbar = false; public boolean handlesToolbarInset = false;
public boolean swipeable = true; public boolean swipeable = true;
boolean search = false; boolean search = false;
String searchText; String searchText;
Toolbar toolbar;
LinearLayout view;
public ToolbarMenuItem createOverflow(Context context, ToolbarMenuItem.ToolbarMenuItemCallback callback, List<FloatingMenuItem> items) { public ToolbarMenuItem createOverflow(Context context, ToolbarMenuItem.ToolbarMenuItemCallback callback, List<FloatingMenuItem> items) {
ToolbarMenuItem overflow = menu.createOverflow(callback); ToolbarMenuItem overflow = menu.createOverflow(callback);
@ -51,12 +48,6 @@ public class NavigationItem {
return overflow; return overflow;
} }
public void updateTitle() {
if (toolbar != null) {
toolbar.setTitle(this);
}
}
public void setTitle(int resId) { public void setTitle(int resId) {
title = getString(resId); title = getString(resId);
} }

@ -30,6 +30,7 @@ import android.text.TextUtils;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.Gravity; import android.view.Gravity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MotionEvent;
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;
@ -51,6 +52,7 @@ import java.util.List;
import static org.floens.chan.utils.AndroidUtils.dp; import static org.floens.chan.utils.AndroidUtils.dp;
import static org.floens.chan.utils.AndroidUtils.getAttrColor; import static org.floens.chan.utils.AndroidUtils.getAttrColor;
import static org.floens.chan.utils.AndroidUtils.removeFromParentView;
import static org.floens.chan.utils.AndroidUtils.setRoundItemBackground; import static org.floens.chan.utils.AndroidUtils.setRoundItemBackground;
public class Toolbar extends LinearLayout implements View.OnClickListener { public class Toolbar extends LinearLayout implements View.OnClickListener {
@ -90,7 +92,9 @@ public class Toolbar extends LinearLayout implements View.OnClickListener {
private boolean transitioning = false; private boolean transitioning = false;
private NavigationItem fromItem; private NavigationItem fromItem;
private LinearLayout fromView;
private NavigationItem toItem; private NavigationItem toItem;
private LinearLayout toView;
public Toolbar(Context context) { public Toolbar(Context context) {
super(context); super(context);
@ -107,6 +111,11 @@ public class Toolbar extends LinearLayout implements View.OnClickListener {
init(); init();
} }
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return transitioning || super.dispatchTouchEvent(ev);
}
public int getToolbarHeight() { public int getToolbarHeight() {
return getHeight() == 0 ? getLayoutParams().height : getHeight(); return getHeight() == 0 ? getLayoutParams().height : getHeight();
} }
@ -189,7 +198,7 @@ public class Toolbar extends LinearLayout implements View.OnClickListener {
attachNavigationItem(newItem); attachNavigationItem(newItem);
navigationItemContainer.addView(toItem.view, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); navigationItemContainer.addView(toView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
transitioning = true; transitioning = true;
} }
@ -203,12 +212,12 @@ public class Toolbar extends LinearLayout implements View.OnClickListener {
final int offset = dp(16); final int offset = dp(16);
toItem.view.setTranslationY((pushing ? offset : -offset) * (1f - progress)); toView.setTranslationY((pushing ? offset : -offset) * (1f - progress));
toItem.view.setAlpha(progress); toView.setAlpha(progress);
if (fromItem != null) { if (fromItem != null) {
fromItem.view.setTranslationY((pushing ? -offset : offset) * progress); fromView.setTranslationY((pushing ? -offset : offset) * progress);
fromItem.view.setAlpha(1f - progress); fromView.setAlpha(1f - progress);
} }
float arrowEnd = toItem.hasBack || toItem.search ? 1f : 0f; float arrowEnd = toItem.hasBack || toItem.search ? 1f : 0f;
@ -226,17 +235,20 @@ public class Toolbar extends LinearLayout implements View.OnClickListener {
if (fromItem != null) { if (fromItem != null) {
// From a search otherwise // From a search otherwise
if (fromItem != toItem) { if (fromItem != toItem) {
removeNavigationItem(fromItem); removeNavigationItem(fromItem, fromView);
fromView = null;
} }
} }
setArrowMenuProgress(toItem.hasBack || toItem.search ? 1f : 0f); setArrowMenuProgress(toItem.hasBack || toItem.search ? 1f : 0f);
} else { } else {
removeNavigationItem(toItem); removeNavigationItem(toItem, toView);
setArrowMenuProgress(fromItem.hasBack || fromItem.search ? 1f : 0f); setArrowMenuProgress(fromItem.hasBack || fromItem.search ? 1f : 0f);
toItem = fromItem; toItem = fromItem;
toView = fromView;
} }
fromItem = null; fromItem = null;
fromView = null;
transitioning = false; transitioning = false;
} }
@ -259,15 +271,16 @@ public class Toolbar extends LinearLayout implements View.OnClickListener {
return arrowMenuDrawable; return arrowMenuDrawable;
} }
void setTitle(NavigationItem navigationItem) { public void updateTitle(NavigationItem navigationItem) {
if (navigationItem.view != null) { LinearLayout view = navigationItem == fromItem ? fromView : (navigationItem == toItem ? toView : null);
TextView titleView = (TextView) navigationItem.view.findViewById(R.id.title); if (view != null) {
TextView titleView = (TextView) view.findViewById(R.id.title);
if (titleView != null) { if (titleView != null) {
titleView.setText(navigationItem.title); titleView.setText(navigationItem.title);
} }
if (!TextUtils.isEmpty(navigationItem.subtitle)) { if (!TextUtils.isEmpty(navigationItem.subtitle)) {
TextView subtitleView = (TextView) navigationItem.view.findViewById(R.id.subtitle); TextView subtitleView = (TextView) view.findViewById(R.id.subtitle);
if (subtitleView != null) { if (subtitleView != null) {
subtitleView.setText(navigationItem.subtitle); subtitleView.setText(navigationItem.subtitle);
} }
@ -344,14 +357,14 @@ public class Toolbar extends LinearLayout implements View.OnClickListener {
navigationItemContainer.setListener(null); navigationItemContainer.setListener(null);
} }
}); });
navigationItemContainer.setView(toItem.view, animate); navigationItemContainer.setView(toView, animate);
animateArrow(toItem.hasBack || toItem.search); animateArrow(toItem.hasBack || toItem.search);
} else { } else {
navigationItemContainer.addView(toItem.view, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); navigationItemContainer.addView(toView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
if (animate) { if (animate) {
toItem.view.setAlpha(0f); toView.setAlpha(0f);
ValueAnimator animator = ObjectAnimator.ofFloat(0f, 1f); ValueAnimator animator = ObjectAnimator.ofFloat(0f, 1f);
animator.setDuration(300); animator.setDuration(300);
@ -385,25 +398,22 @@ public class Toolbar extends LinearLayout implements View.OnClickListener {
} }
fromItem = toItem; fromItem = toItem;
fromView = toView;
toItem = newItem; toItem = newItem;
toView = createNavigationItemView(toItem);
if (!toItem.search) { if (!toItem.search) {
AndroidUtils.hideKeyboard(navigationItemContainer); AndroidUtils.hideKeyboard(navigationItemContainer);
} }
toItem.toolbar = this;
toItem.view = createNavigationItemView(toItem);
} }
private void removeNavigationItem(NavigationItem item) { private void removeNavigationItem(NavigationItem item, LinearLayout view) {
if (!transitioning) { if (!transitioning) {
throw new IllegalStateException("removeNavigationItem called while not transitioning"); throw new IllegalStateException("removeNavigationItem called while not transitioning");
} }
item.view.removeAllViews(); view.removeAllViews();
navigationItemContainer.removeView(item.view); navigationItemContainer.removeView(view);
item.view = null;
item.toolbar = null;
} }
private LinearLayout createNavigationItemView(final NavigationItem item) { private LinearLayout createNavigationItemView(final NavigationItem item) {
@ -471,11 +481,13 @@ public class Toolbar extends LinearLayout implements View.OnClickListener {
} }
if (item.rightView != null) { if (item.rightView != null) {
removeFromParentView(item.rightView);
item.rightView.setPadding(0, 0, dp(16), 0); item.rightView.setPadding(0, 0, dp(16), 0);
menu.addView(item.rightView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)); menu.addView(item.rightView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
} }
if (item.menu != null) { if (item.menu != null) {
removeFromParentView(item.menu);
menu.addView(item.menu, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)); menu.addView(item.menu, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
} }

@ -17,7 +17,6 @@
*/ */
package org.floens.chan.utils; package org.floens.chan.utils;
import android.annotation.SuppressLint;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.Activity; import android.app.Activity;
import android.app.Dialog; import android.app.Dialog;
@ -45,7 +44,6 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewTreeObserver; import android.view.ViewTreeObserver;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.webkit.WebView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
@ -319,7 +317,7 @@ public class AndroidUtils {
if (usingViewTreeObserver.isAlive()) { if (usingViewTreeObserver.isAlive()) {
usingViewTreeObserver.removeOnPreDrawListener(this); usingViewTreeObserver.removeOnPreDrawListener(this);
} else { } else {
Logger.w(TAG, "ViewTreeObserver not alive, could not remove onPreDrawListener! This will probably not end well"); Logger.e(TAG, "ViewTreeObserver not alive, could not remove onPreDrawListener! This will probably not end well");
} }
boolean ret; boolean ret;
@ -331,7 +329,7 @@ public class AndroidUtils {
} }
if (!ret) { if (!ret) {
Logger.w(TAG, "waitForLayout requested a re-layout by returning false"); Logger.d(TAG, "waitForLayout requested a re-layout by returning false");
} }
return ret; return ret;

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

@ -0,0 +1,34 @@
<?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.layout.ThreadSlidingPaneLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/sliding_pane_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?backcolor">
<FrameLayout
android:id="@+id/left_pane"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<FrameLayout
android:id="@+id/right_pane"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</org.floens.chan.ui.layout.ThreadSlidingPaneLayout>

@ -358,6 +358,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<string name="setting_layout_mode">Layout mode</string> <string name="setting_layout_mode">Layout mode</string>
<string name="setting_layout_mode_auto">Auto</string> <string name="setting_layout_mode_auto">Auto</string>
<string name="setting_layout_mode_phone">Phone layout</string> <string name="setting_layout_mode_phone">Phone layout</string>
<string name="setting_layout_mode_slide">Slide mode</string>
<string name="setting_layout_mode_split">Split mode</string> <string name="setting_layout_mode_split">Split mode</string>
<string name="setting_font_size">Font size</string> <string name="setting_font_size">Font size</string>
<string name="setting_font_size_default">(default)</string> <string name="setting_font_size_default">(default)</string>

Loading…
Cancel
Save