diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/FavoritesScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/FavoritesScene.java index b8971d17f..bf8a4c953 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/FavoritesScene.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/FavoritesScene.java @@ -26,6 +26,7 @@ import android.graphics.Point; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.text.InputType; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.TextUtils; @@ -52,6 +53,8 @@ import com.github.amlcurran.showcaseview.targets.PointTarget; import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.hippo.android.resource.AttrResources; import com.hippo.annotation.Implemented; +import com.hippo.app.EditTextDialogBuilder; +import com.hippo.drawable.AddDeleteDrawable; import com.hippo.drawable.DrawerArrowDrawable; import com.hippo.easyrecyclerview.EasyRecyclerView; import com.hippo.easyrecyclerview.FastScroller; @@ -77,6 +80,7 @@ import com.hippo.refreshlayout.RefreshLayout; import com.hippo.ripple.Ripple; import com.hippo.scene.Announcer; import com.hippo.scene.SceneFragment; +import com.hippo.util.AppHelper; import com.hippo.util.DrawableManager; import com.hippo.widget.ContentLayout; import com.hippo.widget.FabLayout; @@ -93,7 +97,8 @@ import java.util.List; public class FavoritesScene extends BaseScene implements EasyRecyclerView.OnItemClickListener, EasyRecyclerView.OnItemLongClickListener, FastScroller.OnDragHandlerListener, SearchBarMover.Helper, SearchBar.Helper, - FabLayout.OnClickFabListener, EasyRecyclerView.CustomChoiceListener { + FabLayout.OnClickFabListener, FabLayout.OnExpandListener, + EasyRecyclerView.CustomChoiceListener { private static final long ANIMATE_TIME = 300L; @@ -124,6 +129,7 @@ public class FavoritesScene extends BaseScene implements @Nullable @ViewLifeCircle private DrawerArrowDrawable mLeftDrawable; + private AddDeleteDrawable mActionFabDrawable; @Nullable private EhDrawerLayout mDrawerLayout; @@ -281,10 +287,13 @@ public class FavoritesScene extends BaseScene implements updateSearchBar(); mSearchBarMover = new SearchBarMover(this, mSearchBar, mRecyclerView); + mActionFabDrawable = new AddDeleteDrawable(context, resources.getColor(R.color.primary_drawable_dark)); + mFabLayout.getPrimaryFab().setImageDrawable(mActionFabDrawable); mFabLayout.setExpanded(false, false); - mFabLayout.setAutoCancel(false); - mFabLayout.setHidePrimaryFab(true); + mFabLayout.setAutoCancel(true); + mFabLayout.setHidePrimaryFab(false); mFabLayout.setOnClickFabListener(this); + mFabLayout.setOnExpandListener(this); addAboveSnackView(mFabLayout); // Restore search mode @@ -542,6 +551,8 @@ public class FavoritesScene extends BaseScene implements if (mRecyclerView != null && mRecyclerView.isInCustomChoice()) { mRecyclerView.outOfCustomChoiceMode(); + } else if (mFabLayout != null && mFabLayout.isExpanded()) { + mFabLayout.toggle(); } else if (mSearchMode) { exitSearchMode(true); } else { @@ -737,19 +748,86 @@ public class FavoritesScene extends BaseScene implements onBackPressed(); } + @Override + public void onExpand(boolean expanded) { + if (expanded) { + mActionFabDrawable.setDelete(ANIMATE_TIME); + } else { + mActionFabDrawable.setAdd(ANIMATE_TIME); + } + } + @Override @Implemented(FabLayout.OnClickFabListener.class) public void onClickPrimaryFab(FabLayout view, FloatingActionButton fab) { - if (mRecyclerView != null) { - mRecyclerView.outOfCustomChoiceMode(); + if (mRecyclerView != null && mFabLayout != null) { + if (mRecyclerView.isInCustomChoice()) { + mRecyclerView.outOfCustomChoiceMode(); + } else { + mFabLayout.toggle(); + } } } + private void showGoToDialog() { + Context context = getContext2(); + if (null == context || null == mHelper) { + return; + } + + final int page = mHelper.getPageForTop(); + final int pages = mHelper.getPages(); + String hint = getString(R.string.go_to_hint, page + 1, pages); + final EditTextDialogBuilder builder = new EditTextDialogBuilder(context, null, hint); + builder.getEditText().setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL); + final AlertDialog dialog = builder.setTitle(R.string.go_to) + .setPositiveButton(android.R.string.ok, null) + .show(); + dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(v -> { + if (null == mHelper) { + dialog.dismiss(); + return; + } + + String text = builder.getText().trim(); + int goTo; + try { + goTo = Integer.parseInt(text) - 1; + } catch (NumberFormatException e){ + builder.setError(getString(R.string.error_invalid_number)); + return; + } + if (goTo < 0 || goTo >= pages) { + builder.setError(getString(R.string.error_out_of_range)); + return; + } + builder.setError(null); + mHelper.goTo(goTo); + AppHelper.hideSoftInput(dialog); + dialog.dismiss(); + }); + } + @Override @Implemented(FabLayout.OnClickFabListener.class) public void onClickSecondaryFab(FabLayout view, FloatingActionButton fab, int position) { Context context = getContext2(); - if (null == context || null == mRecyclerView || null == mHelper || !mRecyclerView.isInCustomChoice()) { + if (null == context || null == mRecyclerView || null == mHelper) { + return; + } + + if (!mRecyclerView.isInCustomChoice()) { + switch (position) { + case 0: // Go to + if (mHelper.canGoTo()) { + showGoToDialog(); + } + break; + case 1: // Refresh + mHelper.refresh(); + break; + } + view.setExpanded(false); return; } @@ -765,7 +843,7 @@ public class FavoritesScene extends BaseScene implements } switch (position) { - case 0: { // Download + case 2: { // Download Activity activity = getActivity2(); if (activity != null) { CommonOperations.startDownload(getActivity2(), mModifyGiList, false); @@ -776,7 +854,7 @@ public class FavoritesScene extends BaseScene implements } break; } - case 1: { // Delete + case 3: { // Delete DeleteDialogHelper helper = new DeleteDialogHelper(); new AlertDialog.Builder(context) .setTitle(R.string.delete_favorites_dialog_title) @@ -786,7 +864,7 @@ public class FavoritesScene extends BaseScene implements .show(); break; } - case 2: { // Move + case 4: { // Move MoveDialogHelper helper = new MoveDialogHelper(); // First is local favorite, the other 10 is cloud favorite String[] array = new String[11]; @@ -802,11 +880,45 @@ public class FavoritesScene extends BaseScene implements } } + private Runnable showNormalFabsRunnable = new Runnable() { + @Override + public void run() { + if (mFabLayout != null) { + mFabLayout.setSecondaryFabVisibilityAt(0, true); + mFabLayout.setSecondaryFabVisibilityAt(1, true); + mFabLayout.setSecondaryFabVisibilityAt(2, false); + mFabLayout.setSecondaryFabVisibilityAt(3, false); + mFabLayout.setSecondaryFabVisibilityAt(4, false); + } + } + }; + + private void showNormalFabs() { + // Delay showing normal fabs to avoid mutation + SimpleHandler.getInstance().removeCallbacks(showNormalFabsRunnable); + SimpleHandler.getInstance().postDelayed(showNormalFabsRunnable, 300); + } + + private void showSelectionFabs() { + SimpleHandler.getInstance().removeCallbacks(showNormalFabsRunnable); + + if (mFabLayout != null) { + mFabLayout.setSecondaryFabVisibilityAt(0, false); + mFabLayout.setSecondaryFabVisibilityAt(1, false); + mFabLayout.setSecondaryFabVisibilityAt(2, true); + mFabLayout.setSecondaryFabVisibilityAt(3, true); + mFabLayout.setSecondaryFabVisibilityAt(4, true); + } + } + @Override @Implemented(EasyRecyclerView.CustomChoiceListener.class) public void onIntoCustomChoice(EasyRecyclerView view) { if (mFabLayout != null) { - mFabLayout.setExpanded(true); + showSelectionFabs(); + mFabLayout.setAutoCancel(false); + // Delay expanding action to make layout work fine + SimpleHandler.getInstance().post(() -> mFabLayout.setExpanded(true)); } if (mHelper != null) { mHelper.setRefreshLayoutEnable(false); @@ -820,6 +932,8 @@ public class FavoritesScene extends BaseScene implements @Implemented(EasyRecyclerView.CustomChoiceListener.class) public void onOutOfCustomChoice(EasyRecyclerView view) { if (mFabLayout != null) { + showNormalFabs(); + mFabLayout.setAutoCancel(true); mFabLayout.setExpanded(false); } if (mHelper != null) { diff --git a/app/src/main/java/com/hippo/widget/FabLayout.java b/app/src/main/java/com/hippo/widget/FabLayout.java index 44d703637..cc8b7f672 100644 --- a/app/src/main/java/com/hippo/widget/FabLayout.java +++ b/app/src/main/java/com/hippo/widget/FabLayout.java @@ -105,6 +105,19 @@ public class FabLayout extends ViewGroup implements View.OnClickListener { return (FloatingActionButton) getChildAt(index); } + public void setSecondaryFabVisibilityAt(int index, boolean visible) { + View fab = getSecondaryFabAt(index); + if (fab != null) { + if (visible && fab.getVisibility() == View.GONE) { + fab.animate().cancel(); + fab.setVisibility(mExpanded ? View.VISIBLE : View.INVISIBLE); + } else if (!visible && fab.getVisibility() != View.GONE) { + fab.animate().cancel(); + fab.setVisibility(View.GONE); + } + } + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { AssertUtils.assertEquals("Measure mode must be MeasureSpec.EXACTLY", diff --git a/app/src/main/res/layout/scene_favorites.xml b/app/src/main/res/layout/scene_favorites.xml index e279d853d..89727bfc4 100644 --- a/app/src/main/res/layout/scene_favorites.xml +++ b/app/src/main/res/layout/scene_favorites.xml @@ -47,28 +47,44 @@ + + + + + style="@style/Widget.Design.FloatingActionButton.Mini" + android:visibility="gone"/> + style="@style/Widget.Design.FloatingActionButton.Mini" + android:visibility="gone"/>