Skip to content

Commit

Permalink
Bug 1821961 - Updated the collapse animation of the tabs tray FAB & s…
Browse files Browse the repository at this point in the history
…crim
  • Loading branch information
t-p-white authored and mergify[bot] committed May 4, 2023
1 parent c3dda7c commit 444597e
Show file tree
Hide file tree
Showing 3 changed files with 650 additions and 68 deletions.
Expand Up @@ -8,41 +8,45 @@ import android.content.res.Configuration
import android.util.DisplayMetrics
import android.view.View
import androidx.annotation.VisibleForTesting
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HIDDEN
import mozilla.components.support.ktx.android.util.dpToPx

@VisibleForTesting internal const val EXPANDED_OFFSET_IN_LANDSCAPE_DP = 0

@VisibleForTesting internal const val EXPANDED_OFFSET_IN_PORTRAIT_DP = 40

/**
* The default max dim value of the [TabsTrayDialog].
*/
private const val DEFAULT_MAX_DIM = 0.6f

/**
* The dim amount is 0.0 - 1.0 inclusive. We use this to convert the view element to the dim scale.
*/
private const val DIM_CONVERSION = 1000f

/**
* Helper class for updating how the tray looks and behaves depending on app state / internal tray state.
*
* @param behavior [BottomSheetBehavior] that will actually control the tray.
* @param orientation current Configuration.ORIENTATION_* of the device.
* @param maxNumberOfTabs highest number of tabs in each tray page.
* @param numberForExpandingTray limit depending on which the tray should be collapsed or expanded.
* @param navigationInteractor [NavigationInteractor] used for tray updates / navigation.
* @param displayMetrics [DisplayMetrics] used for adapting resources to the current display.
*/
internal class TabSheetBehaviorManager(
private val behavior: BottomSheetBehavior<out View>,
orientation: Int,
private val maxNumberOfTabs: Int,
private val numberForExpandingTray: Int,
navigationInteractor: NavigationInteractor,
private val displayMetrics: DisplayMetrics,
) {
@VisibleForTesting
internal var currentOrientation = orientation

init {
behavior.skipCollapsed = true
behavior.addBottomSheetCallback(
TraySheetBehaviorCallback(behavior, navigationInteractor),
)

val isInLandscape = isLandscape(orientation)
updateBehaviorExpandedOffset(isInLandscape)
updateBehaviorState(isInLandscape)
Expand Down Expand Up @@ -83,21 +87,78 @@ internal class TabSheetBehaviorManager(
internal fun isLandscape(orientation: Int) = Configuration.ORIENTATION_LANDSCAPE == orientation
}

@VisibleForTesting
internal class TraySheetBehaviorCallback(
@get:VisibleForTesting internal val behavior: BottomSheetBehavior<out View>,
@get:VisibleForTesting internal val trayInteractor: NavigationInteractor,
private val tabsTrayDialog: TabsTrayDialog,
private var newTabFab: View,
) : BottomSheetBehavior.BottomSheetCallback() {

@VisibleForTesting
var draggedLowestSheetTop: Int? = null

override fun onStateChanged(bottomSheet: View, newState: Int) {
if (newState == STATE_HIDDEN) {
trayInteractor.onTabTrayDismissed()
} else if (newState == BottomSheetBehavior.STATE_HALF_EXPANDED) {
when (newState) {
BottomSheetBehavior.STATE_HIDDEN -> trayInteractor.onTabTrayDismissed()

// We only support expanded and collapsed states.
// Otherwise the tray may be left in an unusable state. See #14980.
behavior.state = STATE_HIDDEN
BottomSheetBehavior.STATE_HALF_EXPANDED ->
behavior.state = BottomSheetBehavior.STATE_HIDDEN

// Reset the dragged lowest top value
BottomSheetBehavior.STATE_EXPANDED, BottomSheetBehavior.STATE_COLLAPSED -> {
draggedLowestSheetTop = null
}

BottomSheetBehavior.STATE_DRAGGING, BottomSheetBehavior.STATE_SETTLING -> {
// Do nothing. Both cases are handled in the onSlide function.
}
}
}

override fun onSlide(bottomSheet: View, slideOffset: Float) {
setTabsTrayDialogDimAmount(bottomSheet.top)
setFabY(bottomSheet.top)
}

private fun setTabsTrayDialogDimAmount(bottomSheetTop: Int) {
// Get any displayed bottom system bar.
val bottomSystemBarHeight =
ViewCompat.getRootWindowInsets(newTabFab)
?.getInsets(WindowInsetsCompat.Type.systemBars())?.bottom ?: 0

// Calculate and convert delta to dim amount.
val appVisibleBottom = newTabFab.rootView.bottom - bottomSystemBarHeight
val trayTopAppBottomDelta = appVisibleBottom - bottomSheetTop
val convertedDimValue = trayTopAppBottomDelta / DIM_CONVERSION

if (convertedDimValue < DEFAULT_MAX_DIM) {
tabsTrayDialog.window?.setDimAmount(convertedDimValue)
}
}

private fun setFabY(bottomSheetTop: Int) {
if (behavior.state == BottomSheetBehavior.STATE_DRAGGING) {
draggedLowestSheetTop = getDraggedLowestSheetTop(bottomSheetTop)

val dynamicSheetButtonDelta = newTabFab.top - draggedLowestSheetTop!!
newTabFab.y = getUpdatedFabY(bottomSheetTop, dynamicSheetButtonDelta)
}

if (behavior.state == BottomSheetBehavior.STATE_SETTLING) {
val dynamicSheetButtonDelta = newTabFab.top - getDraggedLowestSheetTop(bottomSheetTop)
newTabFab.y = getUpdatedFabY(bottomSheetTop, dynamicSheetButtonDelta)
}
}

override fun onSlide(bottomSheet: View, slideOffset: Float) = Unit
private fun getDraggedLowestSheetTop(currentBottomSheetTop: Int) =
if (draggedLowestSheetTop == null || currentBottomSheetTop < draggedLowestSheetTop!!) {
currentBottomSheetTop
} else {
draggedLowestSheetTop!!
}

private fun getUpdatedFabY(bottomSheetTop: Int, dynamicSheetButtonDelta: Int) =
(bottomSheetTop + dynamicSheetButtonDelta).toFloat()
}
Expand Up @@ -4,6 +4,7 @@

package org.mozilla.fenix.tabstray

import android.app.Dialog
import android.content.Context
import android.content.res.Configuration
import android.os.Build
Expand Down Expand Up @@ -80,6 +81,7 @@ enum class TabsTrayAccessPoint {
class TabsTrayFragment : AppCompatDialogFragment() {

@VisibleForTesting internal lateinit var tabsTrayStore: TabsTrayStore
private lateinit var tabsTrayDialog: TabsTrayDialog
private lateinit var tabsTrayInteractor: TabsTrayInteractor
private lateinit var tabsTrayController: DefaultTabsTrayController
private lateinit var navigationInteractor: DefaultNavigationInteractor
Expand Down Expand Up @@ -126,15 +128,7 @@ class TabsTrayFragment : AppCompatDialogFragment() {
setStyle(STYLE_NO_TITLE, R.style.TabTrayDialogStyle)
}

override fun onCreateDialog(savedInstanceState: Bundle?) =
TabsTrayDialog(requireContext(), theme) { tabsTrayInteractor }

@Suppress("LongMethod")
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val args by navArgs<TabsTrayFragmentArgs>()
args.accessPoint.takeIf { it != TabsTrayAccessPoint.None }?.let {
TabsTray.accessPoint[it.name.lowercase()].add()
Expand Down Expand Up @@ -196,6 +190,16 @@ class TabsTrayFragment : AppCompatDialogFragment() {
controller = tabsTrayController,
)

tabsTrayDialog = TabsTrayDialog(requireContext(), theme) { tabsTrayInteractor }
return tabsTrayDialog
}

@Suppress("LongMethod")
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
_tabsTrayDialogBinding = FragmentTabTrayDialogBinding.inflate(
inflater,
container,
Expand Down Expand Up @@ -275,7 +279,7 @@ class TabsTrayFragment : AppCompatDialogFragment() {
true,
)
_fabButtonBinding = ComponentTabstrayFabBinding.inflate(
LayoutInflater.from(tabsTrayDialogBinding.root.context),
inflater,
tabsTrayDialogBinding.root,
true,
)
Expand Down Expand Up @@ -310,8 +314,27 @@ class TabsTrayFragment : AppCompatDialogFragment() {
} else {
tabsTrayBinding.tabWrapper
}

val newTabFab = if (requireContext().settings().enableTabsTrayToCompose) {
fabButtonComposeBinding.root
} else {
fabButtonBinding.newTabButton
}

val behavior = BottomSheetBehavior.from(rootView).apply {
addBottomSheetCallback(
TraySheetBehaviorCallback(
this,
navigationInteractor,
tabsTrayDialog,
newTabFab,
),
)
skipCollapsed = true
}

trayBehaviorManager = TabSheetBehaviorManager(
behavior = BottomSheetBehavior.from(rootView),
behavior = behavior,
orientation = resources.configuration.orientation,
maxNumberOfTabs = max(
requireContext().components.core.store.state.normalTabs.size,
Expand All @@ -322,7 +345,6 @@ class TabsTrayFragment : AppCompatDialogFragment() {
} else {
EXPAND_AT_LIST_SIZE
},
navigationInteractor = navigationInteractor,
displayMetrics = requireContext().resources.displayMetrics,
)

Expand Down

0 comments on commit 444597e

Please sign in to comment.