From 6e00a4133c48afb0ea491a04ab5be7cb44a5bdcc Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Sat, 12 Aug 2023 17:16:08 +0800 Subject: [PATCH 1/8] Fix nav checked item --- .../androidx/navigation/ui/NavigationUI.kt | 1 - .../com/hippo/ehviewer/ui/MainActivity.kt | 6 ++- .../ehviewer/ui/scene/GalleryListScene.kt | 37 +++++++++++-------- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/androidx/navigation/ui/NavigationUI.kt b/app/src/main/java/androidx/navigation/ui/NavigationUI.kt index f51c9aabb..9669c0994 100644 --- a/app/src/main/java/androidx/navigation/ui/NavigationUI.kt +++ b/app/src/main/java/androidx/navigation/ui/NavigationUI.kt @@ -11,7 +11,6 @@ import androidx.navigation.NavOptions @SuppressLint("PrivateResource") fun onNavDestinationSelected2(item: MenuItem, navController: NavController): Boolean { - if (navController.currentDestination?.matchDestination(item.itemId) == true) return true val builder = NavOptions.Builder().setLaunchSingleTop(true) if ( navController.currentDestination!!.parent!!.findNode(item.itemId) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.kt b/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.kt index 88c4ae759..035a51421 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.kt @@ -197,7 +197,7 @@ class MainActivity : EhActivity() { // Trick: Tweak NavigationUI to disable multiple backstack binding.navView.setNavigationItemSelectedListener { val navigationView = binding.navView - val handled = onNavDestinationSelected2(it, navController) + val handled = navigationView.checkedItem?.itemId == it.itemId || onNavDestinationSelected2(it, navController) if (handled) { val parent = navigationView.parent if (parent is Openable) { @@ -398,6 +398,10 @@ class MainActivity : EhActivity() { } } + fun clearNavCheckedItem() { + binding.navView.setCheckedItem(R.id.nav_stub) + } + fun showTip(@StringRes id: Int, length: Int, useToast: Boolean = false) { showTip(getString(id), length, useToast) } 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 e24f6bacd..0d3e8001b 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 @@ -66,10 +66,12 @@ import com.hippo.ehviewer.client.EhUrl import com.hippo.ehviewer.client.EhUtils import com.hippo.ehviewer.client.data.BaseGalleryInfo import com.hippo.ehviewer.client.data.ListUrlBuilder +import com.hippo.ehviewer.client.data.ListUrlBuilder.Companion.MODE_IMAGE_SEARCH import com.hippo.ehviewer.client.data.ListUrlBuilder.Companion.MODE_NORMAL import com.hippo.ehviewer.client.data.ListUrlBuilder.Companion.MODE_SUBSCRIPTION import com.hippo.ehviewer.client.data.ListUrlBuilder.Companion.MODE_TAG import com.hippo.ehviewer.client.data.ListUrlBuilder.Companion.MODE_TOPLIST +import com.hippo.ehviewer.client.data.ListUrlBuilder.Companion.MODE_UPLOADER import com.hippo.ehviewer.client.data.ListUrlBuilder.Companion.MODE_WHATS_HOT import com.hippo.ehviewer.client.exception.CloudflareBypassException import com.hippo.ehviewer.client.exception.EhException @@ -156,7 +158,7 @@ class VMStorage1 : ViewModel() { } } val r = runSuspendCatching { - if (ListUrlBuilder.MODE_IMAGE_SEARCH == urlBuilder.mode) { + if (MODE_IMAGE_SEARCH == urlBuilder.mode) { EhEngine.imageSearch( File(urlBuilder.imagePath!!), urlBuilder.isUseSimilarityScan, @@ -295,6 +297,14 @@ class GalleryListScene : SearchBarScene() { title = resources.getString(R.string.search) } setSearchBarHint(title) + + when (mode) { + MODE_NORMAL -> if (category != EhUtils.NONE || !keyword.isNullOrEmpty()) { + mainActivity?.clearNavCheckedItem() + } + MODE_TAG, MODE_UPLOADER, MODE_IMAGE_SEARCH -> mainActivity?.clearNavCheckedItem() + else -> Unit + } } private val dialogState = DialogState() @@ -520,7 +530,7 @@ class GalleryListScene : SearchBarScene() { val context = context ?: return // Can't add image search as quick search - if (ListUrlBuilder.MODE_IMAGE_SEARCH == mUrlBuilder.mode) { + if (MODE_IMAGE_SEARCH == mUrlBuilder.mode) { showTip(R.string.image_search_not_quick_search, LENGTH_LONG) return } @@ -899,26 +909,21 @@ class GalleryListScene : SearchBarScene() { private inner class QsDrawerAdapter(private val mInflater: LayoutInflater) : RecyclerView.Adapter() { + private val keywords = intArrayOf(11, 12, 13, 15) + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): QsDrawerHolder { val holder = QsDrawerHolder(ItemDrawerListBinding.inflate(mInflater, parent, false)) - if (!mIsTopList) { - holder.itemView.setOnClickListener { + holder.itemView.setOnClickListener { + if (!mIsTopList) { val q = mQuickSearchList[holder.bindingAdapterPosition] mUrlBuilder.set(q) - onUpdateUrlBuilder() - mAdapter?.refresh() - setState(State.NORMAL) - closeSideSheet() - } - } else { - val keywords = intArrayOf(11, 12, 13, 15) - holder.itemView.setOnClickListener { + } else { mUrlBuilder.keyword = keywords[holder.bindingAdapterPosition].toString() - onUpdateUrlBuilder() - mAdapter?.refresh() - setState(State.NORMAL) - closeSideSheet() } + onUpdateUrlBuilder() + mAdapter?.refresh() + setState(State.NORMAL) + closeSideSheet() } return holder } From c34ba56896802def8c23ae4ee460ab2a5a3144bb Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Sat, 12 Aug 2023 22:47:20 +0800 Subject: [PATCH 2/8] Start a new fragment if search was performed from Popular or Toplist --- .../ehviewer/ui/scene/GalleryListScene.kt | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) 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 0d3e8001b..148f18855 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 @@ -225,7 +225,6 @@ class GalleryListScene : SearchBarScene() { ACTION_LIST_URL_BUILDER -> args?.getParcelableCompat(KEY_LIST_URL_BUILDER)?.copy() ?: ListUrlBuilder() else -> throw IllegalStateException("Wrong KEY_ACTION:${args?.getString(KEY_ACTION)} when handle args!") } - args?.getString(KEY_GOTO)?.let { mUrlBuilder.mNext = it } } override fun onCreate(savedInstanceState: Bundle?) { @@ -268,10 +267,7 @@ class GalleryListScene : SearchBarScene() { val category = mUrlBuilder.category val mode = mUrlBuilder.mode val isPopular = mode == MODE_WHATS_HOT - val isTopList = mode == MODE_TOPLIST - if (isTopList != mIsTopList) { - mIsTopList = isTopList - } + mIsTopList = mode == MODE_TOPLIST // Update fab visibility binding.fabLayout.setSecondaryFabVisibilityAt(0, !isPopular) @@ -380,6 +376,7 @@ 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 { when (val state = it.refresh) { is LoadState.Loading -> { @@ -873,24 +870,35 @@ class GalleryListScene : SearchBarScene() { private fun onApplySearch(query: String?) { _binding ?: return lifecycleScope.launchIO { + val builder = ListUrlBuilder() + val oldMode = mUrlBuilder.mode if (mState == State.SEARCH || mState == State.SEARCH_SHOW_LIST) { try { - binding.searchLayout.formatListUrlBuilder(mUrlBuilder, query) + binding.searchLayout.formatListUrlBuilder(builder, query) } catch (e: EhException) { showTip(e.message, LENGTH_LONG) return@launchIO } } else { - val oldMode = mUrlBuilder.mode // If it's MODE_SUBSCRIPTION, keep it val newMode = if (oldMode == MODE_SUBSCRIPTION) MODE_SUBSCRIPTION else MODE_NORMAL - mUrlBuilder.reset() - mUrlBuilder.mode = newMode - mUrlBuilder.keyword = query + builder.mode = newMode + builder.keyword = query } withUIContext { - onUpdateUrlBuilder() - mAdapter?.refresh() + when (oldMode) { + MODE_TOPLIST, MODE_WHATS_HOT -> { + // Wait for search view to hide + delay(300) + navAnimated(R.id.galleryListScene, builder.toStartArgs()) + } + + else -> { + mUrlBuilder = builder + onUpdateUrlBuilder() + mAdapter?.refresh() + } + } setState(State.NORMAL) } } @@ -916,12 +924,13 @@ class GalleryListScene : SearchBarScene() { holder.itemView.setOnClickListener { if (!mIsTopList) { val q = mQuickSearchList[holder.bindingAdapterPosition] - mUrlBuilder.set(q) + // Navigate to galleryListScene to clear nav checked item + navAnimated(R.id.galleryListScene, ListUrlBuilder().apply { set(q) }.toStartArgs()) } else { mUrlBuilder.keyword = keywords[holder.bindingAdapterPosition].toString() + onUpdateUrlBuilder() + mAdapter?.refresh() } - onUpdateUrlBuilder() - mAdapter?.refresh() setState(State.NORMAL) closeSideSheet() } @@ -1053,7 +1062,6 @@ class GalleryListScene : SearchBarScene() { companion object { const val KEY_ACTION = "action" - const val KEY_GOTO = "goto" const val ACTION_HOMEPAGE = "action_homepage" const val ACTION_SUBSCRIPTION = "action_subscription" const val ACTION_WHATS_HOT = "action_whats_hot" From fd45319715fd162bc3765f61d7d965edb864d07a Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Sun, 13 Aug 2023 00:14:44 +0800 Subject: [PATCH 3/8] Fix toplist --- .../ehviewer/client/data/ListUrlBuilder.kt | 4 ++-- .../ehviewer/ui/scene/GalleryListScene.kt | 19 ++++++++++++------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/hippo/ehviewer/client/data/ListUrlBuilder.kt b/app/src/main/java/com/hippo/ehviewer/client/data/ListUrlBuilder.kt index bd21ec468..138d9e1d3 100644 --- a/app/src/main/java/com/hippo/ehviewer/client/data/ListUrlBuilder.kt +++ b/app/src/main/java/com/hippo/ehviewer/client/data/ListUrlBuilder.kt @@ -70,8 +70,8 @@ data class ListUrlBuilder( mPrev = index?.takeUnless { isNext } } - fun setJumpTo(jumpTo: String?) { - mJumpTo = jumpTo + fun setJumpTo(jumpTo: Int) { + mJumpTo = jumpTo.takeUnless { it == 0 }?.toString() } var keyword: String? 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 148f18855..9afe9462d 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 @@ -132,10 +132,10 @@ class VMStorage1 : ViewModel() { if (urlBuilder.mode == MODE_TOPLIST) { // TODO: Since we know total pages, let pager support jump val key = (params.key ?: urlBuilder.mJumpTo ?: "0").toInt() - val prev = if (key != 0) key - 1 else null - val next = if (key != 199) key + 1 else null + val prev = (key - 1).takeIf { it > 0 } + val next = (key + 1).takeIf { it < TOPLIST_PAGES } runSuspendCatching { - urlBuilder.setJumpTo(key.toString()) + urlBuilder.setJumpTo(key) EhEngine.getGalleryList(urlBuilder.build()) }.onFailure { return@withIOContext LoadResult.Error(it) @@ -461,10 +461,12 @@ class GalleryListScene : SearchBarScene() { 0 -> showGoToDialog() 1 -> { mUrlBuilder.setIndex(null, true) + mUrlBuilder.mJumpTo = null mAdapter?.refresh() } 2 -> { if (mIsTopList) { + mUrlBuilder.mJumpTo = "${TOPLIST_PAGES - 1}" mAdapter?.refresh() } else { mUrlBuilder.setIndex("1", false) @@ -651,9 +653,9 @@ class GalleryListScene : SearchBarScene() { private fun showGoToDialog() { mAdapter ?: return if (mIsTopList) { - val pages = 200 + val page = mUrlBuilder.mJumpTo?.toIntOrNull() ?: 0 val title = getString(R.string.go_to) - val hint = getString(R.string.go_to_hint, 1, 200) + val hint = getString(R.string.go_to_hint, page + 1, TOPLIST_PAGES) lifecycleScope.launch { val text = dialogState.awaitInputText( title = title, @@ -666,13 +668,13 @@ class GalleryListScene : SearchBarScene() { }.onFailure { return@awaitInputText getString(R.string.error_invalid_number) }.getOrThrow() - if (goTo < 0 || goTo >= pages) { + if (goTo !in 0.. Date: Sun, 13 Aug 2023 18:54:53 +0800 Subject: [PATCH 4/8] Show search fab in FavoritesScene --- .../hippo/ehviewer/ui/scene/FavoritesScene.kt | 15 ++- .../ehviewer/ui/scene/GalleryListScene.kt | 91 ++----------------- .../hippo/ehviewer/ui/scene/SearchBarScene.kt | 83 +++++++++++++++++ 3 files changed, 104 insertions(+), 85 deletions(-) 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 From 69a26aeedb3317a2473d747e27a10f712d46c018 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Sun, 13 Aug 2023 22:51:05 +0800 Subject: [PATCH 5/8] Implement swipe-to-remove in Downloads and Favorites --- .../com/hippo/ehviewer/ui/CommonOperations.kt | 37 +++++++++++++++---- .../hippo/ehviewer/ui/scene/DownloadsScene.kt | 25 +++++++++---- .../hippo/ehviewer/ui/scene/FavoritesScene.kt | 36 ++++++++++++++++++ .../com/hippo/ehviewer/ui/tools/Dialog.kt | 11 +++++- 4 files changed, 92 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/CommonOperations.kt b/app/src/main/java/com/hippo/ehviewer/ui/CommonOperations.kt index c33006506..a80af410a 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/CommonOperations.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/CommonOperations.kt @@ -20,6 +20,8 @@ import android.content.Context import android.content.Intent import android.os.Build import androidx.appcompat.app.AlertDialog +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Download @@ -28,7 +30,12 @@ import androidx.compose.material.icons.filled.Favorite import androidx.compose.material.icons.filled.FavoriteBorder import androidx.compose.material.icons.filled.HeartBroken import androidx.compose.material.icons.filled.MenuBook +import androidx.compose.material3.Checkbox import androidx.compose.material3.Text +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.res.stringResource import androidx.core.content.ContextCompat import com.hippo.ehviewer.EhDB @@ -55,6 +62,7 @@ import com.hippo.ehviewer.util.requestPermission import com.hippo.unifile.UniFile import eu.kanade.tachiyomi.ui.reader.ReaderActivity import eu.kanade.tachiyomi.util.lang.launchNow +import eu.kanade.tachiyomi.util.lang.withIOContext import eu.kanade.tachiyomi.util.lang.withUIContext import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.sync.Mutex @@ -312,7 +320,6 @@ suspend fun DialogState.doGalleryInfoAction(info: BaseGalleryInfo, context: Cont 1 -> withUIContext { if (downloaded) { confirmRemoveDownload(info) - DownloadManager.deleteDownload(info.gid) } else { CommonOperations.startDownload(this@with, info, false) } @@ -342,12 +349,28 @@ suspend fun DialogState.doGalleryInfoAction(info: BaseGalleryInfo, context: Cont private const val MAX_FAVNOTE_CHAR = 200 -suspend fun DialogState.confirmRemoveDownload(info: GalleryInfo) = awaitPermissionOrCancel( - confirmText = android.R.string.ok, - dismissText = android.R.string.cancel, - title = R.string.download_remove_dialog_title, - text = { Text(text = stringResource(id = R.string.download_remove_dialog_message, info.title.orEmpty())) }, -) +suspend fun DialogState.confirmRemoveDownload(info: GalleryInfo, onDismiss: () -> Unit = {}) { + var checked by mutableStateOf(Settings.removeImageFiles) + awaitPermissionOrCancel( + confirmText = android.R.string.ok, + dismissText = android.R.string.cancel, + title = R.string.download_remove_dialog_title, + onDismiss = onDismiss, + text = { + Column { + Text(text = stringResource(id = R.string.download_remove_dialog_message, info.title.orEmpty())) + Row(verticalAlignment = Alignment.CenterVertically) { + Checkbox(checked = checked, onCheckedChange = { checked = it }) + Text(text = stringResource(id = R.string.download_remove_dialog_check_text)) + } + } + }, + ) + Settings.removeImageFiles = checked + withIOContext { + DownloadManager.deleteDownload(info.gid, checked) + } +} suspend fun DialogState.showMoveDownloadLabel(info: GalleryInfo) { val defaultLabel = appCtx.getString(R.string.default_download_label_name) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/DownloadsScene.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/DownloadsScene.kt index 9cd427282..205afa326 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/DownloadsScene.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/DownloadsScene.kt @@ -47,6 +47,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp @@ -58,7 +59,6 @@ import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper.ACTION_STATE_DRAG import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView -import androidx.recyclerview.widget.SimpleItemAnimator import androidx.recyclerview.widget.StaggeredGridLayoutManager import arrow.core.partially1 import coil.compose.AsyncImage @@ -84,6 +84,7 @@ import com.hippo.ehviewer.download.DownloadService import com.hippo.ehviewer.download.DownloadService.Companion.clear import com.hippo.ehviewer.download.downloadDir import com.hippo.ehviewer.ktbuilder.imageRequest +import com.hippo.ehviewer.ui.confirmRemoveDownload import com.hippo.ehviewer.ui.legacy.AutoStaggeredGridLayoutManager import com.hippo.ehviewer.ui.legacy.BaseDialogBuilder import com.hippo.ehviewer.ui.legacy.CheckBoxDialogBuilder @@ -98,6 +99,7 @@ import com.hippo.ehviewer.ui.main.requestOf import com.hippo.ehviewer.ui.navToReader import com.hippo.ehviewer.ui.setMD3Content import com.hippo.ehviewer.ui.tools.CropDefaults +import com.hippo.ehviewer.ui.tools.DialogState import com.hippo.ehviewer.util.FileUtils import com.hippo.ehviewer.util.LongList import com.hippo.ehviewer.util.sendTo @@ -137,6 +139,8 @@ class DownloadsScene : private lateinit var mLabels: MutableList private var mType = -1 + private val dialogState = DialogState() + private fun initLabels() { context ?: return val listLabel = downloadManager.labelList @@ -247,6 +251,7 @@ class DownloadsScene : savedInstanceState: Bundle?, ): View { _binding = SceneDownloadBinding.inflate(inflater, container!!) + container.addView(ComposeView(inflater.context).apply { setMD3Content { dialogState.Intercept() } }) binding.run { setLiftOnScrollTargetView(recyclerView) mViewTransition = ViewTransition(content, tip) @@ -288,11 +293,6 @@ class DownloadsScene : recyclerView.layoutManager = layoutManager recyclerView.clipToPadding = false recyclerView.clipChildren = false - // Cancel change animation - val itemAnimator = recyclerView.itemAnimator - if (itemAnimator is SimpleItemAnimator) { - itemAnimator.supportsChangeAnimations = false - } val interval = resources.getDimensionPixelOffset(R.dimen.gallery_list_interval) val decoration = object : RecyclerView.ItemDecoration() { override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { @@ -313,7 +313,7 @@ class DownloadsScene : } override fun isLongPressDragEnabled() = false override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int { - return makeMovementFlags(ItemTouchHelper.UP or ItemTouchHelper.DOWN, 0) + return makeMovementFlags(ItemTouchHelper.UP or ItemTouchHelper.DOWN, ItemTouchHelper.LEFT) } override fun onMove( recyclerView: RecyclerView, @@ -336,7 +336,16 @@ class DownloadsScene : } return true } - override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {} + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { + val position = viewHolder.bindingAdapterPosition + val info = mList!![position] + lifecycleScope.launchUI { + dialogState.confirmRemoveDownload(info) { + mAdapter!!.notifyItemChanged(position) + } + mAdapter!!.notifyItemRemoved(position) + } + } }) mItemTouchHelper!!.attachToRecyclerView(recyclerView) fastScroller.attachToRecyclerView(recyclerView) 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 ebdafb5fe..7ef0c2b4e 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 @@ -51,6 +51,8 @@ import androidx.paging.PagingConfig import androidx.paging.PagingSource import androidx.paging.PagingState import androidx.paging.cachedIn +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.RecyclerView import com.google.android.material.datepicker.CalendarConstraints import com.google.android.material.datepicker.CalendarConstraints.DateValidator import com.google.android.material.datepicker.CompositeDateValidator @@ -78,6 +80,7 @@ import com.hippo.ehviewer.ui.legacy.HandlerDrawable import com.hippo.ehviewer.ui.legacy.ViewTransition import com.hippo.ehviewer.ui.legacy.WindowInsetsAnimationHelper import com.hippo.ehviewer.ui.setMD3Content +import com.hippo.ehviewer.ui.tools.DialogState import com.hippo.ehviewer.util.ExceptionUtils import com.hippo.ehviewer.util.SimpleHandler import com.hippo.ehviewer.util.getValue @@ -160,6 +163,8 @@ class FavoritesScene : SearchBarScene() { } } + private val dialogState = DialogState() + override val fabLayout get() = binding.fabLayout private fun onItemClick(position: Int) { @@ -225,6 +230,7 @@ class FavoritesScene : SearchBarScene() { savedInstanceState: Bundle?, ): View { _binding = SceneFavoritesBinding.inflate(inflater, container!!) + container.addView(ComposeView(inflater.context).apply { setMD3Content { dialogState.Intercept() } }) setOnApplySearch { if (!tracker.isInCustomChoice) { switchFav(urlBuilder.favCat, it) @@ -384,6 +390,36 @@ class FavoritesScene : SearchBarScene() { } switchFav(Settings.recentFavCat) } + val itemTouchHelper = ItemTouchHelper(object : ItemTouchHelper.Callback() { + override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int { + return makeMovementFlags(0, ItemTouchHelper.LEFT) + } + override fun onMove( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + target: RecyclerView.ViewHolder, + ) = false + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { + val position = viewHolder.bindingAdapterPosition + val info = mAdapter!!.peek(position)!! + lifecycleScope.launchIO { + dialogState.awaitPermissionOrCancel( + confirmText = R.string.delete, + dismissText = android.R.string.cancel, + title = R.string.delete_favorites_dialog_title, + onDismiss = { mAdapter!!.notifyItemChanged(position) }, + ) { + Text(text = stringResource(id = R.string.delete_favorites_dialog_message, 1)) + } + if (urlBuilder.favCat == FavListUrlBuilder.FAV_CAT_LOCAL) { + EhDB.removeLocalFavorites(info) + } else { + EhEngine.modifyFavorites(info.gid, info.token) + } + } + } + }) + itemTouchHelper.attachToRecyclerView(binding.recyclerView) allowEmptySearch = false return binding.root } diff --git a/app/src/main/java/com/hippo/ehviewer/ui/tools/Dialog.kt b/app/src/main/java/com/hippo/ehviewer/ui/tools/Dialog.kt index 39e224e37..bb99fec6e 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/tools/Dialog.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/tools/Dialog.kt @@ -148,18 +148,25 @@ class DialogState { @StringRes confirmText: Int? = null, @StringRes dismissText: Int? = null, @StringRes title: Int? = null, + onDismiss: () -> Unit = {}, text: (@Composable () -> Unit)? = null, ) { return dialog { cont -> AlertDialog( - onDismissRequest = { cont.cancel() }, + onDismissRequest = { + onDismiss() + cont.cancel() + }, confirmButton = { TextButton(onClick = { cont.resume(Unit) }) { Text(text = stringResource(id = confirmText ?: android.R.string.ok)) } }, dismissButton = dismissText.ifNotNullThen { - TextButton(onClick = { cont.cancel() }) { + TextButton(onClick = { + onDismiss() + cont.cancel() + }) { Text(text = stringResource(id = dismissText!!)) } }, From 1034fcd7b012ece882077c677cab2805c705316f Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Mon, 14 Aug 2023 17:57:55 +0800 Subject: [PATCH 6/8] Fix favorite button color --- .../java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.kt index 8d3b081a8..d012ec689 100755 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.kt @@ -68,7 +68,6 @@ import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.FilledTonalButton -import androidx.compose.material3.FilledTonalIconToggleButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.LargeTopAppBar @@ -159,6 +158,7 @@ import com.hippo.ehviewer.ui.setMD3Content import com.hippo.ehviewer.ui.tools.CrystalCard import com.hippo.ehviewer.ui.tools.DialogState import com.hippo.ehviewer.ui.tools.FilledTertiaryIconButton +import com.hippo.ehviewer.ui.tools.FilledTertiaryIconToggleButton import com.hippo.ehviewer.ui.tools.GalleryDetailRating import com.hippo.ehviewer.util.AppHelper import com.hippo.ehviewer.util.ExceptionUtils @@ -712,7 +712,7 @@ class GalleryDetailScene : BaseScene() { stringResource(id = R.string.not_favorited) } Column(horizontalAlignment = Alignment.CenterHorizontally) { - FilledTonalIconToggleButton( + FilledTertiaryIconToggleButton( checked = favored, onCheckedChange = { modifyFavourite() }, ) { From aa8adfb6f7df0c74c070a34ed9983a8ab72a0133 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Mon, 14 Aug 2023 23:10:32 +0800 Subject: [PATCH 7/8] Use LazyColumn in showSelectItem() --- .../com/hippo/ehviewer/ui/tools/Dialog.kt | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/tools/Dialog.kt b/app/src/main/java/com/hippo/ehviewer/ui/tools/Dialog.kt index bb99fec6e..e5d6994d5 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/tools/Dialog.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/tools/Dialog.kt @@ -3,12 +3,10 @@ package com.hippo.ehviewer.ui.tools import androidx.annotation.StringRes import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed @@ -202,12 +200,22 @@ class DialogState { vararg items: String, @StringRes title: Int, ): Int = showNoButton { - Column(modifier = Modifier.padding(24.dp)) { - Text(text = stringResource(id = title), style = MaterialTheme.typography.headlineSmall) - Spacer(modifier = Modifier.size(16.dp)) - CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.tertiary) { - items.forEachIndexed { index, text -> - Text(text = text, modifier = Modifier.clickable { dismissWith(index) }.fillMaxWidth().padding(vertical = 8.dp), style = MaterialTheme.typography.titleMedium) + Column(modifier = Modifier.padding(vertical = 8.dp)) { + Text( + text = stringResource(id = title), + modifier = Modifier.padding(horizontal = 24.dp, vertical = 8.dp), + style = MaterialTheme.typography.headlineSmall, + ) + LazyColumn { + itemsIndexed(items) { index, text -> + CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.tertiary) { + Text( + text = text, + modifier = Modifier.clickable { dismissWith(index) }.fillMaxWidth() + .padding(horizontal = 24.dp, vertical = 16.dp), + style = MaterialTheme.typography.titleMedium, + ) + } } } } From a05b9174d428441c4eb7f201e355997342b51aac Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Mon, 14 Aug 2023 23:12:39 +0800 Subject: [PATCH 8/8] Tweak EhScreen layout --- .../hippo/ehviewer/ui/settings/EhScreen.kt | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/settings/EhScreen.kt b/app/src/main/java/com/hippo/ehviewer/ui/settings/EhScreen.kt index d73a8cf5b..ddb040918 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/settings/EhScreen.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/settings/EhScreen.kt @@ -193,6 +193,27 @@ fun EhScreen() { summary = stringResource(id = R.string.settings_my_tags_summary), ) { navController.navigate(MYTAGS_SCREEN) } } + var defaultFavSlot by Settings::defaultFavSlot.observed + val disabled = stringResource(id = R.string.disabled_nav) + val localFav = stringResource(id = R.string.local_favorites) + val summary = when (defaultFavSlot) { + -1 -> localFav + in 0..9 -> Settings.favCat[defaultFavSlot] + else -> stringResource(id = R.string.default_favorites_warning) + } + val items = if (signin) { + arrayOf(disabled, localFav, *Settings.favCat) + } else { + arrayOf(disabled, localFav) + } + Preference( + title = stringResource(id = R.string.default_favorites_collection), + summary = summary, + ) { + coroutineScope.launch { + defaultFavSlot = dialogState.showSelectItem(*items, title = R.string.default_favorites_collection) - 2 + } + } SimpleMenuPreferenceInt( title = stringResource(id = rikka.core.R.string.dark_theme), entry = R.array.night_mode_entries, @@ -244,27 +265,6 @@ fun EhScreen() { entryValueRes = R.array.thumb_resolution_entry_values, value = thumbResolution, ) - var defaultFavSlot by Settings::defaultFavSlot.observed - val disabled = stringResource(id = R.string.disabled_nav) - val localFav = stringResource(id = R.string.local_favorites) - val summary = when (defaultFavSlot) { - -1 -> localFav - in 0..9 -> Settings.favCat[defaultFavSlot] - else -> stringResource(id = R.string.default_favorites_warning) - } - val items = if (signin) { - arrayOf(disabled, localFav, *Settings.favCat) - } else { - arrayOf(disabled, localFav) - } - Preference( - title = stringResource(id = R.string.default_favorites_collection), - summary = summary, - ) { - coroutineScope.launch { - defaultFavSlot = dialogState.showSelectItem(*items, title = R.string.default_favorites_collection) - 2 - } - } SwitchPreference( title = stringResource(id = R.string.settings_eh_force_eh_thumb), summary = stringResource(id = R.string.settings_eh_force_eh_thumb_summary),