diff --git a/app/src/main/java/com/topjohnwu/magisk/redesign/MainActivity.kt b/app/src/main/java/com/topjohnwu/magisk/redesign/MainActivity.kt index 8d0e43c2e..d08fb6c8b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/redesign/MainActivity.kt +++ b/app/src/main/java/com/topjohnwu/magisk/redesign/MainActivity.kt @@ -3,14 +3,12 @@ package com.topjohnwu.magisk.redesign import android.graphics.Insets import android.os.Bundle import android.view.MenuItem -import android.view.ViewGroup +import android.view.View import android.view.ViewTreeObserver import androidx.coordinatorlayout.widget.CoordinatorLayout -import androidx.core.view.isVisible import androidx.core.view.setPadding import androidx.core.view.updateLayoutParams import androidx.fragment.app.Fragment -import androidx.interpolator.view.animation.FastOutSlowInInterpolator import com.google.android.material.card.MaterialCardView import com.ncapdevi.fragnav.FragNavController import com.topjohnwu.magisk.Const @@ -25,6 +23,7 @@ import com.topjohnwu.magisk.redesign.module.ModuleFragment import com.topjohnwu.magisk.redesign.superuser.SuperuserFragment import com.topjohnwu.magisk.utils.HideBottomViewOnScrollBehavior import com.topjohnwu.magisk.utils.HideTopViewOnScrollBehavior +import com.topjohnwu.magisk.utils.HideableBehavior import com.topjohnwu.superuser.Shell import org.koin.androidx.viewmodel.ext.android.viewModel import kotlin.reflect.KClass @@ -84,10 +83,9 @@ open class MainActivity : CompatActivity( if (savedInstanceState != null) { onTabTransaction(null, -1) - onFragmentTransaction(null, FragNavController.TransactionType.PUSH) if (!navigation.isRoot) { - requestNavigationHidden(animate = false) + requestNavigationHidden() } } } @@ -114,19 +112,13 @@ open class MainActivity : CompatActivity( return true } - override fun onTabTransaction(fragment: Fragment?, index: Int) { - setDisplayHomeAsUpEnabled(false) - } + override fun onTabTransaction(fragment: Fragment?, index: Int) = + onFragmentTransaction(fragment, FragNavController.TransactionType.PUSH) override fun onFragmentTransaction( fragment: Fragment?, transactionType: FragNavController.TransactionType ) { - binding.mainToolbarWrapper.animate() - .translationY(0f) - .setInterpolator(FastOutSlowInInterpolator()) - .start() - setDisplayHomeAsUpEnabled(!navigation.isRoot) requestNavigationHidden(!navigation.isRoot) } @@ -143,25 +135,19 @@ open class MainActivity : CompatActivity( } } - internal fun requestNavigationHidden(hide: Boolean = true, animate: Boolean = true) { - val lapam = binding.mainBottomBar.layoutParams as ViewGroup.MarginLayoutParams - val height = binding.mainBottomBar.measuredHeight - val verticalMargin = lapam.let { it.topMargin + it.bottomMargin } - val maxTranslation = height + verticalMargin - val translation = if (!hide) 0 else maxTranslation + @Suppress("UNCHECKED_CAST") + internal fun requestNavigationHidden(hide: Boolean = true) { + val topView = binding.mainToolbarWrapper + val bottomView = binding.mainBottomBar - if (!animate) { - binding.mainBottomBar.translationY = translation.toFloat() - binding.mainBottomBar.isVisible = !hide - return - } + val topParams = topView.layoutParams as? CoordinatorLayout.LayoutParams + val bottomParams = bottomView.layoutParams as? CoordinatorLayout.LayoutParams - binding.mainBottomBar.animate() - .translationY(translation.toFloat()) - .setInterpolator(FastOutSlowInInterpolator()) - .withStartAction { if (!hide) binding.mainBottomBar.isVisible = true } - .withEndAction { if (hide) binding.mainBottomBar.isVisible = false } - .start() + val topBehavior = topParams?.behavior as? HideableBehavior + val bottomBehavior = bottomParams?.behavior as? HideableBehavior + + topBehavior?.setHidden(topView, hide = false, lockState = false) + bottomBehavior?.setHidden(bottomView, hide, hide) } fun invalidateToolbar() { diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/HideBottomViewOnScrollBehavior.kt b/app/src/main/java/com/topjohnwu/magisk/utils/HideBottomViewOnScrollBehavior.kt index 521a1fd5d..d3009f56a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/HideBottomViewOnScrollBehavior.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/HideBottomViewOnScrollBehavior.kt @@ -11,14 +11,17 @@ import com.google.android.material.snackbar.Snackbar import com.topjohnwu.magisk.R import kotlin.math.roundToInt -class HideBottomViewOnScrollBehavior : HideBottomViewOnScrollBehavior() { +class HideBottomViewOnScrollBehavior : HideBottomViewOnScrollBehavior(), + HideableBehavior { - override fun layoutDependsOn(parent: CoordinatorLayout, child: T, dependency: View) = + private var lockState: Boolean = false + + override fun layoutDependsOn(parent: CoordinatorLayout, child: V, dependency: View) = super.layoutDependsOn(parent, child, dependency) or (dependency is Snackbar.SnackbarLayout) override fun onDependentViewChanged( parent: CoordinatorLayout, - child: T, + child: V, dependency: View ) = when (dependency) { is Snackbar.SnackbarLayout -> onDependentViewChanged(parent, child, dependency) @@ -27,7 +30,7 @@ class HideBottomViewOnScrollBehavior : HideBottomViewOnScrollBehavior< override fun onDependentViewRemoved( parent: CoordinatorLayout, - child: T, + child: V, dependency: View ) = when (dependency) { is Snackbar.SnackbarLayout -> onDependentViewRemoved(parent, child, dependency) @@ -38,7 +41,7 @@ class HideBottomViewOnScrollBehavior : HideBottomViewOnScrollBehavior< private fun onDependentViewChanged( parent: CoordinatorLayout, - child: T, + child: V, dependency: Snackbar.SnackbarLayout ): Boolean { val viewMargin = (child.layoutParams as ViewGroup.MarginLayoutParams).bottomMargin @@ -58,7 +61,7 @@ class HideBottomViewOnScrollBehavior : HideBottomViewOnScrollBehavior< private fun onDependentViewRemoved( parent: CoordinatorLayout, - child: T, + child: V, dependency: Snackbar.SnackbarLayout ) { // checks whether the navigation is not hidden via scroll @@ -69,6 +72,36 @@ class HideBottomViewOnScrollBehavior : HideBottomViewOnScrollBehavior< //--- + override fun slideUp(child: V) { + if (lockState) return + super.slideUp(child) + } + + override fun slideDown(child: V) { + if (lockState) return + super.slideDown(child) + } + + override fun setHidden( + view: V, + hide: Boolean, + lockState: Boolean + ) { + if (!lockState) { + this.lockState = lockState + } + + if (hide) { + slideDown(view) + } else { + slideUp(view) + } + + this.lockState = lockState + } + + //--- + private fun View.translationY(destination: Float) = animate() .translationY(destination) .setInterpolator(FastOutSlowInInterpolator()) diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/HideTopViewOnScrollBehavior.kt b/app/src/main/java/com/topjohnwu/magisk/utils/HideTopViewOnScrollBehavior.kt index 39650e230..66e6701ff 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/HideTopViewOnScrollBehavior.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/HideTopViewOnScrollBehavior.kt @@ -10,7 +10,8 @@ import androidx.core.view.ViewCompat import com.google.android.material.animation.AnimationUtils import com.google.android.material.behavior.HideBottomViewOnScrollBehavior -class HideTopViewOnScrollBehavior : HideBottomViewOnScrollBehavior() { +class HideTopViewOnScrollBehavior : HideBottomViewOnScrollBehavior(), + HideableBehavior { companion object { private const val STATE_SCROLLED_DOWN = 1 @@ -21,6 +22,7 @@ class HideTopViewOnScrollBehavior : HideBottomViewOnScrollBehavior( private var currentState = STATE_SCROLLED_UP private var additionalHiddenOffsetY = 0 private var currentAnimator: ViewPropertyAnimator? = null + private var lockState: Boolean = false override fun onLayoutChild( parent: CoordinatorLayout, @@ -63,10 +65,30 @@ class HideTopViewOnScrollBehavior : HideBottomViewOnScrollBehavior( dxUnconsumed: Int, dyUnconsumed: Int ) { - when { - dyConsumed > 0 -> slideUp(child) - dyConsumed < 0 -> slideDown(child) + // when initiating scroll while the view is at the bottom or at the top and pushing it + // further, the parent will report consumption of 0 + if (dyConsumed == 0) return + + setHidden(child, dyConsumed > 0, false) + } + + @Suppress("UNCHECKED_CAST") + override fun setHidden( + view: V, + hide: Boolean, + lockState: Boolean + ) { + if (!lockState) { + this.lockState = lockState } + + if (hide) { + slideUp(view) + } else { + slideDown(view) + } + + this.lockState = lockState } /** @@ -74,7 +96,7 @@ class HideTopViewOnScrollBehavior : HideBottomViewOnScrollBehavior( * screen. */ override fun slideDown(child: V) { - if (currentState == STATE_SCROLLED_UP) { + if (currentState == STATE_SCROLLED_UP || lockState) { return } @@ -97,7 +119,7 @@ class HideTopViewOnScrollBehavior : HideBottomViewOnScrollBehavior( * screen. */ override fun slideUp(child: V) { - if (currentState == STATE_SCROLLED_DOWN) { + if (currentState == STATE_SCROLLED_DOWN || lockState) { return } diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/HideableBehavior.kt b/app/src/main/java/com/topjohnwu/magisk/utils/HideableBehavior.kt new file mode 100644 index 000000000..5945472c5 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/utils/HideableBehavior.kt @@ -0,0 +1,9 @@ +package com.topjohnwu.magisk.utils + +import android.view.View + +interface HideableBehavior { + + fun setHidden(view: V, hide: Boolean, lockState: Boolean = false) + +} \ No newline at end of file