Initial tablet NavigationRailView implementation

Co-Authored-By: arkon <4098258+arkon@users.noreply.github.com>
This commit is contained in:
Jays2Kings 2021-05-23 00:11:32 -04:00
parent 3dce788c94
commit d82d738f38
13 changed files with 535 additions and 167 deletions

View File

@ -0,0 +1,50 @@
package eu.kanade.tachiyomi.ui.base.controller
import android.animation.Animator
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.view.View
import android.view.ViewGroup
import com.bluelinelabs.conductor.ControllerChangeHandler
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
import eu.kanade.tachiyomi.util.system.isTablet
/**
* A variation of [FadeChangeHandler] that only fades in.
*/
class OneWayFadeChangeHandler : FadeChangeHandler {
constructor()
constructor(removesFromViewOnPush: Boolean) : super(removesFromViewOnPush)
constructor(duration: Long) : super(duration)
constructor(duration: Long, removesFromViewOnPush: Boolean) : super(
duration,
removesFromViewOnPush
)
override fun getAnimator(
container: ViewGroup,
from: View?,
to: View?,
isPush: Boolean,
toAddedToContainer: Boolean
): Animator {
val animator = AnimatorSet()
if (to != null) {
val start: Float = if (toAddedToContainer) 0F else to.alpha
animator.play(ObjectAnimator.ofFloat(to, View.ALPHA, start, 1f))
}
if (from != null && (!isPush || removesFromViewOnPush())) {
if (!container.context.isTablet()) {
animator.play(ObjectAnimator.ofFloat(from, View.ALPHA, 0f))
} else {
container.removeView(from)
}
}
return animator
}
override fun copy(): ControllerChangeHandler {
return OneWayFadeChangeHandler(animationDuration, removesFromViewOnPush())
}
}

View File

@ -91,10 +91,10 @@ class ExtensionBottomSheet @JvmOverloads constructor(context: Context, attrs: At
binding.pager.adapter = TabbedSheetAdapter() binding.pager.adapter = TabbedSheetAdapter()
binding.tabs.setupWithViewPager(binding.pager) binding.tabs.setupWithViewPager(binding.pager)
this.controller = controller this.controller = controller
binding.pager.doOnApplyWindowInsets { _, _, _ -> binding.pager.doOnApplyWindowInsets { _, insets, _ ->
val bottomBar = controller.activityBinding?.bottomNav val bottomBar = controller.activityBinding?.bottomNav
extensionFrameLayout?.binding?.recycler?.updatePaddingRelative(bottom = bottomBar?.height ?: 0) extensionFrameLayout?.binding?.recycler?.updatePaddingRelative(bottom = bottomBar?.height ?: insets.systemWindowInsetBottom)
migrationFrameLayout?.binding?.recycler?.updatePaddingRelative(bottom = bottomBar?.height ?: 0) migrationFrameLayout?.binding?.recycler?.updatePaddingRelative(bottom = bottomBar?.height ?: insets.systemWindowInsetBottom)
} }
binding.tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { binding.tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab?) { override fun onTabSelected(tab: TabLayout.Tab?) {
@ -336,9 +336,15 @@ class ExtensionBottomSheet @JvmOverloads constructor(context: Context, attrs: At
* @return a new view. * @return a new view.
*/ */
override fun createView(container: ViewGroup): View { override fun createView(container: ViewGroup): View {
val binding = RecyclerWithScrollerBinding.inflate(LayoutInflater.from(container.context), container, false) val binding = RecyclerWithScrollerBinding.inflate(
LayoutInflater.from(container.context),
container,
false
)
val view: RecyclerWithScrollerView = binding.root val view: RecyclerWithScrollerView = binding.root
view.setUp(this@ExtensionBottomSheet, binding, this@ExtensionBottomSheet.controller.activityBinding?.bottomNav?.height ?: 0) val height = this@ExtensionBottomSheet.controller.activityBinding?.bottomNav?.height
?: view.rootWindowInsets?.systemWindowInsetBottom ?: 0
view.setUp(this@ExtensionBottomSheet, binding, height)
return view return view
} }

View File

@ -200,6 +200,10 @@ class LibraryController(
get() = preferences.showCategoryInTitle().get() && presenter.showAllCategories get() = preferences.showCategoryInTitle().get() && presenter.showAllCategories
private lateinit var elevateAppBar: ((Boolean) -> Unit) private lateinit var elevateAppBar: ((Boolean) -> Unit)
private var hopperOffset = 0f private var hopperOffset = 0f
private val maxHopperOffset: Float
get() =
if (activityBinding?.bottomNav != null) 55f.dpToPx
else (view?.rootWindowInsets?.systemWindowInsetBottom?.toFloat() ?: 0f) + 55f.dpToPx
override fun getTitle(): String? { override fun getTitle(): String? {
setSubtitle() setSubtitle()
@ -222,9 +226,9 @@ class LibraryController(
if (!recyclerCover.isClickable && isAnimatingHopper != true) { if (!recyclerCover.isClickable && isAnimatingHopper != true) {
if (preferences.autohideHopper().get()) { if (preferences.autohideHopper().get()) {
hopperOffset += dy hopperOffset += dy
hopperOffset = hopperOffset.coerceIn(0f, 55f.dpToPx) hopperOffset = hopperOffset.coerceIn(0f, maxHopperOffset)
} }
if (!preferences.hideBottomNavOnScroll().get()) { if (!preferences.hideBottomNavOnScroll().get() || activityBinding?.bottomNav == null) {
updateFilterSheetY() updateFilterSheetY()
} }
binding.roundedCategoryHopper.upCategory.alpha = if (isAtTop()) 0.25f else 1f binding.roundedCategoryHopper.upCategory.alpha = if (isAtTop()) 0.25f else 1f
@ -291,6 +295,11 @@ class LibraryController(
binding.fastScroller.updateLayoutParams<ViewGroup.MarginLayoutParams> { binding.fastScroller.updateLayoutParams<ViewGroup.MarginLayoutParams> {
bottomMargin = -pad.toInt() bottomMargin = -pad.toInt()
} }
} else {
binding.filterBottomSheet.filterBottomSheet.updatePaddingRelative(
bottom = view?.rootWindowInsets?.getBottomGestureInsets() ?: 0
)
updateHopperY()
} }
} }
@ -300,12 +309,17 @@ class LibraryController(
) ?: 0 ) ?: 0
if (preferences.autohideHopper().get()) { if (preferences.autohideHopper().get()) {
// Flow same snap rules as bottom nav // Flow same snap rules as bottom nav
val closerToHopperBottom = hopperOffset > 25f.dpToPx val closerToHopperBottom = hopperOffset > maxHopperOffset / 2
val halfWayBottom = activityBinding?.bottomNav?.height?.toFloat()?.div(2) ?: 0f val halfWayBottom = activityBinding?.bottomNav?.height?.toFloat()?.div(2) ?: 0f
val closerToBottom = (activityBinding?.bottomNav?.translationY ?: 0f) > halfWayBottom val closerToBottom = (activityBinding?.bottomNav?.translationY ?: 0f) > halfWayBottom
val atTop = !binding.libraryGridRecycler.recycler.canScrollVertically(-1) val atTop = !binding.libraryGridRecycler.recycler.canScrollVertically(-1)
val closerToEdge = if (preferences.hideBottomNavOnScroll().get()) (closerToBottom && !atTop) else closerToHopperBottom val closerToEdge =
val end = if (closerToEdge) 55f.dpToPx else 0f if (preferences.hideBottomNavOnScroll().get() && activityBinding?.bottomNav != null) {
closerToBottom && !atTop
} else {
closerToHopperBottom
}
val end = if (closerToEdge) maxHopperOffset else 0f
val alphaAnimation = ValueAnimator.ofFloat(hopperOffset, end) val alphaAnimation = ValueAnimator.ofFloat(hopperOffset, end)
alphaAnimation.addUpdateListener { valueAnimator -> alphaAnimation.addUpdateListener { valueAnimator ->
hopperOffset = valueAnimator.animatedValue as Float hopperOffset = valueAnimator.animatedValue as Float
@ -385,7 +399,7 @@ class LibraryController(
if (preferences.shownFilterTutorial().get() || !hasExpanded) return if (preferences.shownFilterTutorial().get() || !hasExpanded) return
val activityBinding = activityBinding ?: return val activityBinding = activityBinding ?: return
val activity = activity ?: return val activity = activity ?: return
val icon = activityBinding.bottomNav.getItemView(R.id.nav_library) ?: return val icon = (activityBinding.bottomNav ?: activityBinding.sideNav)?.getItemView(R.id.nav_library) ?: return
filterTooltip = filterTooltip =
ViewTooltip.on(activity, icon).autoHide(false, 0L).align(ViewTooltip.ALIGN.START) ViewTooltip.on(activity, icon).autoHide(false, 0L).align(ViewTooltip.ALIGN.START)
.position(ViewTooltip.Position.TOP).text(R.string.tap_library_to_show_filters) .position(ViewTooltip.Position.TOP).text(R.string.tap_library_to_show_filters)
@ -684,7 +698,7 @@ class LibraryController(
activityBinding?.bottomNav?.y ?: binding.filterBottomSheet.filterBottomSheet.y activityBinding?.bottomNav?.y ?: binding.filterBottomSheet.filterBottomSheet.y
) )
val insetBottom = view.rootWindowInsets?.systemWindowInsetBottom ?: 0 val insetBottom = view.rootWindowInsets?.systemWindowInsetBottom ?: 0
if (!preferences.autohideHopper().get()) { if (!preferences.autohideHopper().get() || activityBinding?.bottomNav == null) {
listOfYs.add(view.height - (insetBottom).toFloat()) listOfYs.add(view.height - (insetBottom).toFloat())
} }
binding.categoryHopperFrame.y = -binding.categoryHopperFrame.height + binding.categoryHopperFrame.y = -binding.categoryHopperFrame.height +

View File

@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.library.display
import android.animation.ValueAnimator import android.animation.ValueAnimator
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.view.View
import android.view.ViewTreeObserver import android.view.ViewTreeObserver
import android.widget.SeekBar import android.widget.SeekBar
import androidx.core.animation.addListener import androidx.core.animation.addListener
@ -27,6 +28,7 @@ import kotlin.math.roundToInt
class LibraryDisplayView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : class LibraryDisplayView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
BaseLibraryDisplayView<LibraryDisplayLayoutBinding>(context, attrs) { BaseLibraryDisplayView<LibraryDisplayLayoutBinding>(context, attrs) {
var mainView: View? = null
override fun inflateBinding() = LibraryDisplayLayoutBinding.bind(this) override fun inflateBinding() = LibraryDisplayLayoutBinding.bind(this)
override fun initGeneralPreferences() { override fun initGeneralPreferences() {
binding.displayGroup.bindToPreference(preferences.libraryLayout()) binding.displayGroup.bindToPreference(preferences.libraryLayout())
@ -127,7 +129,7 @@ class LibraryDisplayView @JvmOverloads constructor(context: Context, attrs: Attr
private fun setGridText(progress: Int) { private fun setGridText(progress: Int) {
with(binding.gridSizeText) { with(binding.gridSizeText) {
val rows = this@LibraryDisplayView.rowsForValue(progress) val rows = (mainView ?: this@LibraryDisplayView).rowsForValue(progress)
val titleText = context.getString(R.string.grid_size) val titleText = context.getString(R.string.grid_size)
val subtitleText = context.getString(R.string._per_row, rows) val subtitleText = context.getString(R.string._per_row, rows)
text = titleText.withSubtitle(context, subtitleText) text = titleText.withSubtitle(context, subtitleText)
@ -138,7 +140,7 @@ class LibraryDisplayView @JvmOverloads constructor(context: Context, attrs: Attr
with(binding.seekBarTextView.root) { with(binding.seekBarTextView.root) {
val value = val value =
(progress * (seekBar.width - 12.dpToPx - 2 * seekBar.thumbOffset)) / seekBar.max (progress * (seekBar.width - 12.dpToPx - 2 * seekBar.thumbOffset)) / seekBar.max
text = this@LibraryDisplayView.rowsForValue(progress).toString() text = (mainView ?: this@LibraryDisplayView).rowsForValue(progress).toString()
x = seekBar.x + value + seekBar.thumbOffset / 2 + 5.dpToPx x = seekBar.x + value + seekBar.thumbOffset / 2 + 5.dpToPx
y = seekBar.y + binding.gridSizeLayout.y - 6.dpToPx - height y = seekBar.y + binding.gridSizeLayout.y - 6.dpToPx - height
} }

View File

@ -25,6 +25,7 @@ open class TabbedLibraryDisplaySheet(val controller: Controller) :
badgesView.controller = libraryController badgesView.controller = libraryController
categoryView.controller = libraryController categoryView.controller = libraryController
} }
displayView.mainView = controller.view
binding.menu.isVisible = controller !is SettingsLibraryController binding.menu.isVisible = controller !is SettingsLibraryController
binding.menu.compatToolTipText = context.getString(R.string.more_library_settings) binding.menu.compatToolTipText = context.getString(R.string.more_library_settings)
binding.menu.setImageDrawable( binding.menu.setImageDrawable(

View File

@ -110,7 +110,10 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri
this.controller = controller this.controller = controller
libraryRecyler = controller.binding.libraryGridRecycler.recycler libraryRecyler = controller.binding.libraryGridRecycler.recycler
libraryRecyler?.post { libraryRecyler?.post {
bottomBarHeight = controller.activityBinding?.bottomNav?.height ?: 0 bottomBarHeight =
controller.activityBinding?.bottomNav?.height
?: controller.activityBinding?.root?.rootWindowInsets?.systemWindowInsetBottom
?: 0
} }
val shadow2: View = controller.binding.shadow2 val shadow2: View = controller.binding.shadow2
val shadow: View = controller.binding.shadow val shadow: View = controller.binding.shadow

View File

@ -35,6 +35,7 @@ import com.bluelinelabs.conductor.ControllerChangeHandler
import com.bluelinelabs.conductor.Router import com.bluelinelabs.conductor.Router
import com.getkeepsafe.taptargetview.TapTarget import com.getkeepsafe.taptargetview.TapTarget
import com.getkeepsafe.taptargetview.TapTargetView import com.getkeepsafe.taptargetview.TapTargetView
import com.google.android.material.navigation.NavigationBarView
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.Migrations import eu.kanade.tachiyomi.Migrations
@ -71,6 +72,7 @@ import eu.kanade.tachiyomi.util.system.contextCompatDrawable
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.system.hasSideNavBar import eu.kanade.tachiyomi.util.system.hasSideNavBar
import eu.kanade.tachiyomi.util.system.isBottomTappable import eu.kanade.tachiyomi.util.system.isBottomTappable
import eu.kanade.tachiyomi.util.system.isTablet
import eu.kanade.tachiyomi.util.system.launchUI import eu.kanade.tachiyomi.util.system.launchUI
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets
@ -167,7 +169,7 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
) )
var continueSwitchingTabs = false var continueSwitchingTabs = false
binding.bottomNav.getItemView(R.id.nav_library)?.setOnLongClickListener { nav.getItemView(R.id.nav_library)?.setOnLongClickListener {
if (!LibraryUpdateService.isRunning()) { if (!LibraryUpdateService.isRunning()) {
LibraryUpdateService.start(this) LibraryUpdateService.start(this)
binding.mainContent.snack(R.string.updating_library) { binding.mainContent.snack(R.string.updating_library) {
@ -186,9 +188,9 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
true true
} }
for (id in listOf(R.id.nav_recents, R.id.nav_browse)) { for (id in listOf(R.id.nav_recents, R.id.nav_browse)) {
binding.bottomNav.getItemView(id)?.setOnLongClickListener { nav.getItemView(id)?.setOnLongClickListener {
binding.bottomNav.selectedItemId = id nav.selectedItemId = id
binding.bottomNav.post { nav.post {
val controller = val controller =
router.backstack.firstOrNull()?.controller as? BottomSheetController router.backstack.firstOrNull()?.controller as? BottomSheetController
controller?.showSheet() controller?.showSheet()
@ -196,15 +198,67 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
true true
} }
} }
binding.bottomNav.setOnNavigationItemSelectedListener { item ->
val container: ViewGroup = binding.controllerContainer
val content: ViewGroup = binding.mainContent
DownloadService.addListener(this)
content.systemUiVisibility =
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
container.systemUiVisibility =
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
supportActionBar?.setDisplayShowCustomEnabled(true)
setNavBarColor(content.rootWindowInsets)
nav.isVisible = false
content.doOnApplyWindowInsets { v, insets, _ ->
setNavBarColor(insets)
val contextView = window?.decorView?.findViewById<View>(R.id.action_mode_bar)
contextView?.updateLayoutParams<ViewGroup.MarginLayoutParams> {
leftMargin = insets.systemWindowInsetLeft
rightMargin = insets.systemWindowInsetRight
}
// Consume any horizontal insets and pad all content in. There's not much we can do
// with horizontal insets
v.updatePadding(
left = insets.systemWindowInsetLeft,
right = insets.systemWindowInsetRight
)
binding.appBar.updatePadding(
top = insets.systemWindowInsetTop
)
binding.bottomNav?.updatePadding(bottom = insets.systemWindowInsetBottom)
binding.sideNav?.updatePadding(
left = insets.systemWindowInsetLeft,
right = insets.systemWindowInsetRight
)
binding.bottomView?.isVisible = insets.systemWindowInsetBottom > 0
binding.bottomView?.updateLayoutParams<ViewGroup.LayoutParams> {
height = insets.systemWindowInsetBottom
}
}
router = Conductor.attachRouter(this, container, savedInstanceState)
if (router.hasRootController()) {
nav.selectedItemId =
when (router.backstack.firstOrNull()?.controller) {
is RecentsController -> R.id.nav_recents
is BrowseController -> R.id.nav_browse
else -> R.id.nav_library
}
}
nav.setOnItemSelectedListener { item ->
val id = item.itemId val id = item.itemId
val currentController = router.backstack.lastOrNull()?.controller val currentController = router.backstack.lastOrNull()?.controller
if (!continueSwitchingTabs && currentController is BottomNavBarInterface) { if (!continueSwitchingTabs && currentController is BottomNavBarInterface) {
if (!currentController.canChangeTabs { if (!currentController.canChangeTabs {
continueSwitchingTabs = true continueSwitchingTabs = true
this@MainActivity.binding.bottomNav.selectedItemId = id this@MainActivity.nav.selectedItemId = id
} }
) return@setOnNavigationItemSelectedListener false ) return@setOnItemSelectedListener false
} }
continueSwitchingTabs = false continueSwitchingTabs = false
val currentRoot = router.backstack.firstOrNull() val currentRoot = router.backstack.firstOrNull()
@ -226,43 +280,7 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
} }
true true
} }
val container: ViewGroup = binding.controllerContainer
val content: ViewGroup = binding.mainContent
DownloadService.addListener(this)
content.systemUiVisibility =
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
container.systemUiVisibility =
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
supportActionBar?.setDisplayShowCustomEnabled(true)
setNavBarColor(content.rootWindowInsets)
binding.bottomView.isVisible = false
content.doOnApplyWindowInsets { v, insets, _ ->
setNavBarColor(insets)
val contextView = window?.decorView?.findViewById<View>(R.id.action_mode_bar)
contextView?.updateLayoutParams<ViewGroup.MarginLayoutParams> {
leftMargin = insets.systemWindowInsetLeft
rightMargin = insets.systemWindowInsetRight
}
// Consume any horizontal insets and pad all content in. There's not much we can do
// with horizontal insets
v.updatePadding(
left = insets.systemWindowInsetLeft,
right = insets.systemWindowInsetRight
)
binding.appBar.updatePadding(
top = insets.systemWindowInsetTop
)
binding.bottomNav.updatePadding(bottom = insets.systemWindowInsetBottom)
binding.bottomView.isVisible = insets.systemWindowInsetBottom > 0
binding.bottomView.updateLayoutParams<ViewGroup.LayoutParams> {
height = insets.systemWindowInsetBottom
}
}
router = Conductor.attachRouter(this, container, savedInstanceState)
if (!router.hasRootController()) { if (!router.hasRootController()) {
// Set start screen // Set start screen
if (!handleIntentAction(intent)) { if (!handleIntentAction(intent)) {
@ -288,9 +306,9 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
binding.cardToolbar.menu.findItem(R.id.action_search)?.expandActionView() binding.cardToolbar.menu.findItem(R.id.action_search)?.expandActionView()
} }
binding.bottomNav.isVisible = !hideBottomNav nav.isVisible = !hideBottomNav
binding.bottomView.visibility = if (hideBottomNav) View.GONE else binding.bottomView.visibility binding.bottomView?.visibility = if (hideBottomNav) View.GONE else binding.bottomView?.visibility ?: View.GONE
binding.bottomNav.alpha = if (hideBottomNav) 0f else 1f nav.alpha = if (hideBottomNav) 0f else 1f
router.addChangeListener( router.addChangeListener(
object : ControllerChangeHandler.ControllerChangeListener { object : ControllerChangeHandler.ControllerChangeListener {
override fun onChangeStarted( override fun onChangeStarted(
@ -303,7 +321,7 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
syncActivityViewWithController(to, from, isPush) syncActivityViewWithController(to, from, isPush)
binding.appBar.y = 0f binding.appBar.y = 0f
if (!isPush || router.backstackSize == 1) { if (!isPush || router.backstackSize == 1) {
binding.bottomNav.translationY = 0f nav.translationY = 0f
} }
snackBar?.dismiss() snackBar?.dismiss()
} }
@ -316,7 +334,7 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
handler: ControllerChangeHandler handler: ControllerChangeHandler
) { ) {
binding.appBar.y = 0f binding.appBar.y = 0f
binding.bottomNav.translationY = 0f nav.translationY = 0f
showDLQueueTutorial() showDLQueueTutorial()
} }
} }
@ -348,10 +366,10 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
binding.cardToolbar.setIncognitoMode(it) binding.cardToolbar.setIncognitoMode(it)
} }
setExtensionsBadge() setExtensionsBadge()
setFloatingToolbar(canShowFloatingToolbar(router.backstack.lastOrNull()?.controller)) setFloatingToolbar(canShowFloatingToolbar(router.backstack.lastOrNull()?.controller), changeBG = false)
} }
open fun setFloatingToolbar(show: Boolean, solidBG: Boolean = false) { open fun setFloatingToolbar(show: Boolean, solidBG: Boolean = false, changeBG: Boolean = true) {
val oldTB = currentToolbar val oldTB = currentToolbar
currentToolbar = if (show) { currentToolbar = if (show) {
binding.cardToolbar binding.cardToolbar
@ -363,9 +381,11 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
} }
binding.toolbar.isVisible = !show binding.toolbar.isVisible = !show
binding.cardFrame.isVisible = show binding.cardFrame.isVisible = show
binding.appBar.setBackgroundColor( if (changeBG) {
if (show && !solidBG) Color.TRANSPARENT else getResourceColor(R.attr.colorSecondary) binding.appBar.setBackgroundColor(
) if (show && !solidBG) Color.TRANSPARENT else getResourceColor(R.attr.colorSecondary)
)
}
currentToolbar?.setNavigationOnClickListener { currentToolbar?.setNavigationOnClickListener {
val rootSearchController = router.backstack.lastOrNull()?.controller val rootSearchController = router.backstack.lastOrNull()?.controller
if (rootSearchController is RootSearchInterface) { if (rootSearchController is RootSearchInterface) {
@ -435,10 +455,10 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
private fun setExtensionsBadge() { private fun setExtensionsBadge() {
val updates = preferences.extensionUpdatesCount().getOrDefault() val updates = preferences.extensionUpdatesCount().getOrDefault()
if (updates > 0) { if (updates > 0) {
val badge = binding.bottomNav.getOrCreateBadge(R.id.nav_browse) val badge = nav.getOrCreateBadge(R.id.nav_browse)
badge.number = updates badge.number = updates
} else { } else {
binding.bottomNav.removeBadge(R.id.nav_browse) nav.removeBadge(R.id.nav_browse)
} }
} }
@ -455,7 +475,7 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
downloadManager.hasQueue() && !preferences.shownDownloadQueueTutorial().get() downloadManager.hasQueue() && !preferences.shownDownloadQueueTutorial().get()
) { ) {
if (!isBindingInitialized) return if (!isBindingInitialized) return
val recentsItem = binding.bottomNav.getItemView(R.id.nav_recents) ?: return val recentsItem = nav.getItemView(R.id.nav_recents) ?: return
preferences.shownDownloadQueueTutorial().set(true) preferences.shownDownloadQueueTutorial().set(true)
TapTargetView.showFor( TapTargetView.showFor(
this, this,
@ -474,7 +494,7 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
object : TapTargetView.Listener() { object : TapTargetView.Listener() {
override fun onTargetClick(view: TapTargetView) { override fun onTargetClick(view: TapTargetView) {
super.onTargetClick(view) super.onTargetClick(view)
binding.bottomNav.selectedItemId = R.id.nav_recents nav.selectedItemId = R.id.nav_recents
} }
} }
) )
@ -540,14 +560,14 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
intent.getIntExtra("groupId", 0) intent.getIntExtra("groupId", 0)
) )
when (intent.action) { when (intent.action) {
SHORTCUT_LIBRARY -> binding.bottomNav.selectedItemId = R.id.nav_library SHORTCUT_LIBRARY -> nav.selectedItemId = R.id.nav_library
SHORTCUT_RECENTLY_UPDATED, SHORTCUT_RECENTLY_READ -> { SHORTCUT_RECENTLY_UPDATED, SHORTCUT_RECENTLY_READ -> {
if (binding.bottomNav.selectedItemId != R.id.nav_recents) { if (nav.selectedItemId != R.id.nav_recents) {
binding.bottomNav.selectedItemId = R.id.nav_recents nav.selectedItemId = R.id.nav_recents
} else { } else {
router.popToRoot() router.popToRoot()
} }
binding.bottomNav.post { nav.post {
val controller = val controller =
router.backstack.firstOrNull()?.controller as? RecentsController router.backstack.firstOrNull()?.controller as? RecentsController
controller?.tempJumpTo( controller?.tempJumpTo(
@ -558,14 +578,14 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
) )
} }
} }
SHORTCUT_BROWSE -> binding.bottomNav.selectedItemId = R.id.nav_browse SHORTCUT_BROWSE -> nav.selectedItemId = R.id.nav_browse
SHORTCUT_EXTENSIONS -> { SHORTCUT_EXTENSIONS -> {
if (binding.bottomNav.selectedItemId != R.id.nav_browse) { if (nav.selectedItemId != R.id.nav_browse) {
binding.bottomNav.selectedItemId = R.id.nav_browse nav.selectedItemId = R.id.nav_browse
} else { } else {
router.popToRoot() router.popToRoot()
} }
binding.bottomNav.post { nav.post {
val controller = val controller =
router.backstack.firstOrNull()?.controller as? BrowseController router.backstack.firstOrNull()?.controller as? BrowseController
controller?.showSheet() controller?.showSheet()
@ -573,25 +593,25 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
} }
SHORTCUT_MANGA -> { SHORTCUT_MANGA -> {
val extras = intent.extras ?: return false val extras = intent.extras ?: return false
if (router.backstack.isEmpty()) binding.bottomNav.selectedItemId = R.id.nav_library if (router.backstack.isEmpty()) nav.selectedItemId = R.id.nav_library
router.pushController(MangaDetailsController(extras).withFadeTransaction()) router.pushController(MangaDetailsController(extras).withFadeTransaction())
} }
SHORTCUT_UPDATE_NOTES -> { SHORTCUT_UPDATE_NOTES -> {
val extras = intent.extras ?: return false val extras = intent.extras ?: return false
if (router.backstack.isEmpty()) binding.bottomNav.selectedItemId = R.id.nav_library if (router.backstack.isEmpty()) nav.selectedItemId = R.id.nav_library
if (router.backstack.lastOrNull()?.controller !is AboutController.NewUpdateDialogController) { if (router.backstack.lastOrNull()?.controller !is AboutController.NewUpdateDialogController) {
AboutController.NewUpdateDialogController(extras).showDialog(router) AboutController.NewUpdateDialogController(extras).showDialog(router)
} }
} }
SHORTCUT_SOURCE -> { SHORTCUT_SOURCE -> {
val extras = intent.extras ?: return false val extras = intent.extras ?: return false
if (router.backstack.isEmpty()) binding.bottomNav.selectedItemId = R.id.nav_library if (router.backstack.isEmpty()) nav.selectedItemId = R.id.nav_library
router.pushController(BrowseSourceController(extras).withFadeTransaction()) router.pushController(BrowseSourceController(extras).withFadeTransaction())
} }
SHORTCUT_DOWNLOADS -> { SHORTCUT_DOWNLOADS -> {
binding.bottomNav.selectedItemId = R.id.nav_recents nav.selectedItemId = R.id.nav_recents
router.popToRoot() router.popToRoot()
binding.bottomNav.post { nav.post {
val controller = val controller =
router.backstack.firstOrNull()?.controller as? RecentsController router.backstack.firstOrNull()?.controller as? RecentsController
controller?.showSheet() controller?.showSheet()
@ -619,7 +639,7 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
else !router.handleBack() else !router.handleBack()
) { ) {
if (preferences.backReturnsToStart().get() && this !is SearchActivity && if (preferences.backReturnsToStart().get() && this !is SearchActivity &&
startingTab() != binding.bottomNav.selectedItemId startingTab() != nav.selectedItemId
) { ) {
goToStartingTab() goToStartingTab()
} else { } else {
@ -633,13 +653,16 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
} }
} }
protected val nav: NavigationBarView
get() = binding.bottomNav ?: binding.sideNav!!
private fun setStartingTab() { private fun setStartingTab() {
if (this is SearchActivity) return if (this is SearchActivity) return
if (binding.bottomNav.selectedItemId != R.id.nav_browse && if (nav.selectedItemId != R.id.nav_browse &&
preferences.startingTab().get() >= 0 preferences.startingTab().get() >= 0
) { ) {
preferences.startingTab().set( preferences.startingTab().set(
when (binding.bottomNav.selectedItemId) { when (nav.selectedItemId) {
R.id.nav_library -> 0 R.id.nav_library -> 0
else -> 1 else -> 1
} }
@ -658,7 +681,7 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
} }
private fun goToStartingTab() { private fun goToStartingTab() {
binding.bottomNav.selectedItemId = startingTab() nav.selectedItemId = startingTab()
} }
private fun setRoot(controller: Controller, id: Int) { private fun setRoot(controller: Controller, id: Int) {
@ -750,27 +773,33 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
binding.cardToolbar.subtitle = null binding.cardToolbar.subtitle = null
drawerArrow?.progress = 1f drawerArrow?.progress = 1f
binding.bottomNav.visibility = if (!hideBottomNav) View.VISIBLE else binding.bottomNav.visibility nav.visibility = if (!hideBottomNav) View.VISIBLE else nav.visibility
animationSet?.cancel() if (isTablet()) {
animationSet = AnimatorSet() nav.isVisible = !hideBottomNav
val alphaAnimation = ValueAnimator.ofFloat( nav.alpha = 1f
binding.bottomNav.alpha, } else {
if (hideBottomNav) 0f else 1f animationSet?.cancel()
) animationSet = AnimatorSet()
alphaAnimation.addUpdateListener { valueAnimator -> val alphaAnimation = ValueAnimator.ofFloat(
binding.bottomNav.alpha = valueAnimator.animatedValue as Float nav.alpha,
} if (hideBottomNav) 0f else 1f
alphaAnimation.addListener( )
EndAnimatorListener { alphaAnimation.addUpdateListener { valueAnimator ->
binding.bottomNav.isVisible = !hideBottomNav nav.alpha = valueAnimator.animatedValue as Float
binding.bottomView.visibility =
if (hideBottomNav) View.GONE else binding.bottomView.visibility
} }
) alphaAnimation.addListener(
alphaAnimation.duration = 200 EndAnimatorListener {
alphaAnimation.startDelay = 50 nav.isVisible = !hideBottomNav
animationSet?.playTogether(alphaAnimation) binding.bottomView?.visibility =
animationSet?.start() if (hideBottomNav) View.GONE else binding.bottomView?.visibility
?: View.GONE
}
)
alphaAnimation.duration = 200
alphaAnimation.startDelay = 50
animationSet?.playTogether(alphaAnimation)
animationSet?.start()
}
} }
fun showTabBar(show: Boolean, animate: Boolean = true) { fun showTabBar(show: Boolean, animate: Boolean = true) {
@ -810,10 +839,10 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
val hasQueue = downloading || downloadManager.hasQueue() val hasQueue = downloading || downloadManager.hasQueue()
launchUI { launchUI {
if (hasQueue) { if (hasQueue) {
binding.bottomNav.getOrCreateBadge(R.id.nav_recents) nav.getOrCreateBadge(R.id.nav_recents)
showDLQueueTutorial() showDLQueueTutorial()
} else { } else {
binding.bottomNav.removeBadge(R.id.nav_recents) nav.removeBadge(R.id.nav_recents)
} }
} }
} }
@ -867,7 +896,7 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
val diffX = e2.x - e1.x val diffX = e2.x - e1.x
if (abs(diffX) <= abs(diffY)) { if (abs(diffX) <= abs(diffY)) {
val sheetRect = Rect() val sheetRect = Rect()
binding.bottomNav.getGlobalVisibleRect(sheetRect) binding.bottomNav?.getGlobalVisibleRect(sheetRect)
if (sheetRect.contains(e1.x.toInt(), e1.y.toInt()) && if (sheetRect.contains(e1.x.toInt(), e1.y.toInt()) &&
abs(diffY) > Companion.SWIPE_THRESHOLD && abs(diffY) > Companion.SWIPE_THRESHOLD &&
abs(velocityY) > Companion.SWIPE_VELOCITY_THRESHOLD && abs(velocityY) > Companion.SWIPE_VELOCITY_THRESHOLD &&

View File

@ -51,8 +51,8 @@ class SearchActivity : MainActivity() {
} }
} }
override fun setFloatingToolbar(show: Boolean, solidBG: Boolean) { override fun setFloatingToolbar(show: Boolean, solidBG: Boolean, changeBG: Boolean) {
super.setFloatingToolbar(show, solidBG) super.setFloatingToolbar(show, solidBG, changeBG)
currentToolbar?.setNavigationOnClickListener { popToRoot() } currentToolbar?.setNavigationOnClickListener { popToRoot() }
} }
@ -73,8 +73,8 @@ class SearchActivity : MainActivity() {
binding.toolbar.navigationIcon = drawerArrow binding.toolbar.navigationIcon = drawerArrow
drawerArrow?.progress = 1f drawerArrow?.progress = 1f
binding.bottomNav.isVisible = false nav.isVisible = false
binding.bottomView.isVisible = false binding.bottomView?.isVisible = false
} }
override fun handleIntentAction(intent: Intent): Boolean { override fun handleIntentAction(intent: Intent): Boolean {

View File

@ -163,11 +163,11 @@ class RecentsController(bundle: Bundle? = null) :
height = it.systemWindowInsetTop + (toolbarHeight ?: appBarHeight) height = it.systemWindowInsetTop + (toolbarHeight ?: appBarHeight)
} }
binding.recycler.updatePaddingRelative( binding.recycler.updatePaddingRelative(
bottom = activityBinding?.bottomNav?.height ?: 0 bottom = activityBinding?.bottomNav?.height ?: it.systemWindowInsetBottom
) )
binding.recentsEmptyView.updateLayoutParams<ViewGroup.MarginLayoutParams> { binding.recentsEmptyView.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = headerHeight topMargin = headerHeight
bottomMargin = activityBinding?.bottomNav?.height ?: 0 bottomMargin = activityBinding?.bottomNav?.height ?: it.systemWindowInsetBottom
} }
}, },
onBottomNavUpdate = { onBottomNavUpdate = {
@ -182,10 +182,11 @@ class RecentsController(bundle: Bundle? = null) :
} }
) )
activityBinding?.bottomNav?.post { activityBinding?.root?.post {
binding.recycler.updatePaddingRelative(bottom = activityBinding?.bottomNav?.height ?: 0) val height = activityBinding?.bottomNav?.height ?: view.rootWindowInsets?.systemWindowInsetBottom ?: 0
binding.recycler.updatePaddingRelative(bottom = height)
binding.downloadBottomSheet.dlRecycler.updatePaddingRelative( binding.downloadBottomSheet.dlRecycler.updatePaddingRelative(
bottom = activityBinding?.bottomNav?.height ?: 0 bottom = height
) )
val isExpanded = binding.downloadBottomSheet.root.sheetBehavior.isExpanded() val isExpanded = binding.downloadBottomSheet.root.sheetBehavior.isExpanded()
activityBinding?.tabsFrameLayout?.isVisible = !isExpanded activityBinding?.tabsFrameLayout?.isVisible = !isExpanded

View File

@ -22,17 +22,18 @@ import com.bluelinelabs.conductor.Controller
import com.bluelinelabs.conductor.ControllerChangeHandler import com.bluelinelabs.conductor.ControllerChangeHandler
import com.bluelinelabs.conductor.ControllerChangeType import com.bluelinelabs.conductor.ControllerChangeType
import com.bluelinelabs.conductor.RouterTransaction import com.bluelinelabs.conductor.RouterTransaction
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.databinding.MainActivityBinding import eu.kanade.tachiyomi.databinding.MainActivityBinding
import eu.kanade.tachiyomi.ui.base.MaterialFastScroll import eu.kanade.tachiyomi.ui.base.MaterialFastScroll
import eu.kanade.tachiyomi.ui.base.controller.OneWayFadeChangeHandler
import eu.kanade.tachiyomi.ui.main.BottomSheetController import eu.kanade.tachiyomi.ui.main.BottomSheetController
import eu.kanade.tachiyomi.ui.main.FloatingSearchInterface import eu.kanade.tachiyomi.ui.main.FloatingSearchInterface
import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.system.isTablet
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
@ -171,6 +172,9 @@ fun Controller.scrollViewWith(
var statusBarHeight = -1 var statusBarHeight = -1
val tabBarHeight = 48.dpToPx val tabBarHeight = 48.dpToPx
activityBinding?.appBar?.y = 0f activityBinding?.appBar?.y = 0f
activityBinding?.tabsFrameLayout?.elevation = 0f
val isTabletWithTabs = recycler.context.isTablet() && includeTabView
activityBinding?.tabShadow?.isVisible = isTabletWithTabs
val attrsArray = intArrayOf(R.attr.actionBarSize) val attrsArray = intArrayOf(R.attr.actionBarSize)
val array = recycler.context.obtainStyledAttributes(attrsArray) val array = recycler.context.obtainStyledAttributes(attrsArray)
var appBarHeight = ( var appBarHeight = (
@ -226,17 +230,33 @@ fun Controller.scrollViewWith(
liftOnScroll.invoke(el) liftOnScroll.invoke(el)
} else { } else {
elevationAnim?.cancel() elevationAnim?.cancel()
val floatingBar = (this as? FloatingSearchInterface)?.showFloatingBar() == true && !includeTabView if (isTabletWithTabs && el) {
activityBinding?.tabShadow?.isVisible = true
}
val floatingBar =
(this as? FloatingSearchInterface)?.showFloatingBar() == true && !includeTabView
if (floatingBar) { if (floatingBar) {
activityBinding?.appBar?.elevation = 0f if (isTabletWithTabs) {
activityBinding?.tabShadow?.alpha = 0f
} else {
activityBinding?.appBar?.elevation = 0f
}
return@f return@f
} }
elevationAnim = ValueAnimator.ofFloat( elevationAnim = ValueAnimator.ofFloat(
activityBinding?.appBar?.elevation ?: 0f, if (isTabletWithTabs) {
(activityBinding?.tabShadow?.alpha ?: 0f) * 100
} else {
activityBinding?.appBar?.elevation ?: 0f
},
if (el) 15f else 0f if (el) 15f else 0f
) )
elevationAnim?.addUpdateListener { valueAnimator -> elevationAnim?.addUpdateListener { valueAnimator ->
activityBinding?.appBar?.elevation = valueAnimator.animatedValue as Float if (isTabletWithTabs) {
activityBinding?.tabShadow?.alpha = valueAnimator.animatedValue as Float / 100
} else {
activityBinding?.appBar?.elevation = valueAnimator.animatedValue as Float
}
} }
elevationAnim?.start() elevationAnim?.start()
} }
@ -254,6 +274,7 @@ fun Controller.scrollViewWith(
super.onChangeStart(controller, changeHandler, changeType) super.onChangeStart(controller, changeHandler, changeType)
isInView = changeType.isEnter isInView = changeType.isEnter
if (changeType.isEnter) { if (changeType.isEnter) {
activityBinding?.tabShadow?.isVisible = isTabletWithTabs
elevateFunc(elevate) elevateFunc(elevate)
if (fakeToolbarView?.parent != null) { if (fakeToolbarView?.parent != null) {
val parent = fakeToolbarView?.parent as? ViewGroup ?: return val parent = fakeToolbarView?.parent as? ViewGroup ?: return
@ -275,6 +296,7 @@ fun Controller.scrollViewWith(
} }
} }
} else { } else {
activityBinding?.tabShadow?.isVisible = false
if (!customPadding && lastY == 0f && ( if (!customPadding && lastY == 0f && (
( (
this@scrollViewWith !is FloatingSearchInterface && router.backstack.lastOrNull() this@scrollViewWith !is FloatingSearchInterface && router.backstack.lastOrNull()
@ -318,6 +340,7 @@ fun Controller.scrollViewWith(
recycler.post { recycler.post {
elevateFunc(recycler.canScrollVertically(-1)) elevateFunc(recycler.canScrollVertically(-1))
} }
val isTablet = recycler.context.isTablet()
recycler.addOnScrollListener( recycler.addOnScrollListener(
object : RecyclerView.OnScrollListener() { object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
@ -336,7 +359,7 @@ fun Controller.scrollViewWith(
.setDuration(shortAnimationDuration.toLong()) .setDuration(shortAnimationDuration.toLong())
.start() .start()
if (router.backstackSize == 1 && isInView) { if (router.backstackSize == 1 && isInView) {
activityBinding!!.bottomNav.let { activityBinding!!.bottomNav?.let {
val animator = it.animate()?.translationY(0f) val animator = it.animate()?.translationY(0f)
?.setDuration(shortAnimationDuration.toLong()) ?.setDuration(shortAnimationDuration.toLong())
animator?.setUpdateListener { animator?.setUpdateListener {
@ -348,36 +371,43 @@ fun Controller.scrollViewWith(
lastY = 0f lastY = 0f
if (elevate) elevateFunc(false) if (elevate) elevateFunc(false)
} else { } else {
activityBinding!!.appBar.y -= dy if (!isTablet) {
activityBinding!!.appBar.y = MathUtils.clamp( activityBinding!!.appBar.y -= dy
activityBinding!!.appBar.y, activityBinding!!.appBar.y = MathUtils.clamp(
-activityBinding!!.appBar.height.toFloat(), activityBinding!!.appBar.y,
0f -activityBinding!!.appBar.height.toFloat(),
) 0f
val tabBar = activityBinding!!.bottomNav
if (tabBar.isVisible && isInView) {
if (preferences.hideBottomNavOnScroll().get()) {
tabBar.translationY += dy
tabBar.translationY = MathUtils.clamp(
tabBar.translationY,
0f,
tabBar.height.toFloat()
)
updateViewsNearBottom()
} else if (tabBar.translationY != 0f) {
tabBar.translationY = 0f
activityBinding!!.bottomView?.translationY = 0f
}
}
if (!elevate && (
dy == 0 ||
(
activityBinding!!.appBar.y <= -activityBinding!!.appBar.height.toFloat() ||
dy == 0 && activityBinding!!.appBar.y == 0f
)
) )
) { activityBinding!!.bottomNav?.let { bottomNav ->
elevateFunc(true) if (bottomNav.isVisible && isInView) {
if (preferences.hideBottomNavOnScroll().get()) {
bottomNav.translationY += dy
bottomNav.translationY = MathUtils.clamp(
bottomNav.translationY,
0f,
bottomNav.height.toFloat()
)
updateViewsNearBottom()
} else if (bottomNav.translationY != 0f) {
bottomNav.translationY = 0f
activityBinding!!.bottomView?.translationY = 0f
}
}
}
if (!elevate && (
dy == 0 ||
(
activityBinding!!.appBar.y <= -activityBinding!!.appBar.height.toFloat() ||
dy == 0 && activityBinding!!.appBar.y == 0f
)
)
) {
elevateFunc(true)
}
} else {
val notAtTop = recycler.canScrollVertically(-1)
if (notAtTop != elevate) elevateFunc(notAtTop)
} }
lastY = activityBinding!!.appBar.y lastY = activityBinding!!.appBar.y
} }
@ -387,6 +417,9 @@ fun Controller.scrollViewWith(
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState) super.onScrollStateChanged(recyclerView, newState)
if (newState == RecyclerView.SCROLL_STATE_IDLE) { if (newState == RecyclerView.SCROLL_STATE_IDLE) {
if (isTablet) {
return
}
if (router?.backstack?.lastOrNull() if (router?.backstack?.lastOrNull()
?.controller == this@scrollViewWith && statusBarHeight > -1 && ?.controller == this@scrollViewWith && statusBarHeight > -1 &&
activity != null && activityBinding!!.appBar.height > 0 && activity != null && activityBinding!!.appBar.height > 0 &&
@ -397,18 +430,20 @@ fun Controller.scrollViewWith(
android.R.integer.config_shortAnimTime android.R.integer.config_shortAnimTime
) ?: 0 ) ?: 0
val closerToTop = abs(activityBinding!!.appBar.y) > halfWay val closerToTop = abs(activityBinding!!.appBar.y) > halfWay
val halfWayBottom = activityBinding!!.bottomNav.height.toFloat() / 2 val halfWayBottom = (activityBinding!!.bottomNav?.height?.toFloat() ?: 0f) / 2
val closerToBottom = activityBinding!!.bottomNav.translationY > halfWayBottom val closerToBottom = activityBinding!!.bottomNav?.translationY ?: 0f > halfWayBottom
val atTop = !recycler.canScrollVertically(-1) val atTop = !recycler.canScrollVertically(-1)
val closerToEdge = val closerToEdge =
if (activityBinding!!.bottomNav.isVisible && if (activityBinding!!.bottomNav?.isVisible == true &&
preferences.hideBottomNavOnScroll().get() preferences.hideBottomNavOnScroll().get()
) closerToBottom else closerToTop ) closerToBottom else closerToTop
lastY = lastY =
if (closerToEdge && !atTop) (-activityBinding!!.appBar.height.toFloat()) else 0f if (closerToEdge && !atTop) (-activityBinding!!.appBar.height.toFloat()) else 0f
activityBinding!!.appBar.animate().y(lastY) activityBinding!!.appBar.animate().y(lastY)
.setDuration(shortAnimationDuration.toLong()).start() .setDuration(shortAnimationDuration.toLong()).start()
if (activityBinding!!.bottomNav.isVisible && isInView && preferences.hideBottomNavOnScroll().get()) { if (activityBinding!!.bottomNav?.isVisible == true &&
isInView && preferences.hideBottomNavOnScroll().get()
) {
activityBinding!!.bottomNav?.let { activityBinding!!.bottomNav?.let {
val lastBottomY = val lastBottomY =
if (closerToEdge && !atTop) it.height.toFloat() else 0f if (closerToEdge && !atTop) it.height.toFloat() else 0f
@ -447,8 +482,8 @@ fun Controller.requestPermissionsSafe(permissions: Array<String>, requestCode: I
fun Controller.withFadeTransaction(): RouterTransaction { fun Controller.withFadeTransaction(): RouterTransaction {
return RouterTransaction.with(this) return RouterTransaction.with(this)
.pushChangeHandler(FadeChangeHandler()) .pushChangeHandler(OneWayFadeChangeHandler())
.popChangeHandler(FadeChangeHandler()) .popChangeHandler(OneWayFadeChangeHandler())
} }
fun Controller.openInBrowser(url: String) { fun Controller.openInBrowser(url: String) {

View File

@ -31,10 +31,10 @@ import androidx.recyclerview.widget.LinearSmoothScroller
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.SmoothScroller import androidx.recyclerview.widget.RecyclerView.SmoothScroller
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.google.android.material.bottomnavigation.BottomNavigationItemView
import com.google.android.material.bottomnavigation.BottomNavigationMenuView
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import com.google.android.material.navigation.NavigationBarItemView
import com.google.android.material.navigation.NavigationBarMenuView
import com.google.android.material.navigation.NavigationBarView
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.lang.tintText import eu.kanade.tachiyomi.util.lang.tintText
@ -259,9 +259,9 @@ fun TextView.setTextColorRes(@ColorRes id: Int) {
} }
@SuppressLint("RestrictedApi") @SuppressLint("RestrictedApi")
fun BottomNavigationView.getItemView(@IdRes id: Int): BottomNavigationItemView? { fun NavigationBarView.getItemView(@IdRes id: Int): NavigationBarItemView? {
val order = (menu as MenuBuilder).findItemIndex(id) val order = (menu as MenuBuilder).findItemIndex(id)
return (getChildAt(0) as BottomNavigationMenuView).getChildAt(order) as? BottomNavigationItemView return (getChildAt(0) as NavigationBarMenuView).getChildAt(order) as? NavigationBarItemView
} }
fun RecyclerView.smoothScrollToTop() { fun RecyclerView.smoothScrollToTop() {

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="180"
android:endColor="@android:color/transparent"
android:startColor="@color/md_black_1000_54"/>
</shape>

View File

@ -0,0 +1,220 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.bluelinelabs.conductor.ChangeHandlerFrameLayout
android:id="@+id/controller_container"
android:layout_width="0dp"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@id/side_nav"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0">
</com.bluelinelabs.conductor.ChangeHandlerFrameLayout>
<com.google.android.material.navigationrail.NavigationRailView
android:id="@+id/side_nav"
style="@style/Widget.MaterialComponents.NavigationRailView.Colored"
android:background="?android:colorBackground"
android:layout_width="wrap_content"
android:layout_height="0dp"
app:itemIconTint="@color/bottom_nav_item_selector"
app:itemRippleColor="@color/fullRippleColor"
app:itemTextColor="@color/bottom_nav_item_selector"
app:labelVisibilityMode="labeled"
android:translationZ="-10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/app_bar"
app:menu="@menu/bottom_navigation" />
<View
android:id="@+id/shadow_gap"
android:layout_width="1dp"
android:layout_height="16dp"
app:layout_constraintEnd_toEndOf="@id/side_nav"
app:layout_constraintBottom_toTopOf="@id/side_nav" />
<View
android:id="@+id/side_shadow"
android:layout_width="6dp"
android:layout_height="0dp"
android:layout_gravity="bottom"
android:alpha="0.13"
android:translationZ="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@id/side_nav"
app:layout_constraintTop_toTopOf="@id/shadow_gap"
android:background="@drawable/shape_gradient_start_shadow" />
<FrameLayout
android:id="@+id/tabs_frame_layout"
android:clickable="true"
android:visibility="gone"
android:layout_width="0dp"
android:background="?attr/colorSecondary"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/app_bar"
app:layout_constraintStart_toEndOf="@id/side_nav"
app:layout_constraintEnd_toEndOf="parent"
tools:visibility="visible"
tools:ignore="KeyboardInaccessibleWidget">
<com.google.android.material.tabs.TabLayout
android:id="@+id/main_tabs"
style="@style/Theme.Widget.Tabs.Highlight"
android:background="?attr/colorSecondary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:layout_marginEnd="6dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:tabGravity="fill"/>
</FrameLayout>
<View
android:id="@+id/tab_shadow"
android:layout_width="0dp"
android:visibility="gone"
android:layout_height="6dp"
android:rotation="180"
android:alpha="0.15"
android:background="@drawable/shape_gradient_top_shadow"
app:layout_constraintStart_toStartOf="@id/tabs_frame_layout"
app:layout_constraintEnd_toEndOf="@id/tabs_frame_layout"
app:layout_constraintTop_toBottomOf="@id/tabs_frame_layout"
android:paddingBottom="10dp" />
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorSecondary"
android:stateListAnimator="@null"
android:theme="?attr/actionBarTheme"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<eu.kanade.tachiyomi.ui.base.CenteredToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
app:titleTextColor="?actionBarTintColor"
android:layout_height="?attr/actionBarSize"
app:collapseIcon="@drawable/ic_arrow_back_24dp"
android:background="?attr/colorSecondary">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/toolbar_title"
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTint="?actionBarTintColor"
android:ellipsize="end"
android:layout_gravity="center"
android:maxLines="1"
android:textColor="?actionBarTintColor"
android:textSize="20sp"
tools:drawableEnd="@drawable/ic_arrow_drop_down_24dp"
tools:drawableStart="@drawable/ic_blank_24dp"
tools:text="Title Text" />
</eu.kanade.tachiyomi.ui.base.CenteredToolbar>
<FrameLayout
android:id="@+id/card_frame"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" >
<androidx.cardview.widget.CardView
android:id="@+id/card_view"
android:layout_width="match_parent"
android:layout_marginTop="4dp"
app:cardBackgroundColor="?colorPrimaryVariant"
android:layout_marginBottom="4dp"
android:layout_marginStart="14dp"
android:layout_marginEnd="14dp"
app:cardCornerRadius="8dp"
android:layout_height="match_parent" >
<eu.kanade.tachiyomi.ui.base.FloatingToolbar
android:id="@+id/card_toolbar"
tools:title="Search Library..."
app:contentInsetStartWithNavigation="0dp"
app:contentInsetEndWithActions="0dp"
app:contentInsetStart="0dp"
app:contentInsetEnd="0dp"
android:background="@drawable/rect_ripple"
app:navigationIconTint="@color/text_color_secondary"
app:navigationIcon="@drawable/ic_search_24dp"
app:titleTextAppearance="@style/TextAppearance.MaterialComponents.Body1"
app:subtitleTextAppearance="@style/TextAppearance.MaterialComponents.Caption"
app:collapseIcon="@drawable/ic_arrow_back_24dp"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="start|center"
android:orientation="horizontal">
<ImageView
android:id="@+id/card_incog_image"
app:tint="?actionBarTintColor"
android:layout_gravity="center|start"
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_marginEnd="6dp"
android:layout_marginStart="0dp"
android:contentDescription="@string/incognito_mode"
android:src="@drawable/ic_incognito_circle_24dp"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="start|center"
android:orientation="vertical">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/card_title"
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTint="?actionBarTintColor"
android:ellipsize="end"
android:layout_gravity="center"
android:maxLines="1"
android:textColor="?actionBarTintColor"
android:textSize="20sp"
tools:drawableEnd="@drawable/ic_arrow_drop_down_24dp"
tools:drawableStart="@drawable/ic_blank_24dp"
tools:text="Title Text" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/card_subtitle"
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:layout_gravity="start|center"
android:maxLines="1"
android:textColor="?actionBarTintColor"
android:textSize="12sp"
tools:text="Title Text" />
</LinearLayout>
</LinearLayout>
</eu.kanade.tachiyomi.ui.base.FloatingToolbar>
</androidx.cardview.widget.CardView>
</FrameLayout>
</com.google.android.material.appbar.AppBarLayout>
</androidx.constraintlayout.widget.ConstraintLayout>