diff --git a/Clover/app/proguard.cfg b/Clover/app/proguard.cfg index 9c87b09f..810d3043 100644 --- a/Clover/app/proguard.cfg +++ b/Clover/app/proguard.cfg @@ -103,5 +103,6 @@ #-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.v4.widget.SlidingPaneLayout diff --git a/Clover/app/src/main/java/org/floens/chan/controller/Controller.java b/Clover/app/src/main/java/org/floens/chan/controller/Controller.java index 42f9853b..9dffa588 100644 --- a/Clover/app/src/main/java/org/floens/chan/controller/Controller.java +++ b/Clover/app/src/main/java/org/floens/chan/controller/Controller.java @@ -27,7 +27,7 @@ import android.view.ViewGroup; import org.floens.chan.controller.transition.FadeInTransition; import org.floens.chan.controller.transition.FadeOutTransition; 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.utils.AndroidUtils; import org.floens.chan.utils.Logger; @@ -51,7 +51,7 @@ public abstract class Controller { public Controller previousSiblingController; public NavigationController navigationController; - public SplitNavigationController splitNavigationController; + public DoubleNavigationController doubleNavigationController; /** * Controller that this controller is presented by. @@ -127,7 +127,12 @@ public abstract class Controller { public void addChildController(Controller controller) { childControllers.add(controller); controller.parentController = this; - controller.splitNavigationController = splitNavigationController; + if (doubleNavigationController != null) { + controller.doubleNavigationController = doubleNavigationController; + } + if (navigationController != null) { + controller.navigationController = navigationController; + } controller.onCreate(); } diff --git a/Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java b/Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java index a0aa103c..4f3a35c3 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java +++ b/Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java @@ -71,6 +71,7 @@ public class ChanSettings { public enum LayoutMode implements OptionSettingItem { AUTO("auto"), PHONE("phone"), + SLIDE("slide"), SPLIT("split"); String name; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java index fd1f80bc..39b9cbb3 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java @@ -44,9 +44,11 @@ import org.floens.chan.core.model.Loadable; import org.floens.chan.core.model.Pin; import org.floens.chan.core.settings.ChanSettings; 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.SplitNavigationController; 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.helper.ImagePickDelegate; import org.floens.chan.ui.helper.PreviousVersionHandler; @@ -95,35 +97,7 @@ public class StartActivity extends AppCompatActivity implements NfcAdapter.Creat drawerController.onCreate(); drawerController.onShow(); - StyledToolbarNavigationController toolbarNavigationController = 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 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); + setupLayout(); setContentView(drawerController.view); addController(drawerController); @@ -190,6 +164,45 @@ public class StartActivity extends AppCompatActivity implements NfcAdapter.Creat 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() { Intent intent = getIntent(); finish(); @@ -237,9 +250,9 @@ public class StartActivity extends AppCompatActivity implements NfcAdapter.Creat Loadable thread = null; if (drawerController.childControllers.get(0) instanceof SplitNavigationController) { - SplitNavigationController splitNavigationController = (SplitNavigationController) drawerController.childControllers.get(0); - if (splitNavigationController.rightController instanceof NavigationController) { - NavigationController rightNavigationController = (NavigationController) splitNavigationController.rightController; + SplitNavigationController doubleNav = (SplitNavigationController) drawerController.childControllers.get(0); + if (doubleNav.getRightController() instanceof NavigationController) { + NavigationController rightNavigationController = (NavigationController) doubleNav.getRightController(); for (Controller controller : rightNavigationController.childControllers) { if (controller instanceof ViewThreadController) { thread = ((ViewThreadController) controller).getLoadable(); @@ -254,6 +267,12 @@ public class StartActivity extends AppCompatActivity implements NfcAdapter.Creat if (controller instanceof ViewThreadController) { thread = ((ViewThreadController) controller).getLoadable(); 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 public NdefMessage createNdefMessage(NfcEvent event) { Controller threadController = null; - if (drawerController.childControllers.get(0) instanceof SplitNavigationController) { + if (drawerController.childControllers.get(0) instanceof DoubleNavigationController) { SplitNavigationController splitNavigationController = (SplitNavigationController) drawerController.childControllers.get(0); if (splitNavigationController.rightController instanceof NavigationController) { NavigationController rightNavigationController = (NavigationController) splitNavigationController.rightController; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/AlbumDownloadController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/AlbumDownloadController.java index 64ffa1b2..03b9b4b6 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/AlbumDownloadController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/AlbumDownloadController.java @@ -168,7 +168,7 @@ public class AlbumDownloadController extends Controller implements ToolbarMenuIt private void updateTitle() { navigationItem.title = context.getString(R.string.album_download_screen, getCheckCount(), items.size()); - navigationItem.updateTitle(); + ((ToolbarNavigationController) navigationController).toolbar.updateTitle(navigationItem); } private void updateAllChecked() { diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/AlbumViewController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/AlbumViewController.java index c36a3c0a..41ef9068 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/AlbumViewController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/AlbumViewController.java @@ -135,11 +135,21 @@ public class AlbumViewController extends Controller implements ImageViewerContro @Override public ImageViewerController.ImageViewerCallback goToPost(PostImage postImage) { + ThreadController threadController = null; + if (previousSiblingController instanceof ThreadController) { - ThreadController sibling = (ThreadController) previousSiblingController; - sibling.selectPostImage(postImage); + threadController = (ThreadController) previousSiblingController; + } 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); - return sibling; + return threadController; } else { return null; } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/BrowseController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/BrowseController.java index 6b1d040e..4c4377bc 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/BrowseController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/BrowseController.java @@ -216,8 +216,8 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte loadBoard(((FloatingMenuItemBoard) item).board); } else { BoardEditController boardEditController = new BoardEditController(context); - if (splitNavigationController != null) { - splitNavigationController.pushController(boardEditController); + if (doubleNavigationController != null) { + doubleNavigationController.pushController(boardEditController); } else { navigationController.pushController(boardEditController); } @@ -240,22 +240,55 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte 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) { - if (splitNavigationController != null) { - if (splitNavigationController.rightController instanceof StyledToolbarNavigationController) { - StyledToolbarNavigationController navigationController = (StyledToolbarNavigationController) splitNavigationController.rightController; + // The target ThreadViewController is in a split nav + // (BrowseController -> ToolbarNavigationController -> SplitNavigationController) + 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) { ((ViewThreadController) navigationController.getTop()).loadThread(threadLoadable); } } else { StyledToolbarNavigationController navigationController = new StyledToolbarNavigationController(context); - splitNavigationController.setRightController(navigationController); + splitNav.setRightController(navigationController); ViewThreadController viewThreadController = new ViewThreadController(context); viewThreadController.setLoadable(threadLoadable); 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 { + // the target ThreadNav must be pushed to the parent nav controller + // (BrowseController -> ToolbarNavigationController) ViewThreadController viewThreadController = new ViewThreadController(context); viewThreadController.setLoadable(threadLoadable); navigationController.pushController(viewThreadController, animated); @@ -282,7 +315,7 @@ public class BrowseController extends ThreadController implements ToolbarMenuIte break; } } - navigationItem.updateTitle(); + ((ToolbarNavigationController) navigationController).toolbar.updateTitle(navigationItem); } private void loadBoards() { diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/DoubleNavigationController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/DoubleNavigationController.java new file mode 100644 index 00000000..a711e927 --- /dev/null +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/DoubleNavigationController.java @@ -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 . + */ +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); +} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/DrawerController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/DrawerController.java index c4c367ce..91b9a59b 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/DrawerController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/DrawerController.java @@ -120,7 +120,7 @@ public class DrawerController extends Controller implements PinAdapter.Callback, } public void onMenuClicked() { - if (getStyledToolbarNavigationController().getTop().navigationItem.hasDrawer) { + if (getMainToolbarNavigationController().getTop().navigationItem.hasDrawer) { drawerLayout.openDrawer(drawer); } } @@ -138,12 +138,8 @@ public class DrawerController extends Controller implements PinAdapter.Callback, @Override public void onPinClicked(Pin pin) { drawerLayout.closeDrawer(Gravity.LEFT); - - StyledToolbarNavigationController navigationController = getStyledToolbarNavigationController(); - if (navigationController.getTop() instanceof ThreadController) { - ThreadController threadController = (ThreadController) navigationController.getTop(); - threadController.openPin(pin); - } + ThreadController threadController = getTopThreadController(); + threadController.openPin(pin); } @Override @@ -277,7 +273,7 @@ public class DrawerController extends Controller implements PinAdapter.Callback, } 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(); if (top instanceof NavigationController) { ((NavigationController) top).pushController(controller); - } else if (top instanceof SplitNavigationController) { - ((SplitNavigationController) top).pushController(controller); + } else if (top instanceof DoubleNavigationController) { + ((DoubleNavigationController) top).pushController(controller); } drawerLayout.closeDrawer(Gravity.LEFT); } - private StyledToolbarNavigationController getStyledToolbarNavigationController() { - StyledToolbarNavigationController navigationController = null; + private ThreadController getTopThreadController() { + 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(); if (top instanceof StyledToolbarNavigationController) { navigationController = (StyledToolbarNavigationController) top; } else if (top instanceof SplitNavigationController) { - SplitNavigationController splitNavigationController = (SplitNavigationController) top; - if (splitNavigationController.leftController instanceof StyledToolbarNavigationController) { - navigationController = (StyledToolbarNavigationController) splitNavigationController.leftController; + SplitNavigationController splitNav = (SplitNavigationController) top; + if (splitNav.getLeftController() instanceof StyledToolbarNavigationController) { + navigationController = (StyledToolbarNavigationController) splitNav.getLeftController(); } + } else if (top instanceof ThreadSlideController) { + ThreadSlideController slideNav = (ThreadSlideController) top; + navigationController = (StyledToolbarNavigationController) slideNav.leftController; } if (navigationController == null) { 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; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerController.java index 85104b2a..e08b8ed9 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerController.java @@ -173,6 +173,8 @@ public class ImageViewerController extends Controller implements ImageViewerPres return false; } }); + } else { + presenter.onExit(); } break; case SAVE_ID: @@ -281,7 +283,7 @@ public class ImageViewerController extends Controller implements ImageViewerPres navigationItem.title = postImage.filename + "." + postImage.extension; } navigationItem.subtitle = (index + 1) + "/" + count; - navigationItem.updateTitle(); + ((ToolbarNavigationController) navigationController).toolbar.updateTitle(navigationItem); } public void scrollToImage(PostImage postImage) { diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/MainSettingsController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/MainSettingsController.java index 80dc0c88..49742ba4 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/MainSettingsController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/MainSettingsController.java @@ -218,6 +218,9 @@ public class MainSettingsController extends SettingsController implements Toolba case PHONE: name = R.string.setting_layout_mode_phone; break; + case SLIDE: + name = R.string.setting_layout_mode_slide; + break; case SPLIT: name = R.string.setting_layout_mode_split; break; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/PopupController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/PopupController.java index 935153b2..86e10f5e 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/PopupController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/PopupController.java @@ -55,7 +55,7 @@ public class PopupController extends Controller implements View.OnClickListener } public void dismiss() { - if (presentingByController instanceof SplitNavigationController) { + if (presentingByController instanceof DoubleNavigationController) { ((SplitNavigationController) presentingByController).popAll(); } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/SplitNavigationController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/SplitNavigationController.java index 4ee4dcf1..788c6c12 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/SplitNavigationController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/SplitNavigationController.java @@ -32,7 +32,7 @@ import org.floens.chan.ui.layout.SplitNavigationControllerLayout; 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 rightController; @@ -52,7 +52,7 @@ public class SplitNavigationController extends Controller { public void onCreate() { super.onCreate(); - splitNavigationController = this; + doubleNavigationController = this; SplitNavigationControllerLayout container = new SplitNavigationControllerLayout(context); view = container; @@ -72,10 +72,12 @@ public class SplitNavigationController extends Controller { setRightController(null); } + @Override public void setEmptyView(ViewGroup emptyView) { this.emptyView = emptyView; } + @Override public void setLeftController(Controller leftController) { if (this.leftController != null) { this.leftController.onHide(); @@ -91,6 +93,7 @@ public class SplitNavigationController extends Controller { } } + @Override public void setRightController(Controller rightController) { if (this.rightController != null) { 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) { return pushController(to, true); } + @Override public boolean pushController(final Controller to, boolean animated) { return pushController(to, animated ? new PushControllerTransition() : null); } + @Override public boolean pushController(Controller to, ControllerTransition controllerTransition) { if (popup == null) { popup = new PopupController(context); @@ -132,14 +153,17 @@ public class SplitNavigationController extends Controller { return true; } + @Override public boolean popController() { return popController(true); } + @Override public boolean popController(boolean animated) { return popController(animated ? new PopControllerTransition() : null); } + @Override public boolean popController(ControllerTransition controllerTransition) { if (popup != null) { if (popupChild.childControllers.size() == 1) { diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/StyledToolbarNavigationController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/StyledToolbarNavigationController.java index ffad563c..7da1965c 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/StyledToolbarNavigationController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/StyledToolbarNavigationController.java @@ -87,9 +87,9 @@ public class StyledToolbarNavigationController extends ToolbarNavigationControll } else if (parentController instanceof PopupController && childControllers.size() == 1) { ((PopupController) parentController).dismiss(); return true; - } else if (splitNavigationController != null && childControllers.size() == 1) { - if (splitNavigationController.rightController == this) { - splitNavigationController.setRightController(null); + } else if (doubleNavigationController != null && childControllers.size() == 1) { + if (doubleNavigationController.getRightController() == this) { + doubleNavigationController.setRightController(null); return true; } else { return false; @@ -110,9 +110,10 @@ public class StyledToolbarNavigationController extends ToolbarNavigationControll private DrawerController getDrawerController() { if (parentController instanceof DrawerController) { return (DrawerController) parentController; - } else if (splitNavigationController != null) { - if (splitNavigationController.parentController instanceof DrawerController) { - return (DrawerController) splitNavigationController.parentController; + } else if (doubleNavigationController != null) { + Controller doubleNav = (Controller) doubleNavigationController; + if (doubleNav.parentController instanceof DrawerController) { + return (DrawerController) doubleNav.parentController; } } return null; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java index 5c977eca..6403cb30 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java @@ -36,10 +36,12 @@ import org.floens.chan.core.model.Loadable; import org.floens.chan.core.model.Pin; import org.floens.chan.core.model.Post; 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.layout.ThreadLayout; import org.floens.chan.ui.toolbar.Toolbar; import org.floens.chan.ui.view.ThumbnailView; +import org.floens.chan.utils.AndroidUtils; import org.floens.chan.utils.Logger; import java.util.List; @@ -64,7 +66,7 @@ public abstract class ThreadController extends Controller implements ThreadLayou EventBus.getDefault().register(this); - navigationItem.collapseToolbar = true; + navigationItem.handlesToolbarInset = true; threadLayout = (ThreadLayout) LayoutInflater.from(context).inflate(R.layout.layout_thread, null); threadLayout.setCallback(this); @@ -79,7 +81,7 @@ public abstract class ThreadController extends Controller implements ThreadLayou swipeRefreshLayout.setOnRefreshListener(this); - if (navigationItem.collapseToolbar) { + if (navigationItem.handlesToolbarInset) { int toolbarHeight = getToolbar().getToolbarHeight(); 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) { AlbumViewController albumViewController = new AlbumViewController(context); 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 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 @@ -238,8 +254,8 @@ public abstract class ThreadController extends Controller implements ThreadLayou @Override public void openFilterForTripcode(String tripcode) { FiltersController filtersController = new FiltersController(context); - if (splitNavigationController != null) { - splitNavigationController.pushController(filtersController); + if (doubleNavigationController != null) { + doubleNavigationController.pushController(filtersController); } else { navigationController.pushController(filtersController); } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadSlideController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadSlideController.java new file mode 100644 index 00000000..4fee6eb4 --- /dev/null +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadSlideController.java @@ -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 . + */ +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); + } + } +} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/ToolbarNavigationController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/ToolbarNavigationController.java index ec2b4a64..9ac14bcd 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/ToolbarNavigationController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/ToolbarNavigationController.java @@ -123,7 +123,7 @@ public abstract class ToolbarNavigationController extends NavigationController i } protected void updateToolbarCollapse(Controller controller, boolean animate) { - if (!controller.navigationItem.collapseToolbar) { + if (!controller.navigationItem.handlesToolbarInset) { FrameLayout.LayoutParams toViewParams = (FrameLayout.LayoutParams) controller.view.getLayoutParams(); toViewParams.topMargin = toolbar.getToolbarHeight(); controller.view.setLayoutParams(toViewParams); diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/ViewThreadController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/ViewThreadController.java index 1dafed3b..71c773c3 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/ViewThreadController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/ViewThreadController.java @@ -145,7 +145,7 @@ public class ViewThreadController extends ThreadController implements ThreadLayo presenter.bindLoadable(loadable); this.loadable = presenter.getLoadable(); navigationItem.title = loadable.title; - navigationItem.updateTitle(); + ((ToolbarNavigationController) navigationController).toolbar.updateTitle(navigationItem); setPinIconState(presenter.isPinned()); updateDrawerHighlighting(loadable); updateLeftPaneHighlighting(loadable); @@ -165,7 +165,7 @@ public class ViewThreadController extends ThreadController implements ThreadLayo super.onShowPosts(); navigationItem.title = loadable.title; - navigationItem.updateTitle(); + ((ToolbarNavigationController) navigationController).toolbar.updateTitle(navigationItem); } @Override @@ -221,27 +221,31 @@ public class ViewThreadController extends ThreadController implements ThreadLayo if (navigationController.parentController instanceof DrawerController) { ((DrawerController) navigationController.parentController).setPinHighlighted(pin); - } else if (splitNavigationController != null) { - if (splitNavigationController.parentController instanceof DrawerController) { - ((DrawerController) splitNavigationController.parentController).setPinHighlighted(pin); + } else if (doubleNavigationController != null) { + Controller doubleNav = (Controller) doubleNavigationController; + if (doubleNav.parentController instanceof DrawerController) { + ((DrawerController) doubleNav.parentController).setPinHighlighted(pin); } } } private void updateLeftPaneHighlighting(Loadable loadable) { - if (splitNavigationController != null) { - if (splitNavigationController.leftController instanceof NavigationController) { - NavigationController leftNavigationController = (NavigationController) splitNavigationController.leftController; - ThreadController threadController = null; + if (doubleNavigationController != null) { + ThreadController threadController = null; + Controller leftController = doubleNavigationController.getLeftController(); + if (leftController instanceof ThreadController) { + threadController = (ThreadController) leftController; + } else if (leftController instanceof NavigationController) { + NavigationController leftNavigationController = (NavigationController) leftController; for (Controller controller : leftNavigationController.childControllers) { if (controller instanceof ThreadController) { threadController = (ThreadController) controller; break; } } - if (threadController != null) { - threadController.selectPost(loadable != null ? loadable.no : -1); - } + } + if (threadController != null) { + threadController.selectPost(loadable != null ? loadable.no : -1); } } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadLayout.java b/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadLayout.java index 535859b7..48fcb578 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadLayout.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadLayout.java @@ -201,6 +201,11 @@ public class ThreadLayout extends CoordinatorLayout implements ThreadPresenter.T return callback.getToolbar(); } + @Override + public boolean shouldToolbarCollapse() { + return callback.shouldToolbarCollapse(); + } + @Override public void showPosts(ChanThread thread, PostsFilter filter) { threadListLayout.showPosts(thread, filter, visible != Visible.THREAD); @@ -565,6 +570,8 @@ public class ThreadLayout extends CoordinatorLayout implements ThreadPresenter.T Toolbar getToolbar(); + boolean shouldToolbarCollapse(); + void openFilterForTripcode(String tripcode); } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadListLayout.java b/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadListLayout.java index 93d1106e..389df6e4 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadListLayout.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadListLayout.java @@ -454,7 +454,7 @@ public class ThreadListLayout extends FrameLayout implements ReplyLayout.ReplyLa } private void attachToolbarScroll(boolean attach) { - if (!AndroidUtils.isTablet(getContext()) && !ChanSettings.neverHideToolbar.get()) { + if (threadListLayoutCallback.shouldToolbarCollapse()) { Toolbar toolbar = threadListLayoutCallback.getToolbar(); if (attach) { toolbar.attachRecyclerViewScrollStateListener(recyclerView); @@ -537,5 +537,7 @@ public class ThreadListLayout extends FrameLayout implements ReplyLayout.ReplyLa void replyLayoutOpen(boolean open); Toolbar getToolbar(); + + boolean shouldToolbarCollapse(); } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadSlidingPaneLayout.java b/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadSlidingPaneLayout.java new file mode 100644 index 00000000..69758f3c --- /dev/null +++ b/Clover/app/src/main/java/org/floens/chan/ui/layout/ThreadSlidingPaneLayout.java @@ -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 . + */ +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); + } +} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/toolbar/NavigationItem.java b/Clover/app/src/main/java/org/floens/chan/ui/toolbar/NavigationItem.java index fb86a8f9..8f538bbe 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/toolbar/NavigationItem.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/toolbar/NavigationItem.java @@ -19,7 +19,6 @@ package org.floens.chan.ui.toolbar; import android.content.Context; import android.view.View; -import android.widget.LinearLayout; import org.floens.chan.ui.view.FloatingMenu; import org.floens.chan.ui.view.FloatingMenuItem; @@ -36,13 +35,11 @@ public class NavigationItem { public FloatingMenu middleMenu; public View rightView; public boolean hasDrawer = false; - public boolean collapseToolbar = false; + public boolean handlesToolbarInset = false; public boolean swipeable = true; boolean search = false; String searchText; - Toolbar toolbar; - LinearLayout view; public ToolbarMenuItem createOverflow(Context context, ToolbarMenuItem.ToolbarMenuItemCallback callback, List items) { ToolbarMenuItem overflow = menu.createOverflow(callback); @@ -51,12 +48,6 @@ public class NavigationItem { return overflow; } - public void updateTitle() { - if (toolbar != null) { - toolbar.setTitle(this); - } - } - public void setTitle(int resId) { title = getString(resId); } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/toolbar/Toolbar.java b/Clover/app/src/main/java/org/floens/chan/ui/toolbar/Toolbar.java index d5341327..c072defd 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/toolbar/Toolbar.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/toolbar/Toolbar.java @@ -30,6 +30,7 @@ import android.text.TextUtils; import android.util.AttributeSet; import android.view.Gravity; import android.view.LayoutInflater; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; 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.getAttrColor; +import static org.floens.chan.utils.AndroidUtils.removeFromParentView; import static org.floens.chan.utils.AndroidUtils.setRoundItemBackground; 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 NavigationItem fromItem; + private LinearLayout fromView; private NavigationItem toItem; + private LinearLayout toView; public Toolbar(Context context) { super(context); @@ -107,6 +111,11 @@ public class Toolbar extends LinearLayout implements View.OnClickListener { init(); } + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + return transitioning || super.dispatchTouchEvent(ev); + } + public int getToolbarHeight() { return getHeight() == 0 ? getLayoutParams().height : getHeight(); } @@ -189,7 +198,7 @@ public class Toolbar extends LinearLayout implements View.OnClickListener { attachNavigationItem(newItem); - navigationItemContainer.addView(toItem.view, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + navigationItemContainer.addView(toView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); transitioning = true; } @@ -203,12 +212,12 @@ public class Toolbar extends LinearLayout implements View.OnClickListener { final int offset = dp(16); - toItem.view.setTranslationY((pushing ? offset : -offset) * (1f - progress)); - toItem.view.setAlpha(progress); + toView.setTranslationY((pushing ? offset : -offset) * (1f - progress)); + toView.setAlpha(progress); if (fromItem != null) { - fromItem.view.setTranslationY((pushing ? -offset : offset) * progress); - fromItem.view.setAlpha(1f - progress); + fromView.setTranslationY((pushing ? -offset : offset) * progress); + fromView.setAlpha(1f - progress); } float arrowEnd = toItem.hasBack || toItem.search ? 1f : 0f; @@ -226,17 +235,20 @@ public class Toolbar extends LinearLayout implements View.OnClickListener { if (fromItem != null) { // From a search otherwise if (fromItem != toItem) { - removeNavigationItem(fromItem); + removeNavigationItem(fromItem, fromView); + fromView = null; } } setArrowMenuProgress(toItem.hasBack || toItem.search ? 1f : 0f); } else { - removeNavigationItem(toItem); + removeNavigationItem(toItem, toView); setArrowMenuProgress(fromItem.hasBack || fromItem.search ? 1f : 0f); toItem = fromItem; + toView = fromView; } fromItem = null; + fromView = null; transitioning = false; } @@ -259,15 +271,16 @@ public class Toolbar extends LinearLayout implements View.OnClickListener { return arrowMenuDrawable; } - void setTitle(NavigationItem navigationItem) { - if (navigationItem.view != null) { - TextView titleView = (TextView) navigationItem.view.findViewById(R.id.title); + public void updateTitle(NavigationItem navigationItem) { + LinearLayout view = navigationItem == fromItem ? fromView : (navigationItem == toItem ? toView : null); + if (view != null) { + TextView titleView = (TextView) view.findViewById(R.id.title); if (titleView != null) { titleView.setText(navigationItem.title); } 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) { subtitleView.setText(navigationItem.subtitle); } @@ -344,14 +357,14 @@ public class Toolbar extends LinearLayout implements View.OnClickListener { navigationItemContainer.setListener(null); } }); - navigationItemContainer.setView(toItem.view, animate); + navigationItemContainer.setView(toView, animate); animateArrow(toItem.hasBack || toItem.search); } else { - navigationItemContainer.addView(toItem.view, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + navigationItemContainer.addView(toView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); if (animate) { - toItem.view.setAlpha(0f); + toView.setAlpha(0f); ValueAnimator animator = ObjectAnimator.ofFloat(0f, 1f); animator.setDuration(300); @@ -385,25 +398,22 @@ public class Toolbar extends LinearLayout implements View.OnClickListener { } fromItem = toItem; + fromView = toView; toItem = newItem; + toView = createNavigationItemView(toItem); if (!toItem.search) { AndroidUtils.hideKeyboard(navigationItemContainer); } - - toItem.toolbar = this; - toItem.view = createNavigationItemView(toItem); } - private void removeNavigationItem(NavigationItem item) { + private void removeNavigationItem(NavigationItem item, LinearLayout view) { if (!transitioning) { throw new IllegalStateException("removeNavigationItem called while not transitioning"); } - item.view.removeAllViews(); - navigationItemContainer.removeView(item.view); - item.view = null; - item.toolbar = null; + view.removeAllViews(); + navigationItemContainer.removeView(view); } private LinearLayout createNavigationItemView(final NavigationItem item) { @@ -471,11 +481,13 @@ public class Toolbar extends LinearLayout implements View.OnClickListener { } if (item.rightView != null) { + removeFromParentView(item.rightView); item.rightView.setPadding(0, 0, dp(16), 0); menu.addView(item.rightView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)); } if (item.menu != null) { + removeFromParentView(item.menu); menu.addView(item.menu, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)); } diff --git a/Clover/app/src/main/java/org/floens/chan/utils/AndroidUtils.java b/Clover/app/src/main/java/org/floens/chan/utils/AndroidUtils.java index 6c5d70ff..f8ef0b6e 100644 --- a/Clover/app/src/main/java/org/floens/chan/utils/AndroidUtils.java +++ b/Clover/app/src/main/java/org/floens/chan/utils/AndroidUtils.java @@ -17,7 +17,6 @@ */ package org.floens.chan.utils; -import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.Activity; import android.app.Dialog; @@ -45,7 +44,6 @@ import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.inputmethod.InputMethodManager; -import android.webkit.WebView; import android.widget.TextView; import android.widget.Toast; @@ -319,7 +317,7 @@ public class AndroidUtils { if (usingViewTreeObserver.isAlive()) { usingViewTreeObserver.removeOnPreDrawListener(this); } 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; @@ -331,7 +329,7 @@ public class AndroidUtils { } 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; diff --git a/Clover/app/src/main/res/drawable-hdpi/panel_shadow.9.png b/Clover/app/src/main/res/drawable-hdpi/panel_shadow.9.png new file mode 100644 index 00000000..19ae6630 Binary files /dev/null and b/Clover/app/src/main/res/drawable-hdpi/panel_shadow.9.png differ diff --git a/Clover/app/src/main/res/drawable-mdpi/panel_shadow.9.png b/Clover/app/src/main/res/drawable-mdpi/panel_shadow.9.png new file mode 100644 index 00000000..e104117f Binary files /dev/null and b/Clover/app/src/main/res/drawable-mdpi/panel_shadow.9.png differ diff --git a/Clover/app/src/main/res/drawable-xhdpi/panel_shadow.9.png b/Clover/app/src/main/res/drawable-xhdpi/panel_shadow.9.png new file mode 100644 index 00000000..a702c667 Binary files /dev/null and b/Clover/app/src/main/res/drawable-xhdpi/panel_shadow.9.png differ diff --git a/Clover/app/src/main/res/drawable-xxhdpi/panel_shadow.9.png b/Clover/app/src/main/res/drawable-xxhdpi/panel_shadow.9.png new file mode 100644 index 00000000..82091c3b Binary files /dev/null and b/Clover/app/src/main/res/drawable-xxhdpi/panel_shadow.9.png differ diff --git a/Clover/app/src/main/res/layout/controller_thread_slide.xml b/Clover/app/src/main/res/layout/controller_thread_slide.xml new file mode 100644 index 00000000..be45958c --- /dev/null +++ b/Clover/app/src/main/res/layout/controller_thread_slide.xml @@ -0,0 +1,34 @@ + + + + + + + + diff --git a/Clover/app/src/main/res/values/strings.xml b/Clover/app/src/main/res/values/strings.xml index 8cb0818b..d70c0826 100644 --- a/Clover/app/src/main/res/values/strings.xml +++ b/Clover/app/src/main/res/values/strings.xml @@ -358,6 +358,7 @@ along with this program. If not, see . Layout mode Auto Phone layout + Slide mode Split mode Font size (default)