diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/FavoritesScene.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/FavoritesScene.kt index 8c30b9532..ebdafb5fe 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/FavoritesScene.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/FavoritesScene.kt @@ -160,6 +160,8 @@ class FavoritesScene : SearchBarScene() { } } + override val fabLayout get() = binding.fabLayout + private fun onItemClick(position: Int) { // Skip if in search mode if (!tracker.isInCustomChoice) { @@ -191,6 +193,7 @@ class FavoritesScene : SearchBarScene() { } if (keyword.isNullOrEmpty()) { setSearchBarHint(getString(R.string.favorites_title, favCatName)) + setSearchBarText(null) } else { setSearchBarHint(getString(R.string.favorites_title_2, favCatName, keyword)) } @@ -439,6 +442,16 @@ class FavoritesScene : SearchBarScene() { } } + override fun onSearchViewExpanded() { + super.onSearchViewExpanded() + selectSearchFab(true) + } + + override fun onSearchViewHidden() { + super.onSearchViewHidden() + selectActionFab(true) + } + private fun showGoToDialog() { context ?: return val local = LocalDateTime.of(2007, 3, 21, 0, 0) @@ -528,5 +541,3 @@ class FavoritesScene : SearchBarScene() { } } } - -private const val ANIMATE_TIME = 300L diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt index 9afe9462d..2cfbfbd44 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt @@ -15,7 +15,6 @@ */ package com.hippo.ehviewer.ui.scene -import android.animation.Animator import android.content.Context import android.content.DialogInterface import android.os.Bundle @@ -100,7 +99,6 @@ import com.hippo.ehviewer.ui.tools.DialogState import com.hippo.ehviewer.updater.AppUpdater import com.hippo.ehviewer.util.AnimationUtils import com.hippo.ehviewer.util.ExceptionUtils -import com.hippo.ehviewer.util.SimpleAnimatorListener import com.hippo.ehviewer.util.getParcelableCompat import com.hippo.ehviewer.util.getValue import com.hippo.ehviewer.util.lazyMut @@ -110,6 +108,7 @@ import eu.kanade.tachiyomi.util.lang.launchUI import eu.kanade.tachiyomi.util.lang.withIOContext import eu.kanade.tachiyomi.util.lang.withUIContext import kotlinx.coroutines.delay +import kotlinx.coroutines.ensureActive import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch import kotlinx.parcelize.Parcelize @@ -194,23 +193,15 @@ class GalleryListScene : SearchBarScene() { } private var _binding: SceneGalleryListBinding? = null private val binding get() = _binding!! - private val mSearchFabAnimatorListener = object : SimpleAnimatorListener() { - override fun onAnimationEnd(animation: Animator) { - mSearchFab.visibility = View.INVISIBLE - } - } - private val mActionFabAnimatorListener = object : SimpleAnimatorListener() { - override fun onAnimationEnd(animation: Animator) { - binding.fabLayout.primaryFab?.visibility = View.INVISIBLE - } - } private var fabAnimator: ViewPropertyAnimator? = null private var mViewTransition: ViewTransition? = null private var mAdapter: GalleryAdapter? = null lateinit var mQuickSearchList: MutableList private var mHideActionFabSlop = 0 - private var mShowActionFab = true private var mState = State.NORMAL + + override val fabLayout get() = binding.fabLayout + override fun getMenuResId(): Int { return R.menu.scene_gallery_list_searchbar_menu } @@ -376,8 +367,8 @@ class GalleryListScene : SearchBarScene() { val empty = getString(R.string.gallery_list_empty_hit) val noWatch = getString(R.string.gallery_list_empty_hit_subscription) adapter.addLoadStateListener { - _binding ?: return@addLoadStateListener - lifecycleScope.launchUI { + viewLifecycleOwner.lifecycleScope.launchUI { + ensureActive() when (val state = it.refresh) { is LoadState.Loading -> { showSearchBar() @@ -459,12 +450,12 @@ class GalleryListScene : SearchBarScene() { override fun onClickSecondaryFab(view: FabLayout, fab: FloatingActionButton, position: Int) { when (position) { 0 -> showGoToDialog() - 1 -> { + 1 -> { // First mUrlBuilder.setIndex(null, true) mUrlBuilder.mJumpTo = null mAdapter?.refresh() } - 2 -> { + 2 -> { // Last if (mIsTopList) { mUrlBuilder.mJumpTo = "${TOPLIST_PAGES - 1}" mAdapter?.refresh() @@ -490,7 +481,6 @@ class GalleryListScene : SearchBarScene() { } binding.fabLayout.primaryFab!!.setImageDrawable(actionFabDrawable) addAboveSnackView(binding.fabLayout) - mSearchFab.setOnClickListener { onApplySearch() } // Update list url builder onUpdateUrlBuilder() @@ -747,70 +737,6 @@ class GalleryListScene : SearchBarScene() { } } - private fun selectSearchFab(animation: Boolean) { - _binding ?: return - mShowActionFab = false - if (animation) { - val fab: View? = binding.fabLayout.primaryFab - val delay: Long - if (View.INVISIBLE == fab!!.visibility) { - delay = 0L - } else { - delay = ANIMATE_TIME - binding.fabLayout.setExpanded(expanded = false, animation = true) - fab.animate().scaleX(0.0f).scaleY(0.0f).setListener(mActionFabAnimatorListener) - .setDuration(ANIMATE_TIME).setStartDelay(0L) - .setInterpolator(AnimationUtils.SLOW_FAST_INTERPOLATOR).start() - } - mSearchFab.visibility = View.VISIBLE - mSearchFab.rotation = -45.0f - mSearchFab.animate().scaleX(1.0f).scaleY(1.0f).rotation(0.0f).setListener(null) - .setDuration(ANIMATE_TIME).setStartDelay(delay) - .setInterpolator(AnimationUtils.FAST_SLOW_INTERPOLATOR).start() - } else { - binding.fabLayout.setExpanded(expanded = false, animation = false) - val fab: View? = binding.fabLayout.primaryFab - fab!!.visibility = View.INVISIBLE - fab.scaleX = 0.0f - fab.scaleY = 0.0f - mSearchFab.visibility = View.VISIBLE - mSearchFab.scaleX = 1.0f - mSearchFab.scaleY = 1.0f - } - } - - private fun selectActionFab(animation: Boolean) { - _binding ?: return - mShowActionFab = true - if (animation) { - val delay: Long - if (View.INVISIBLE == mSearchFab.visibility) { - delay = 0L - } else { - delay = ANIMATE_TIME - mSearchFab.animate().scaleX(0.0f).scaleY(0.0f) - .setListener(mSearchFabAnimatorListener) - .setDuration(ANIMATE_TIME).setStartDelay(0L) - .setInterpolator(AnimationUtils.SLOW_FAST_INTERPOLATOR).start() - } - val fab: View? = binding.fabLayout.primaryFab - fab!!.visibility = View.VISIBLE - fab.rotation = -45.0f - fab.animate().scaleX(1.0f).scaleY(1.0f).rotation(0.0f).setListener(null) - .setDuration(ANIMATE_TIME).setStartDelay(delay) - .setInterpolator(AnimationUtils.FAST_SLOW_INTERPOLATOR).start() - } else { - binding.fabLayout.setExpanded(expanded = false, animation = false) - val fab: View? = binding.fabLayout.primaryFab - fab!!.visibility = View.VISIBLE - fab.scaleX = 1.0f - fab.scaleY = 1.0f - mSearchFab.visibility = View.INVISIBLE - mSearchFab.scaleX = 0.0f - mSearchFab.scaleY = 0.0f - } - } - private fun setState(state: State) { setState(state, true) } @@ -1072,7 +998,6 @@ class GalleryListScene : SearchBarScene() { const val ACTION_LIST_URL_BUILDER = "action_list_url_builder" const val KEY_LIST_URL_BUILDER = "list_url_builder" const val KEY_STATE = "state" - private const val ANIMATE_TIME = 300L fun ListUrlBuilder.toStartArgs() = bundleOf( KEY_ACTION to ACTION_LIST_URL_BUILDER, KEY_LIST_URL_BUILDER to this, diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/SearchBarScene.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/SearchBarScene.kt index d9bc1ff09..1de4690aa 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/SearchBarScene.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/SearchBarScene.kt @@ -1,5 +1,6 @@ package com.hippo.ehviewer.ui.scene +import android.animation.Animator import android.os.Bundle import android.view.LayoutInflater import android.view.MenuItem @@ -40,7 +41,10 @@ import com.hippo.ehviewer.dao.Search import com.hippo.ehviewer.dao.SearchDao import com.hippo.ehviewer.databinding.SceneSearchbarBinding import com.hippo.ehviewer.ui.legacy.BaseDialogBuilder +import com.hippo.ehviewer.ui.legacy.FabLayout import com.hippo.ehviewer.ui.setMD3Content +import com.hippo.ehviewer.util.AnimationUtils +import com.hippo.ehviewer.util.SimpleAnimatorListener import com.jamal.composeprefs3.ui.ifNotNullThen import com.jamal.composeprefs3.ui.ifTrueThen import eu.kanade.tachiyomi.util.lang.launchIO @@ -57,6 +61,18 @@ abstract class SearchBarScene : BaseScene(), ToolBarScene { private val mSearchDatabase = searchDatabase.searchDao() private var onApplySearch: (String) -> Unit = {} protected val mSearchFab get() = binding.searchFab + protected abstract val fabLayout: FabLayout + protected var mShowActionFab = true + protected val mActionFabAnimatorListener = object : SimpleAnimatorListener() { + override fun onAnimationEnd(animation: Animator) { + fabLayout.primaryFab?.visibility = View.INVISIBLE + } + } + private val mSearchFabAnimatorListener = object : SimpleAnimatorListener() { + override fun onAnimationEnd(animation: Animator) { + mSearchFab.visibility = View.INVISIBLE + } + } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { _binding = SceneSearchbarBinding.inflate(inflater, container, false) @@ -99,6 +115,7 @@ abstract class SearchBarScene : BaseScene(), ToolBarScene { onSearchViewHidden() } } + mSearchFab.setOnClickListener { onApplySearch() } onCreateViewWithToolbar(inflater, binding.root, savedInstanceState) // This has to be placed after onCreateViewWithToolbar() since // callbacks are invoked in the reverse order in which they are added @@ -147,6 +164,70 @@ abstract class SearchBarScene : BaseScene(), ToolBarScene { privLockModeStart = null } + fun selectSearchFab(animation: Boolean) { + _binding ?: return + mShowActionFab = false + if (animation) { + val fab: View? = fabLayout.primaryFab + val delay: Long + if (View.INVISIBLE == fab!!.visibility) { + delay = 0L + } else { + delay = ANIMATE_TIME + fabLayout.setExpanded(expanded = false, animation = true) + fab.animate().scaleX(0.0f).scaleY(0.0f).setListener(mActionFabAnimatorListener) + .setDuration(ANIMATE_TIME).setStartDelay(0L) + .setInterpolator(AnimationUtils.SLOW_FAST_INTERPOLATOR).start() + } + mSearchFab.visibility = View.VISIBLE + mSearchFab.rotation = -45.0f + mSearchFab.animate().scaleX(1.0f).scaleY(1.0f).rotation(0.0f).setListener(null) + .setDuration(ANIMATE_TIME).setStartDelay(delay) + .setInterpolator(AnimationUtils.FAST_SLOW_INTERPOLATOR).start() + } else { + fabLayout.setExpanded(expanded = false, animation = false) + val fab = fabLayout.primaryFab!! + fab.visibility = View.INVISIBLE + fab.scaleX = 0.0f + fab.scaleY = 0.0f + mSearchFab.visibility = View.VISIBLE + mSearchFab.scaleX = 1.0f + mSearchFab.scaleY = 1.0f + } + } + + fun selectActionFab(animation: Boolean) { + _binding ?: return + mShowActionFab = true + if (animation) { + val delay: Long + if (View.INVISIBLE == mSearchFab.visibility) { + delay = 0L + } else { + delay = ANIMATE_TIME + mSearchFab.animate().scaleX(0.0f).scaleY(0.0f) + .setListener(mSearchFabAnimatorListener) + .setDuration(ANIMATE_TIME).setStartDelay(0L) + .setInterpolator(AnimationUtils.SLOW_FAST_INTERPOLATOR).start() + } + val fab = fabLayout.primaryFab!! + fab.visibility = View.VISIBLE + fab.rotation = -45.0f + fab.animate().scaleX(1.0f).scaleY(1.0f).rotation(0.0f).setListener(null) + .setDuration(ANIMATE_TIME).setStartDelay(delay) + .setInterpolator(AnimationUtils.FAST_SLOW_INTERPOLATOR).start() + } else { + fabLayout.setExpanded(expanded = false, animation = false) + val fab = fabLayout.primaryFab!! + fab.visibility = View.VISIBLE + fab.scaleX = 1.0f + fab.scaleY = 1.0f + mSearchFab.visibility = View.INVISIBLE + mSearchFab.scaleX = 0.0f + mSearchFab.scaleY = 0.0f + } + } + fun setSearchBarHint(hint: String?) { binding.toolbar.hint = hint } @@ -329,3 +410,5 @@ fun wrapTagKeyword(keyword: String, translate: Boolean = false): String { } } } + +const val ANIMATE_TIME = 300L