mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-17 14:59:18 +01:00
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
This commit is contained in:
parent
ae2a6a3d4f
commit
2932ed670f
@ -4,7 +4,10 @@ import com.google.android.material.tabs.TabLayout
|
|||||||
|
|
||||||
interface TabbedController {
|
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) {}
|
fun cleanupTabs(tabs: TabLayout) {}
|
||||||
}
|
}
|
||||||
|
@ -79,11 +79,12 @@ class BrowseController :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun configureTabs(tabs: TabLayout) {
|
override fun configureTabs(tabs: TabLayout): Boolean {
|
||||||
with(tabs) {
|
with(tabs) {
|
||||||
tabGravity = TabLayout.GRAVITY_FILL
|
tabGravity = TabLayout.GRAVITY_FILL
|
||||||
tabMode = TabLayout.MODE_FIXED
|
tabMode = TabLayout.MODE_FIXED
|
||||||
}
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun cleanupTabs(tabs: TabLayout) {
|
override fun cleanupTabs(tabs: TabLayout) {
|
||||||
|
@ -28,24 +28,13 @@ class LibraryAdapter(
|
|||||||
* The categories to bind in the adapter.
|
* The categories to bind in the adapter.
|
||||||
*/
|
*/
|
||||||
var categories: List<Category> = emptyList()
|
var categories: List<Category> = emptyList()
|
||||||
// This setter helps to not refresh the adapter if the reference to the list doesn't change.
|
private set
|
||||||
set(value) {
|
|
||||||
if (field !== value) {
|
|
||||||
field = value
|
|
||||||
notifyDataSetChanged()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number of manga in each category.
|
* The number of manga in each category.
|
||||||
|
* List order must be the same as [categories]
|
||||||
*/
|
*/
|
||||||
var itemsPerCategory: Map<Int, Int> = emptyMap()
|
private var itemsPerCategory: List<Int> = emptyList()
|
||||||
set(value) {
|
|
||||||
if (field !== value) {
|
|
||||||
field = value
|
|
||||||
notifyDataSetChanged()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var boundViews = arrayListOf<View>()
|
private var boundViews = arrayListOf<View>()
|
||||||
|
|
||||||
@ -62,6 +51,29 @@ class LibraryAdapter(
|
|||||||
.launchIn(controller.viewScope)
|
.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.
|
* Creates a new view for this adapter.
|
||||||
*
|
*
|
||||||
@ -112,10 +124,11 @@ class LibraryAdapter(
|
|||||||
* @return the title to display.
|
* @return the title to display.
|
||||||
*/
|
*/
|
||||||
override fun getPageTitle(position: Int): CharSequence {
|
override fun getPageTitle(position: Int): CharSequence {
|
||||||
if (preferences.categoryNumberOfItems().get()) {
|
return if (!preferences.categoryNumberOfItems().get()) {
|
||||||
return categories[position].let { "${it.name} (${itemsPerCategory[it.id]})" }
|
categories[position].name
|
||||||
|
} else {
|
||||||
|
categories[position].let { "${it.name} (${itemsPerCategory[position]})" }
|
||||||
}
|
}
|
||||||
return categories[position].name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8,6 +8,7 @@ import android.view.MenuInflater
|
|||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.appcompat.view.ActionMode
|
import androidx.appcompat.view.ActionMode
|
||||||
|
import androidx.core.view.doOnAttach
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||||
import com.bluelinelabs.conductor.ControllerChangeType
|
import com.bluelinelabs.conductor.ControllerChangeType
|
||||||
@ -234,8 +235,9 @@ class LibraryController(
|
|||||||
super.onDestroyView(view)
|
super.onDestroyView(view)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun configureTabs(tabs: TabLayout) {
|
override fun configureTabs(tabs: TabLayout): Boolean {
|
||||||
with(tabs) {
|
with(tabs) {
|
||||||
|
isVisible = false
|
||||||
tabGravity = TabLayout.GRAVITY_START
|
tabGravity = TabLayout.GRAVITY_START
|
||||||
tabMode = TabLayout.MODE_SCROLLABLE
|
tabMode = TabLayout.MODE_SCROLLABLE
|
||||||
}
|
}
|
||||||
@ -247,6 +249,8 @@ class LibraryController(
|
|||||||
mangaCountVisibilitySubscription = mangaCountVisibilityRelay.subscribe {
|
mangaCountVisibilitySubscription = mangaCountVisibilityRelay.subscribe {
|
||||||
adapter?.notifyDataSetChanged()
|
adapter?.notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun cleanupTabs(tabs: TabLayout) {
|
override fun cleanupTabs(tabs: TabLayout) {
|
||||||
@ -291,22 +295,17 @@ class LibraryController(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set the categories
|
// Set the categories
|
||||||
adapter.categories = categories
|
adapter.updateCategories(categories.map { it to (mangaMap[it.id]?.size ?: 0) })
|
||||||
adapter.itemsPerCategory = adapter.categories
|
|
||||||
.map { (it.id ?: -1) to (mangaMap[it.id]?.size ?: 0) }
|
|
||||||
.toMap()
|
|
||||||
|
|
||||||
// Restore active category.
|
// Restore active category.
|
||||||
binding.libraryPager.setCurrentItem(activeCat, false)
|
binding.libraryPager.setCurrentItem(activeCat, false)
|
||||||
|
|
||||||
// Trigger display of tabs
|
// Trigger display of tabs
|
||||||
onTabsSettingsChanged()
|
onTabsSettingsChanged(firstLaunch = true)
|
||||||
|
|
||||||
// Delay the scroll position to allow the view to be properly measured.
|
// Delay the scroll position to allow the view to be properly measured.
|
||||||
view.post {
|
view.doOnAttach {
|
||||||
if (isAttached) {
|
(activity as? MainActivity)?.binding?.tabs?.setScrollPosition(binding.libraryPager.currentItem, 0f, true)
|
||||||
(activity as? MainActivity)?.binding?.tabs?.setScrollPosition(binding.libraryPager.currentItem, 0f, true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the manga map to child fragments after the adapter is updated.
|
// Send the manga map to child fragments after the adapter is updated.
|
||||||
@ -338,9 +337,11 @@ class LibraryController(
|
|||||||
presenter.requestBadgesUpdate()
|
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)
|
tabsVisibilityRelay.call(preferences.categoryTabs().get() && adapter?.categories?.size ?: 0 > 1)
|
||||||
mangaCountVisibilityRelay.call(preferences.categoryNumberOfItems().get())
|
|
||||||
updateTitle()
|
updateTitle()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ import com.bluelinelabs.conductor.Conductor
|
|||||||
import com.bluelinelabs.conductor.Controller
|
import com.bluelinelabs.conductor.Controller
|
||||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||||
import com.bluelinelabs.conductor.Router
|
import com.bluelinelabs.conductor.Router
|
||||||
|
import com.bluelinelabs.conductor.RouterTransaction
|
||||||
import com.google.android.material.navigation.NavigationBarView
|
import com.google.android.material.navigation.NavigationBarView
|
||||||
import com.google.android.material.transition.platform.MaterialContainerTransformSharedElementCallback
|
import com.google.android.material.transition.platform.MaterialContainerTransformSharedElementCallback
|
||||||
import dev.chrisbanes.insetter.applyInsetter
|
import dev.chrisbanes.insetter.applyInsetter
|
||||||
@ -236,6 +237,11 @@ class MainActivity : BaseViewBindingActivity<MainActivityBinding>() {
|
|||||||
if (didMigration && !BuildConfig.DEBUG) {
|
if (didMigration && !BuildConfig.DEBUG) {
|
||||||
WhatsNewDialogController().showDialog(router)
|
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())
|
merge(preferences.showUpdatesNavBadge().asFlow(), preferences.unreadUpdatesCount().asFlow())
|
||||||
@ -403,11 +409,12 @@ class MainActivity : BaseViewBindingActivity<MainActivityBinding>() {
|
|||||||
}
|
}
|
||||||
SHORTCUT_MANGA -> {
|
SHORTCUT_MANGA -> {
|
||||||
val extras = intent.extras ?: return false
|
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()
|
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 -> {
|
SHORTCUT_DOWNLOADS -> {
|
||||||
if (router.backstackSize > 1) {
|
if (router.backstackSize > 1) {
|
||||||
@ -553,11 +560,12 @@ class MainActivity : BaseViewBindingActivity<MainActivityBinding>() {
|
|||||||
from.cleanupTabs(binding.tabs)
|
from.cleanupTabs(binding.tabs)
|
||||||
}
|
}
|
||||||
if (to is TabbedController) {
|
if (to is TabbedController) {
|
||||||
to.configureTabs(binding.tabs)
|
if (to.configureTabs(binding.tabs)) {
|
||||||
|
binding.tabs.isVisible = true
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
binding.tabs.setupWithViewPager(null)
|
binding.tabs.isVisible = false
|
||||||
}
|
}
|
||||||
binding.tabs.isVisible = to is TabbedController
|
|
||||||
|
|
||||||
if (from is FabController) {
|
if (from is FabController) {
|
||||||
from.cleanupFab(binding.fabLayout.rootFab)
|
from.cleanupFab(binding.fabLayout.rootFab)
|
||||||
|
@ -5,23 +5,15 @@ import android.os.Parcel
|
|||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.coordinatorlayout.R
|
import androidx.coordinatorlayout.R
|
||||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
import androidx.core.view.doOnLayout
|
import androidx.core.view.doOnLayout
|
||||||
|
import androidx.core.view.isVisible
|
||||||
import androidx.customview.view.AbsSavedState
|
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.appbar.AppBarLayout
|
||||||
|
import com.google.android.material.tabs.TabLayout
|
||||||
import eu.kanade.tachiyomi.util.system.isTablet
|
import eu.kanade.tachiyomi.util.system.isTablet
|
||||||
import eu.kanade.tachiyomi.util.view.findChild
|
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.
|
* [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:
|
* With those conditions, this view expects the following direct child:
|
||||||
*
|
*
|
||||||
* 1. An [AppBarLayout].
|
* 1. An [AppBarLayout].
|
||||||
*
|
|
||||||
* 2. A [ChangeHandlerFrameLayout] that contains an optional [ViewPager].
|
|
||||||
*/
|
*/
|
||||||
class TachiyomiCoordinatorLayout @JvmOverloads constructor(
|
class TachiyomiCoordinatorLayout @JvmOverloads constructor(
|
||||||
context: Context,
|
context: Context,
|
||||||
@ -48,7 +38,7 @@ class TachiyomiCoordinatorLayout @JvmOverloads constructor(
|
|||||||
private val isTablet = context.isTablet()
|
private val isTablet = context.isTablet()
|
||||||
|
|
||||||
private var appBarLayout: AppBarLayout? = null
|
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.
|
* 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)
|
super.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type, consumed)
|
||||||
// Disable elevation overlay when tabs are visible
|
// Disable elevation overlay when tabs are visible
|
||||||
if (canLiftAppBarOnScroll && viewPager == null) {
|
if (canLiftAppBarOnScroll) {
|
||||||
appBarLayout?.isLifted = dyConsumed != 0 || dyUnconsumed >= 0
|
appBarLayout?.isLifted = (dyConsumed != 0 || dyUnconsumed >= 0) && tabLayout?.isVisible == false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAttachedToWindow() {
|
override fun onAttachedToWindow() {
|
||||||
super.onAttachedToWindow()
|
super.onAttachedToWindow()
|
||||||
appBarLayout = findChild()
|
appBarLayout = findChild()
|
||||||
viewPager = findChild<ChangeHandlerFrameLayout>()?.findDescendant()
|
tabLayout = appBarLayout?.findChild()
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDetachedFromWindow() {
|
override fun onDetachedFromWindow() {
|
||||||
super.onDetachedFromWindow()
|
super.onDetachedFromWindow()
|
||||||
appBarLayout = null
|
appBarLayout = null
|
||||||
viewPager = null
|
tabLayout = null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(): Parcelable? {
|
override fun onSaveInstanceState(): Parcelable? {
|
||||||
|
Loading…
Reference in New Issue
Block a user