瀏覽代碼

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
Ivan Iskandar 3 年之前
父節點
當前提交
2932ed670f

+ 4 - 1
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) {}
 }

+ 2 - 1
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) {

+ 30 - 17
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<Category> = 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<Int, Int> = emptyMap()
-        set(value) {
-            if (field !== value) {
-                field = value
-                notifyDataSetChanged()
-            }
-        }
+    private var itemsPerCategory: List<Int> = emptyList()
 
     private var boundViews = arrayListOf<View>()
 
@@ -62,6 +51,29 @@ class LibraryAdapter(
             .launchIn(controller.viewScope)
     }
 
+    /**
+     * Pair of category and size of category
+     */
+    fun updateCategories(new: List<Pair<Category, Int>>) {
+        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
     }
 
     /**

+ 13 - 12
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()
     }
 

+ 14 - 6
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<MainActivityBinding>() {
             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<MainActivityBinding>() {
             }
             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<MainActivityBinding>() {
             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)

+ 7 - 28
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<ChangeHandlerFrameLayout>()?.findDescendant()
-
-        // Updates ViewPager reference when controller is changed
-        findViewTreeLifecycleOwner()?.lifecycle?.coroutineScope?.let { scope ->
-            findChild<ChangeHandlerFrameLayout>()?.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? {