diff --git a/Clover/app/src/main/java/org/floens/chan/core/presenter/ImageViewerPresenter.java b/Clover/app/src/main/java/org/floens/chan/core/presenter/ImageViewerPresenter.java index bfd58f69..e03ed749 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/presenter/ImageViewerPresenter.java +++ b/Clover/app/src/main/java/org/floens/chan/core/presenter/ImageViewerPresenter.java @@ -25,7 +25,6 @@ import org.floens.chan.core.model.Loadable; import org.floens.chan.core.model.PostImage; import org.floens.chan.core.settings.ChanSettings; import org.floens.chan.ui.view.MultiImageView; -import org.floens.chan.utils.Logger; import java.util.ArrayList; import java.util.List; @@ -188,8 +187,6 @@ public class ImageViewerPresenter implements MultiImageView.Callback, ViewPager. private void onLowResInCenter() { PostImage postImage = images.get(selectedPosition); - Logger.test("onLowResInCenter " + postImage.imageUrl); - if (imageAutoLoad(postImage) && !postImage.spoiler) { if (postImage.type == PostImage.Type.STATIC) { callback.setImageMode(postImage, MultiImageView.Mode.BIGIMAGE); 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 55692cbb..e7652857 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 @@ -17,8 +17,6 @@ */ package org.floens.chan.ui.layout; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; import android.annotation.SuppressLint; import android.app.Activity; import android.app.ProgressDialog; @@ -27,14 +25,12 @@ import android.content.ClipboardManager; import android.content.Context; import android.content.DialogInterface; import android.support.design.widget.CoordinatorLayout; -import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v7.app.AlertDialog; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; -import android.view.animation.DecelerateInterpolator; import android.widget.Button; import android.widget.CheckBox; import android.widget.LinearLayout; @@ -64,6 +60,7 @@ import org.floens.chan.ui.adapter.PostsFilter; import org.floens.chan.ui.cell.PostCellInterface; import org.floens.chan.ui.helper.PostPopupHelper; import org.floens.chan.ui.toolbar.Toolbar; +import org.floens.chan.ui.view.HidingFloatingActionButton; import org.floens.chan.ui.view.LoadView; import org.floens.chan.ui.view.ThumbnailView; import org.floens.chan.utils.AndroidUtils; @@ -92,7 +89,7 @@ public class ThreadLayout extends CoordinatorLayout implements ThreadPresenter.T private ThreadPresenter presenter; private LoadView loadView; - private FloatingActionButton replyButton; + private HidingFloatingActionButton replyButton; private ThreadListLayout threadListLayout; private LinearLayout errorLayout; @@ -126,10 +123,8 @@ public class ThreadLayout extends CoordinatorLayout implements ThreadPresenter.T presenter = new ThreadPresenter(this); - loadView = (LoadView) findViewById(R.id.loadview); - replyButton = (FloatingActionButton) findViewById(R.id.reply_button); - replyButton.setOnClickListener(this); + replyButton = (HidingFloatingActionButton) findViewById(R.id.reply_button); threadListLayout = (ThreadListLayout) LayoutInflater.from(getContext()).inflate(R.layout.layout_thread_list, this, false); threadListLayout.setCallbacks(presenter, presenter, presenter, presenter, this); @@ -146,6 +141,9 @@ public class ThreadLayout extends CoordinatorLayout implements ThreadPresenter.T replyButtonEnabled = ChanSettings.enableReplyFab.get(); if (!replyButtonEnabled) { AndroidUtils.removeFromParentView(replyButton); + } else { + replyButton.setOnClickListener(this); + replyButton.setToolbar(callback.getToolbar()); } switchVisible(Visible.LOADING); @@ -471,22 +469,11 @@ public class ThreadLayout extends CoordinatorLayout implements ThreadPresenter.T if (show != showingReplyButton && replyButtonEnabled) { showingReplyButton = show; - replyButton.animate() - .setInterpolator(new DecelerateInterpolator(2f)) - .setStartDelay(show ? 100 : 0) - .setDuration(200) - .alpha(show ? 1f : 0f) - .scaleX(show ? 1f : 0f) - .scaleY(show ? 1f : 0f) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationCancel(Animator animation) { - replyButton.setAlpha(show ? 1f : 0f); - replyButton.setScaleX(show ? 1f : 0f); - replyButton.setScaleY(show ? 1f : 0f); - } - }) - .start(); + if (show) { + replyButton.show(); + } else { + replyButton.hide(); + } } } 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 63bacac3..164c088d 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 @@ -46,6 +46,9 @@ import org.floens.chan.ui.view.FloatingMenu; import org.floens.chan.ui.view.LoadView; import org.floens.chan.utils.AndroidUtils; +import java.util.ArrayList; +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.setRoundItemBackground; @@ -83,6 +86,7 @@ public class Toolbar extends LinearLayout implements View.OnClickListener { private boolean openKeyboardAfterSearchViewCreated = false; private int lastScrollDeltaOffset; private int scrollOffset; + private List collapseCallbacks = new ArrayList<>(); private boolean transitioning = false; private NavigationItem fromItem; @@ -107,6 +111,14 @@ public class Toolbar extends LinearLayout implements View.OnClickListener { return getHeight() == 0 ? getLayoutParams().height : getHeight(); } + public void addCollapseCallback(ToolbarCollapseCallback callback) { + collapseCallbacks.add(callback); + } + + public void removeCollapseCallback(ToolbarCollapseCallback callback) { + collapseCallbacks.remove(callback); + } + public void processScrollCollapse(int offset) { processScrollCollapse(offset, false); } @@ -122,9 +134,18 @@ public class Toolbar extends LinearLayout implements View.OnClickListener { if (animated) { animate().translationY(-scrollOffset).setDuration(300).setInterpolator(new DecelerateInterpolator(2f)).start(); + + boolean collapse = scrollOffset > 0; + for (ToolbarCollapseCallback c : collapseCallbacks) { + c.onCollapseAnimation(collapse); + } } else { animate().cancel(); setTranslationY(-scrollOffset); + + for (ToolbarCollapseCallback c : collapseCallbacks) { + c.onCollapseTranslation(scrollOffset / (float) getHeight()); + } } } @@ -487,4 +508,10 @@ public class Toolbar extends LinearLayout implements View.OnClickListener { void onSearchEntered(NavigationItem item, String entered); } + + public interface ToolbarCollapseCallback { + void onCollapseTranslation(float offset); + + void onCollapseAnimation(boolean collapse); + } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/view/HidingFloatingActionButton.java b/Clover/app/src/main/java/org/floens/chan/ui/view/HidingFloatingActionButton.java new file mode 100644 index 00000000..f99e35a5 --- /dev/null +++ b/Clover/app/src/main/java/org/floens/chan/ui/view/HidingFloatingActionButton.java @@ -0,0 +1,136 @@ +/* + * 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.view; + +import android.content.Context; +import android.support.design.widget.CoordinatorLayout; +import android.support.design.widget.FloatingActionButton; +import android.support.design.widget.Snackbar; +import android.util.AttributeSet; +import android.view.ViewGroup; +import android.view.animation.DecelerateInterpolator; + +import org.floens.chan.ui.toolbar.Toolbar; + +public class HidingFloatingActionButton extends FloatingActionButton implements Toolbar.ToolbarCollapseCallback { + private boolean attachedToWindow; + private Toolbar toolbar; + private boolean attachedToToolbar; + private CoordinatorLayout coordinatorLayout; + private int currentCollapseTranslation; + + public HidingFloatingActionButton(Context context) { + super(context); + } + + public HidingFloatingActionButton(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public HidingFloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public void setToolbar(Toolbar toolbar) { + this.toolbar = toolbar; + + if (attachedToWindow && !attachedToToolbar) { + toolbar.addCollapseCallback(this); + attachedToToolbar = true; + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + attachedToWindow = true; + + if (!(getParent() instanceof CoordinatorLayout)) { + throw new IllegalArgumentException("HidingFloatingActionButton must be a parent of CoordinatorLayout"); + } + + coordinatorLayout = (CoordinatorLayout) getParent(); + + if (toolbar != null && !attachedToToolbar) { + toolbar.addCollapseCallback(this); + attachedToToolbar = true; + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + attachedToWindow = false; + if (attachedToToolbar) { + toolbar.removeCollapseCallback(this); + attachedToToolbar = false; + } + coordinatorLayout = null; + } + + @Override + public void onCollapseTranslation(float offset) { + if (isSnackbarShowing()) { + currentCollapseTranslation = -1; + return; + } + +// Logger.test("onCollapseTranslation " + offset); + + int translation = (int) (getTotalHeight() * offset); + if (translation != currentCollapseTranslation) { + currentCollapseTranslation = translation; + float diff = Math.abs(translation - getTranslationY()); + if (diff >= getHeight()) { + animate().translationY(translation).setDuration(300).setStartDelay(0).setInterpolator(new DecelerateInterpolator(2f)).start(); + } else { + setTranslationY(translation); + } + } + } + + @Override + public void onCollapseAnimation(boolean collapse) { + if (isSnackbarShowing()) { + currentCollapseTranslation = -1; + return; + } + +// Logger.test("onCollapseAnimation " + collapse); + + int translation = collapse ? getTotalHeight() : 0; + if (translation != currentCollapseTranslation) { + currentCollapseTranslation = translation; + animate().translationY(translation).setDuration(300).setStartDelay(0).setInterpolator(new DecelerateInterpolator(2f)).start(); + } + } + + private int getTotalHeight() { + return getHeight() + ((ViewGroup.MarginLayoutParams) getLayoutParams()).bottomMargin; + } + + private boolean isSnackbarShowing() { + for (int i = 0; i < coordinatorLayout.getChildCount(); i++) { + if (coordinatorLayout.getChildAt(i) instanceof Snackbar.SnackbarLayout) { + return true; + } + } + + return false; + } +} diff --git a/Clover/app/src/main/res/layout/layout_thread.xml b/Clover/app/src/main/res/layout/layout_thread.xml index 2f7422dc..67af46fd 100644 --- a/Clover/app/src/main/res/layout/layout_thread.xml +++ b/Clover/app/src/main/res/layout/layout_thread.xml @@ -25,15 +25,12 @@ along with this program. If not, see . android:layout_width="match_parent" android:layout_height="match_parent" /> -