From 2932ed670f5760eba28aea80f1dd29e7a9af48c7 Mon Sep 17 00:00:00 2001 From: Ivan Iskandar <12537387+ivaniskandar@users.noreply.github.com> Date: Sat, 12 Feb 2022 22:58:58 +0700 Subject: [PATCH] MainActivity fixes (#6591) * Reduce notifyDataSetChanged calls when category count is disabled * Fix category tabs briefly showing when it's supposed to be disabled Also fix tabs showing when activity recreated * Lift appbar when tab is hidden Check against tab visibility instead of viewpager * Restore selected nav item after recreate * Simplify SHORTCUT_MANGA intent handling Don't need to change controller if the topmost controller is the target --- .../ui/base/controller/TabbedController.kt | 5 +- .../tachiyomi/ui/browse/BrowseController.kt | 3 +- .../tachiyomi/ui/library/LibraryAdapter.kt | 47 ++++++++++++------- .../tachiyomi/ui/library/LibraryController.kt | 25 +++++----- .../kanade/tachiyomi/ui/main/MainActivity.kt | 20 +++++--- .../widget/TachiyomiCoordinatorLayout.kt | 35 +++----------- 6 files changed, 70 insertions(+), 65 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/TabbedController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/TabbedController.kt index 48cbda58a5..6cf26780ce 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/TabbedController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/TabbedController.kt @@ -4,7 +4,10 @@ import com.google.android.material.tabs.TabLayout interface TabbedController { - fun configureTabs(tabs: TabLayout) {} + /** + * @return true to let activity updates tabs visibility (to visible) + */ + fun configureTabs(tabs: TabLayout): Boolean = true fun cleanupTabs(tabs: TabLayout) {} } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/BrowseController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/BrowseController.kt index e40855e1ab..294a7079fd 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/BrowseController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/BrowseController.kt @@ -79,11 +79,12 @@ class BrowseController : } } - override fun configureTabs(tabs: TabLayout) { + override fun configureTabs(tabs: TabLayout): Boolean { with(tabs) { tabGravity = TabLayout.GRAVITY_FILL tabMode = TabLayout.MODE_FIXED } + return true } override fun cleanupTabs(tabs: TabLayout) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryAdapter.kt index 972843d137..6a18ef897b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryAdapter.kt @@ -28,24 +28,13 @@ class LibraryAdapter( * The categories to bind in the adapter. */ var categories: List = emptyList() - // This setter helps to not refresh the adapter if the reference to the list doesn't change. - set(value) { - if (field !== value) { - field = value - notifyDataSetChanged() - } - } + private set /** * The number of manga in each category. + * List order must be the same as [categories] */ - var itemsPerCategory: Map = emptyMap() - set(value) { - if (field !== value) { - field = value - notifyDataSetChanged() - } - } + private var itemsPerCategory: List = emptyList() private var boundViews = arrayListOf() @@ -62,6 +51,29 @@ class LibraryAdapter( .launchIn(controller.viewScope) } + /** + * Pair of category and size of category + */ + fun updateCategories(new: List>) { + var updated = false + + val newCategories = new.map { it.first } + if (categories != newCategories) { + categories = newCategories + updated = true + } + + val newItemsPerCategory = new.map { it.second } + if (itemsPerCategory !== newItemsPerCategory) { + itemsPerCategory = newItemsPerCategory + updated = true + } + + if (updated) { + notifyDataSetChanged() + } + } + /** * Creates a new view for this adapter. * @@ -112,10 +124,11 @@ class LibraryAdapter( * @return the title to display. */ override fun getPageTitle(position: Int): CharSequence { - if (preferences.categoryNumberOfItems().get()) { - return categories[position].let { "${it.name} (${itemsPerCategory[it.id]})" } + return if (!preferences.categoryNumberOfItems().get()) { + categories[position].name + } else { + categories[position].let { "${it.name} (${itemsPerCategory[position]})" } } - return categories[position].name } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt index 5d19fcf068..3085d4d3cb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt @@ -8,6 +8,7 @@ import android.view.MenuInflater import android.view.MenuItem import android.view.View import androidx.appcompat.view.ActionMode +import androidx.core.view.doOnAttach import androidx.core.view.isVisible import com.bluelinelabs.conductor.ControllerChangeHandler import com.bluelinelabs.conductor.ControllerChangeType @@ -234,8 +235,9 @@ class LibraryController( super.onDestroyView(view) } - override fun configureTabs(tabs: TabLayout) { + override fun configureTabs(tabs: TabLayout): Boolean { with(tabs) { + isVisible = false tabGravity = TabLayout.GRAVITY_START tabMode = TabLayout.MODE_SCROLLABLE } @@ -247,6 +249,8 @@ class LibraryController( mangaCountVisibilitySubscription = mangaCountVisibilityRelay.subscribe { adapter?.notifyDataSetChanged() } + + return false } override fun cleanupTabs(tabs: TabLayout) { @@ -291,22 +295,17 @@ class LibraryController( } // Set the categories - adapter.categories = categories - adapter.itemsPerCategory = adapter.categories - .map { (it.id ?: -1) to (mangaMap[it.id]?.size ?: 0) } - .toMap() + adapter.updateCategories(categories.map { it to (mangaMap[it.id]?.size ?: 0) }) // Restore active category. binding.libraryPager.setCurrentItem(activeCat, false) // Trigger display of tabs - onTabsSettingsChanged() + onTabsSettingsChanged(firstLaunch = true) // Delay the scroll position to allow the view to be properly measured. - view.post { - if (isAttached) { - (activity as? MainActivity)?.binding?.tabs?.setScrollPosition(binding.libraryPager.currentItem, 0f, true) - } + view.doOnAttach { + (activity as? MainActivity)?.binding?.tabs?.setScrollPosition(binding.libraryPager.currentItem, 0f, true) } // Send the manga map to child fragments after the adapter is updated. @@ -338,9 +337,11 @@ class LibraryController( presenter.requestBadgesUpdate() } - private fun onTabsSettingsChanged() { + private fun onTabsSettingsChanged(firstLaunch: Boolean = false) { + if (!firstLaunch) { + mangaCountVisibilityRelay.call(preferences.categoryNumberOfItems().get()) + } tabsVisibilityRelay.call(preferences.categoryTabs().get() && adapter?.categories?.size ?: 0 > 1) - mangaCountVisibilityRelay.call(preferences.categoryNumberOfItems().get()) updateTitle() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt index 72b6eeb8db..78b74756d8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt @@ -27,6 +27,7 @@ import com.bluelinelabs.conductor.Conductor import com.bluelinelabs.conductor.Controller import com.bluelinelabs.conductor.ControllerChangeHandler import com.bluelinelabs.conductor.Router +import com.bluelinelabs.conductor.RouterTransaction import com.google.android.material.navigation.NavigationBarView import com.google.android.material.transition.platform.MaterialContainerTransformSharedElementCallback import dev.chrisbanes.insetter.applyInsetter @@ -236,6 +237,11 @@ class MainActivity : BaseViewBindingActivity() { if (didMigration && !BuildConfig.DEBUG) { WhatsNewDialogController().showDialog(router) } + } else { + // Restore selected nav item + router.backstack.firstOrNull()?.tag()?.toIntOrNull()?.let { + nav.menu.findItem(it).isChecked = true + } } merge(preferences.showUpdatesNavBadge().asFlow(), preferences.unreadUpdatesCount().asFlow()) @@ -403,11 +409,12 @@ class MainActivity : BaseViewBindingActivity() { } SHORTCUT_MANGA -> { val extras = intent.extras ?: return false - if (router.backstackSize > 1) { + val fgController = router.backstack.last()?.controller as? MangaController + if (fgController?.manga?.id != extras.getLong(MangaController.MANGA_EXTRA)) { router.popToRoot() + setSelectedNavItem(R.id.nav_library) + router.pushController(RouterTransaction.with(MangaController(extras))) } - setSelectedNavItem(R.id.nav_library) - router.pushController(MangaController(extras).withFadeTransaction()) } SHORTCUT_DOWNLOADS -> { if (router.backstackSize > 1) { @@ -553,11 +560,12 @@ class MainActivity : BaseViewBindingActivity() { from.cleanupTabs(binding.tabs) } if (to is TabbedController) { - to.configureTabs(binding.tabs) + if (to.configureTabs(binding.tabs)) { + binding.tabs.isVisible = true + } } else { - binding.tabs.setupWithViewPager(null) + binding.tabs.isVisible = false } - binding.tabs.isVisible = to is TabbedController if (from is FabController) { from.cleanupFab(binding.fabLayout.rootFab) diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/TachiyomiCoordinatorLayout.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/TachiyomiCoordinatorLayout.kt index 28d4ef5cf0..90516828ee 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/TachiyomiCoordinatorLayout.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/TachiyomiCoordinatorLayout.kt @@ -5,23 +5,15 @@ import android.os.Parcel import android.os.Parcelable import android.util.AttributeSet import android.view.View -import android.view.ViewGroup import androidx.coordinatorlayout.R import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.view.doOnLayout +import androidx.core.view.isVisible import androidx.customview.view.AbsSavedState -import androidx.lifecycle.coroutineScope -import androidx.lifecycle.findViewTreeLifecycleOwner -import androidx.viewpager.widget.ViewPager -import com.bluelinelabs.conductor.ChangeHandlerFrameLayout import com.google.android.material.appbar.AppBarLayout +import com.google.android.material.tabs.TabLayout import eu.kanade.tachiyomi.util.system.isTablet import eu.kanade.tachiyomi.util.view.findChild -import eu.kanade.tachiyomi.util.view.findDescendant -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import reactivecircus.flowbinding.android.view.HierarchyChangeEvent -import reactivecircus.flowbinding.android.view.hierarchyChangeEvents /** * [CoordinatorLayout] with its own app bar lift state handler. @@ -33,8 +25,6 @@ import reactivecircus.flowbinding.android.view.hierarchyChangeEvents * With those conditions, this view expects the following direct child: * * 1. An [AppBarLayout]. - * - * 2. A [ChangeHandlerFrameLayout] that contains an optional [ViewPager]. */ class TachiyomiCoordinatorLayout @JvmOverloads constructor( context: Context, @@ -48,7 +38,7 @@ class TachiyomiCoordinatorLayout @JvmOverloads constructor( private val isTablet = context.isTablet() private var appBarLayout: AppBarLayout? = null - private var viewPager: ViewPager? = null + private var tabLayout: TabLayout? = null /** * If true, [AppBarLayout] child will be lifted on nested scroll. @@ -72,32 +62,21 @@ class TachiyomiCoordinatorLayout @JvmOverloads constructor( ) { super.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type, consumed) // Disable elevation overlay when tabs are visible - if (canLiftAppBarOnScroll && viewPager == null) { - appBarLayout?.isLifted = dyConsumed != 0 || dyUnconsumed >= 0 + if (canLiftAppBarOnScroll) { + appBarLayout?.isLifted = (dyConsumed != 0 || dyUnconsumed >= 0) && tabLayout?.isVisible == false } } override fun onAttachedToWindow() { super.onAttachedToWindow() appBarLayout = findChild() - viewPager = findChild()?.findDescendant() - - // Updates ViewPager reference when controller is changed - findViewTreeLifecycleOwner()?.lifecycle?.coroutineScope?.let { scope -> - findChild()?.hierarchyChangeEvents() - ?.onEach { - if (it is HierarchyChangeEvent.ChildRemoved) { - viewPager = (it.parent as? ViewGroup)?.findDescendant() - } - } - ?.launchIn(scope) - } + tabLayout = appBarLayout?.findChild() } override fun onDetachedFromWindow() { super.onDetachedFromWindow() appBarLayout = null - viewPager = null + tabLayout = null } override fun onSaveInstanceState(): Parcelable? {