Bug 1821961 - Updated the collapse animation of the tabs tray FAB & scrim

fenix/114.1.0
t-p-white 1 year ago committed by mergify[bot]
parent 8e11d6cb4e
commit 7bbaaf87b8

@ -8,14 +8,25 @@ 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.
*
@ -23,7 +34,6 @@ import mozilla.components.support.ktx.android.util.dpToPx
* @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(
@ -31,18 +41,12 @@ internal class TabSheetBehaviorManager(
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)
@ -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()
}

@ -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
@ -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
@ -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()
@ -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,
@ -275,7 +279,7 @@ class TabsTrayFragment : AppCompatDialogFragment() {
true,
)
_fabButtonBinding = ComponentTabstrayFabBinding.inflate(
LayoutInflater.from(tabsTrayDialogBinding.root.context),
inflater,
tabsTrayDialogBinding.root,
true,
)
@ -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,
@ -322,7 +345,6 @@ class TabsTrayFragment : AppCompatDialogFragment() {
} else {
EXPAND_AT_LIST_SIZE
},
navigationInteractor = navigationInteractor,
displayMetrics = requireContext().resources.displayMetrics,
)

@ -6,6 +6,7 @@ package org.mozilla.fenix.tabstray
import android.content.res.Configuration
import android.util.DisplayMetrics
import android.view.View
import androidx.constraintlayout.widget.ConstraintLayout
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_COLLAPSED
@ -14,18 +15,18 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDE
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HALF_EXPANDED
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HIDDEN
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_SETTLING
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
import io.mockk.Called
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.slot
import io.mockk.spyk
import io.mockk.unmockkStatic
import io.mockk.verify
import mozilla.components.support.ktx.android.util.dpToPx
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertSame
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Test
@ -34,7 +35,7 @@ class TabSheetBehaviorManagerTest {
@Test
fun `WHEN state is hidden THEN invoke interactor`() {
val interactor = mockk<NavigationInteractor>(relaxed = true)
val callback = TraySheetBehaviorCallback(mockk(), interactor)
val callback = TraySheetBehaviorCallback(mockk(), interactor, mockk(), mockk())
callback.onStateChanged(mockk(), STATE_HIDDEN)
@ -44,7 +45,7 @@ class TabSheetBehaviorManagerTest {
@Test
fun `WHEN state is half-expanded THEN close the tray`() {
val behavior = mockk<BottomSheetBehavior<ConstraintLayout>>(relaxed = true)
val callback = TraySheetBehaviorCallback(behavior, mockk())
val callback = TraySheetBehaviorCallback(behavior, mockk(), mockk(), mockk())
callback.onStateChanged(mockk(), STATE_HALF_EXPANDED)
@ -55,7 +56,7 @@ class TabSheetBehaviorManagerTest {
fun `WHEN other states are invoked THEN do nothing`() {
val behavior = mockk<BottomSheetBehavior<ConstraintLayout>>(relaxed = true)
val interactor = mockk<NavigationInteractor>(relaxed = true)
val callback = TraySheetBehaviorCallback(behavior, interactor)
val callback = TraySheetBehaviorCallback(behavior, interactor, mockk(), mockk())
callback.onStateChanged(mockk(), STATE_COLLAPSED)
callback.onStateChanged(mockk(), STATE_DRAGGING)
@ -67,27 +68,359 @@ class TabSheetBehaviorManagerTest {
}
@Test
fun `GIVEN a behavior WHEN TabSheetBehaviorManager is initialized THEN it sets a TraySheetBehaviorCallback on that behavior`() {
val behavior: BottomSheetBehavior<ConstraintLayout> = mockk(relaxed = true)
val navigationInteractor: NavigationInteractor = mockk()
val callbackCaptor = slot<TraySheetBehaviorCallback>()
fun `GIVEN converted dim value is more than max dim WHEN onSlide is called THEN it does not set the dialog dim amount`() {
val behavior = mockk<BottomSheetBehavior<ConstraintLayout>>(relaxed = true)
val tabsTrayDialog = mockk<TabsTrayDialog>(relaxed = true)
val rootView = mockk<View>(relaxed = true)
every { rootView.bottom } returns 1000
val fab = mockk<ExtendedFloatingActionButton>(relaxed = true)
every { fab.rootView } returns rootView
val callback = TraySheetBehaviorCallback(behavior, mockk(), tabsTrayDialog, fab)
val bottomSheet = mockk<View>(relaxed = true)
every { bottomSheet.top } returns 300 // (1000 - 300) / 1000 = 0.7
callback.onSlide(bottomSheet, 1f)
verify(exactly = 0) { tabsTrayDialog.window?.setDimAmount(any()) }
}
@Test
fun `GIVEN converted dim value is at max dim WHEN onSlide is called THEN it does not set the dialog dim amount`() {
val behavior = mockk<BottomSheetBehavior<ConstraintLayout>>(relaxed = true)
val tabsTrayDialog = mockk<TabsTrayDialog>(relaxed = true)
val rootView = mockk<View>(relaxed = true)
every { rootView.bottom } returns 1000
val fab = mockk<ExtendedFloatingActionButton>(relaxed = true)
every { fab.rootView } returns rootView
val callback = TraySheetBehaviorCallback(behavior, mockk(), tabsTrayDialog, fab)
val bottomSheet = mockk<View>(relaxed = true)
every { bottomSheet.top } returns 400 // (1000 - 400) / 1000 = 0.6
callback.onSlide(bottomSheet, 1f)
verify(exactly = 0) { tabsTrayDialog.window?.setDimAmount(any()) }
}
@Test
fun `GIVEN converted dim value is less than max dim WHEN onSlide is called THEN it sets the dialog dim amount`() {
val behavior = mockk<BottomSheetBehavior<ConstraintLayout>>(relaxed = true)
val tabsTrayDialog = mockk<TabsTrayDialog>(relaxed = true)
val rootView = mockk<View>(relaxed = true)
every { rootView.bottom } returns 1000
val fab = mockk<ExtendedFloatingActionButton>(relaxed = true)
every { fab.rootView } returns rootView
val callback = TraySheetBehaviorCallback(behavior, mockk(), tabsTrayDialog, fab)
val bottomSheet = mockk<View>(relaxed = true)
every { bottomSheet.top } returns 500 // (1000 - 500) / 1000 = 0.5
callback.onSlide(bottomSheet, 1f)
verify(exactly = 1) { tabsTrayDialog.window?.setDimAmount(any()) }
}
@Test
fun `GIVEN behaviour state is 'dragging' & draggedLowestSheetTop is null WHEN onSlide is called THEN draggedLowestSheetTop is set to currentBottomSheetTop`() {
val behavior = mockk<BottomSheetBehavior<ConstraintLayout>>(relaxed = true)
every { behavior.state } returns STATE_DRAGGING
val tabsTrayDialog = mockk<TabsTrayDialog>(relaxed = true)
val rootView = mockk<View>(relaxed = true)
every { rootView.bottom } returns 1000
val fab = mockk<ExtendedFloatingActionButton>(relaxed = true)
every { fab.rootView } returns rootView
every { fab.top } returns 900
val callback = TraySheetBehaviorCallback(behavior, mockk(), tabsTrayDialog, fab)
val bottomSheetTop = 10
// draggedLowestSheetTop is null
val bottomSheet = mockk<View>(relaxed = true)
every { bottomSheet.top } returns bottomSheetTop
callback.onSlide(bottomSheet, 1f)
verify { fab.y = 900f }
assertEquals(bottomSheetTop, callback.draggedLowestSheetTop)
}
@Test
fun `GIVEN behaviour state is 'dragging' & currentBottomSheetTop is same as draggedLowestSheetTop WHEN onSlide is called THEN draggedLowestSheetTop is same value`() {
val behavior = mockk<BottomSheetBehavior<ConstraintLayout>>(relaxed = true)
every { behavior.state } returns STATE_DRAGGING
val tabsTrayDialog = mockk<TabsTrayDialog>(relaxed = true)
val rootView = mockk<View>(relaxed = true)
every { rootView.bottom } returns 1000
val fab = mockk<ExtendedFloatingActionButton>(relaxed = true)
every { fab.rootView } returns rootView
every { fab.top } returns 900
val callback = TraySheetBehaviorCallback(behavior, mockk(), tabsTrayDialog, fab)
val bottomSheetTop = 10
// draggedLowestSheetTop is null
val bottomSheet1 = mockk<View>(relaxed = true)
every { bottomSheet1.top } returns bottomSheetTop
callback.onSlide(bottomSheet1, 1f)
verify { fab.y = 900f }
// currentBottomSheetTop is same as draggedLowestSheetTop
val bottomSheet2 = mockk<View>(relaxed = true)
every { bottomSheet2.top } returns bottomSheetTop
callback.onSlide(bottomSheet2, 1f)
verify { fab.y = 900f }
assertEquals(bottomSheetTop, callback.draggedLowestSheetTop)
}
@Test
fun `GIVEN behaviour state is 'dragging' & currentBottomSheetTop is more than draggedLowestSheetTop WHEN onSlide is called THEN draggedLowestSheetTop is same value`() {
val behavior = mockk<BottomSheetBehavior<ConstraintLayout>>(relaxed = true)
every { behavior.state } returns STATE_DRAGGING
val tabsTrayDialog = mockk<TabsTrayDialog>(relaxed = true)
val rootView = mockk<View>(relaxed = true)
every { rootView.bottom } returns 1000
val fab = mockk<ExtendedFloatingActionButton>(relaxed = true)
every { fab.rootView } returns rootView
every { fab.top } returns 900
val callback = TraySheetBehaviorCallback(behavior, mockk(), tabsTrayDialog, fab)
val originalBottomSheetTop = 10
// draggedLowestSheetTop is null
val bottomSheet1 = mockk<View>(relaxed = true)
every { bottomSheet1.top } returns originalBottomSheetTop
callback.onSlide(bottomSheet1, 1f)
verify { fab.y = 900f }
// currentBottomSheetTop is same as draggedLowestSheetTop
val newBottomSheetTop = originalBottomSheetTop + 1
val bottomSheet2 = mockk<View>(relaxed = true)
every { bottomSheet2.top } returns newBottomSheetTop
callback.onSlide(bottomSheet2, 1f)
verify { fab.y = 901f }
assertEquals(originalBottomSheetTop, callback.draggedLowestSheetTop)
}
@Test
fun `GIVEN behaviour state is 'dragging' & currentBottomSheetTop less than draggedLowestSheetTop WHEN onSlide is called THEN draggedLowestSheetTop is set to currentBottomSheetTop`() {
val behavior = mockk<BottomSheetBehavior<ConstraintLayout>>(relaxed = true)
every { behavior.state } returns STATE_DRAGGING
val tabsTrayDialog = mockk<TabsTrayDialog>(relaxed = true)
val rootView = mockk<View>(relaxed = true)
every { rootView.bottom } returns 1000
val fab = mockk<ExtendedFloatingActionButton>(relaxed = true)
every { fab.rootView } returns rootView
every { fab.top } returns 900
val callback = TraySheetBehaviorCallback(behavior, mockk(), tabsTrayDialog, fab)
// draggedLowestSheetTop is null
val bottomSheet1 = mockk<View>(relaxed = true)
every { bottomSheet1.top } returns 10
callback.onSlide(bottomSheet1, 1f)
verify { fab.y = 900f }
// currentBottomSheetTop is less than draggedLowestSheetTop
val newBottomSheetTop = 9
val bottomSheet2 = mockk<View>(relaxed = true)
every { bottomSheet2.top } returns newBottomSheetTop
callback.onSlide(bottomSheet2, 1f)
verify { fab.y = 900f }
assertEquals(newBottomSheetTop, callback.draggedLowestSheetTop)
}
@Test
fun `GIVEN behaviour state is 'settling' & draggedLowestSheetTop is null WHEN onSlide is called THEN draggedLowestSheetTop is set to fab y is set`() {
val behavior = mockk<BottomSheetBehavior<ConstraintLayout>>(relaxed = true)
every { behavior.state } returns STATE_SETTLING
val tabsTrayDialog = mockk<TabsTrayDialog>(relaxed = true)
val rootView = mockk<View>(relaxed = true)
every { rootView.bottom } returns 1000
val fab = mockk<ExtendedFloatingActionButton>(relaxed = true)
every { fab.rootView } returns rootView
every { fab.top } returns 900
val callback = TraySheetBehaviorCallback(behavior, mockk(), tabsTrayDialog, fab)
// draggedLowestSheetTop is null
val bottomSheet = mockk<View>(relaxed = true)
every { bottomSheet.top } returns 10
callback.onSlide(bottomSheet, 1f)
verify { fab.y = 900f }
assertNull(callback.draggedLowestSheetTop)
}
@Test
fun `GIVEN behaviour state is 'settling' & currentBottomSheetTop is same as draggedLowestSheetTop WHEN onSlide is called THEN fab y is set`() {
val behavior = mockk<BottomSheetBehavior<ConstraintLayout>>(relaxed = true)
every { behavior.state } returns STATE_SETTLING
val tabsTrayDialog = mockk<TabsTrayDialog>(relaxed = true)
val rootView = mockk<View>(relaxed = true)
every { rootView.bottom } returns 1000
val fab = mockk<ExtendedFloatingActionButton>(relaxed = true)
every { fab.rootView } returns rootView
every { fab.top } returns 900
val callback = TraySheetBehaviorCallback(behavior, mockk(), tabsTrayDialog, fab)
val bottomSheetTop = 10
// draggedLowestSheetTop is null
val bottomSheet1 = mockk<View>(relaxed = true)
every { bottomSheet1.top } returns bottomSheetTop
callback.onSlide(bottomSheet1, 1f)
verify { fab.y = 900f }
// currentBottomSheetTop is same as draggedLowestSheetTop
val bottomSheet2 = mockk<View>(relaxed = true)
every { bottomSheet2.top } returns bottomSheetTop
callback.onSlide(bottomSheet2, 1f)
verify { fab.y = 900f }
assertNull(callback.draggedLowestSheetTop)
}
@Test
fun `GIVEN behaviour state is 'settling' & currentBottomSheetTop is more than draggedLowestSheetTop WHEN onSlide is called THEN fab y is set`() {
val behavior = mockk<BottomSheetBehavior<ConstraintLayout>>(relaxed = true)
every { behavior.state } returns STATE_SETTLING
val tabsTrayDialog = mockk<TabsTrayDialog>(relaxed = true)
val rootView = mockk<View>(relaxed = true)
every { rootView.bottom } returns 1000
val fab = mockk<ExtendedFloatingActionButton>(relaxed = true)
every { fab.rootView } returns rootView
every { fab.top } returns 900
val callback = TraySheetBehaviorCallback(behavior, mockk(), tabsTrayDialog, fab)
// draggedLowestSheetTop is null
val bottomSheet1 = mockk<View>(relaxed = true)
every { bottomSheet1.top } returns 10
callback.onSlide(bottomSheet1, 1f)
verify { fab.y = 900f }
// currentBottomSheetTop is same as draggedLowestSheetTop
val bottomSheet2 = mockk<View>(relaxed = true)
every { bottomSheet2.top } returns 11
callback.onSlide(bottomSheet2, 1f)
verify { fab.y = 900f }
assertNull(callback.draggedLowestSheetTop)
}
@Test
fun `GIVEN behaviour state is 'settling' & currentBottomSheetTop less than draggedLowestSheetTop WHEN onSlide is called THEN fab y is set`() {
val behavior = mockk<BottomSheetBehavior<ConstraintLayout>>(relaxed = true)
every { behavior.state } returns STATE_SETTLING
val tabsTrayDialog = mockk<TabsTrayDialog>(relaxed = true)
val rootView = mockk<View>(relaxed = true)
every { rootView.bottom } returns 1000
val fab = mockk<ExtendedFloatingActionButton>(relaxed = true)
every { fab.rootView } returns rootView
every { fab.top } returns 900
val callback = TraySheetBehaviorCallback(behavior, mockk(), tabsTrayDialog, fab)
// draggedLowestSheetTop is null
val bottomSheet1 = mockk<View>(relaxed = true)
every { bottomSheet1.top } returns 10
callback.onSlide(bottomSheet1, 1f)
verify { fab.y = 900f }
// currentBottomSheetTop is less than draggedLowestSheetTop
val bottomSheet2 = mockk<View>(relaxed = true)
every { bottomSheet2.top } returns 9
callback.onSlide(bottomSheet2, 1f)
verify { fab.y = 900f }
assertNull(callback.draggedLowestSheetTop)
}
@Test
fun `GIVEN behaviour state is 'state expanded' WHEN onStateChanged is called THEN draggedLowestSheetTop is set to null`() {
val bottomSheet = mockk<View>(relaxed = true)
val callback = TraySheetBehaviorCallback(mockk(), mockk(), mockk(), mockk())
callback.draggedLowestSheetTop = 1
assertEquals(1, callback.draggedLowestSheetTop)
callback.onStateChanged(bottomSheet, STATE_EXPANDED)
assertNull(callback.draggedLowestSheetTop)
}
@Test
fun `GIVEN behaviour state is 'state collapsed' WHEN onStateChanged is called THEN draggedLowestSheetTop is set to null`() {
val bottomSheet = mockk<View>(relaxed = true)
val callback = TraySheetBehaviorCallback(mockk(), mockk(), mockk(), mockk())
callback.draggedLowestSheetTop = 1
assertEquals(1, callback.draggedLowestSheetTop)
TabSheetBehaviorManager(behavior, Configuration.ORIENTATION_UNDEFINED, 2, 2, navigationInteractor, mockk())
callback.onStateChanged(bottomSheet, STATE_COLLAPSED)
verify { behavior.addBottomSheetCallback(capture(callbackCaptor)) }
assertSame(behavior, callbackCaptor.captured.behavior)
assertSame(navigationInteractor, callbackCaptor.captured.trayInteractor)
assertNull(callback.draggedLowestSheetTop)
}
@Test
fun `WHEN TabSheetBehaviorManager is initialized THEN it caches the orientation parameter value`() {
val manager0 = TabSheetBehaviorManager(mockk(relaxed = true), Configuration.ORIENTATION_UNDEFINED, 5, 4, mockk(), mockk())
val manager0 = TabSheetBehaviorManager(
mockk(relaxed = true),
Configuration.ORIENTATION_UNDEFINED,
5,
4,
mockk(),
)
assertEquals(Configuration.ORIENTATION_UNDEFINED, manager0.currentOrientation)
val manager1 = TabSheetBehaviorManager(mockk(relaxed = true), Configuration.ORIENTATION_PORTRAIT, 5, 4, mockk(relaxed = true), mockk())
val manager1 = TabSheetBehaviorManager(
mockk(relaxed = true),
Configuration.ORIENTATION_PORTRAIT,
5,
4,
mockk(),
)
assertEquals(Configuration.ORIENTATION_PORTRAIT, manager1.currentOrientation)
val manager2 = TabSheetBehaviorManager(mockk(relaxed = true), Configuration.ORIENTATION_LANDSCAPE, 5, 4, mockk(), mockk())
val manager2 = TabSheetBehaviorManager(
mockk(relaxed = true),
Configuration.ORIENTATION_LANDSCAPE,
5,
4,
mockk(),
)
assertEquals(Configuration.ORIENTATION_LANDSCAPE, manager2.currentOrientation)
}
@ -95,7 +428,13 @@ class TabSheetBehaviorManagerTest {
fun `GIVEN more tabs opened than the expanding limit and portrait orientation WHEN TabSheetBehaviorManager is initialized THEN the behavior is set as expanded`() {
val behavior = BottomSheetBehavior<ConstraintLayout>()
TabSheetBehaviorManager(behavior, Configuration.ORIENTATION_PORTRAIT, 5, 4, mockk(), mockk())
TabSheetBehaviorManager(
behavior,
Configuration.ORIENTATION_PORTRAIT,
5,
4,
mockk(),
)
assertEquals(STATE_EXPANDED, behavior.state)
}
@ -104,7 +443,13 @@ class TabSheetBehaviorManagerTest {
fun `GIVEN the number of tabs opened is exactly the expanding limit and portrait orientation WHEN TabSheetBehaviorManager is initialized THEN the behavior is set as expanded`() {
val behavior = BottomSheetBehavior<ConstraintLayout>()
TabSheetBehaviorManager(behavior, Configuration.ORIENTATION_PORTRAIT, 5, 5, mockk(), mockk())
TabSheetBehaviorManager(
behavior,
Configuration.ORIENTATION_PORTRAIT,
5,
5,
mockk(),
)
assertEquals(STATE_EXPANDED, behavior.state)
}
@ -113,7 +458,13 @@ class TabSheetBehaviorManagerTest {
fun `GIVEN fewer tabs opened than the expanding limit and portrait orientation WHEN TabSheetBehaviorManager is initialized THEN the behavior is set as collapsed`() {
val behavior = BottomSheetBehavior<ConstraintLayout>()
TabSheetBehaviorManager(behavior, Configuration.ORIENTATION_PORTRAIT, 4, 5, mockk(), mockk())
TabSheetBehaviorManager(
behavior,
Configuration.ORIENTATION_PORTRAIT,
4,
5,
mockk(),
)
assertEquals(STATE_COLLAPSED, behavior.state)
}
@ -122,7 +473,13 @@ class TabSheetBehaviorManagerTest {
fun `GIVEN more tabs opened than the expanding limit and undefined orientation WHEN TabSheetBehaviorManager is initialized THEN the behavior is set as expanded`() {
val behavior = BottomSheetBehavior<ConstraintLayout>()
TabSheetBehaviorManager(behavior, Configuration.ORIENTATION_UNDEFINED, 5, 4, mockk(), mockk())
TabSheetBehaviorManager(
behavior,
Configuration.ORIENTATION_UNDEFINED,
5,
4,
mockk(),
)
assertEquals(STATE_EXPANDED, behavior.state)
}
@ -131,7 +488,13 @@ class TabSheetBehaviorManagerTest {
fun `GIVEN the number of tabs opened is exactly the expanding limit and undefined orientation WHEN TabSheetBehaviorManager is initialized THEN the behavior is set as expanded`() {
val behavior = BottomSheetBehavior<ConstraintLayout>()
TabSheetBehaviorManager(behavior, Configuration.ORIENTATION_UNDEFINED, 5, 5, mockk(), mockk())
TabSheetBehaviorManager(
behavior,
Configuration.ORIENTATION_UNDEFINED,
5,
5,
mockk(),
)
assertEquals(STATE_EXPANDED, behavior.state)
}
@ -140,7 +503,13 @@ class TabSheetBehaviorManagerTest {
fun `GIVEN fewer tabs opened than the expanding limit and undefined orientation WHEN TabSheetBehaviorManager is initialized THEN the behavior is set as collapsed`() {
val behavior = BottomSheetBehavior<ConstraintLayout>()
TabSheetBehaviorManager(behavior, Configuration.ORIENTATION_UNDEFINED, 4, 5, mockk(), mockk())
TabSheetBehaviorManager(
behavior,
Configuration.ORIENTATION_UNDEFINED,
4,
5,
mockk(),
)
assertEquals(STATE_COLLAPSED, behavior.state)
}
@ -149,7 +518,13 @@ class TabSheetBehaviorManagerTest {
fun `GIVEN more tabs opened than the expanding limit and landscape orientation WHEN TabSheetBehaviorManager is initialized THEN the behavior is set as expanded`() {
val behavior = BottomSheetBehavior<ConstraintLayout>()
TabSheetBehaviorManager(behavior, Configuration.ORIENTATION_LANDSCAPE, 5, 4, mockk(), mockk())
TabSheetBehaviorManager(
behavior,
Configuration.ORIENTATION_LANDSCAPE,
5,
4,
mockk(),
)
assertEquals(STATE_EXPANDED, behavior.state)
}
@ -158,7 +533,13 @@ class TabSheetBehaviorManagerTest {
fun `GIVEN the number of tabs opened is exactly the expanding limit and landscape orientation WHEN TabSheetBehaviorManager is initialized THEN the behavior is set as expanded`() {
val behavior = BottomSheetBehavior<ConstraintLayout>()
TabSheetBehaviorManager(behavior, Configuration.ORIENTATION_LANDSCAPE, 5, 5, mockk(), mockk())
TabSheetBehaviorManager(
behavior,
Configuration.ORIENTATION_LANDSCAPE,
5,
5,
mockk(),
)
assertEquals(STATE_EXPANDED, behavior.state)
}
@ -167,7 +548,13 @@ class TabSheetBehaviorManagerTest {
fun `GIVEN fewer tabs opened than the expanding limit and landscape orientation WHEN TabSheetBehaviorManager is initialized THEN the behavior is set as expanded`() {
val behavior = BottomSheetBehavior<ConstraintLayout>()
TabSheetBehaviorManager(behavior, Configuration.ORIENTATION_LANDSCAPE, 4, 5, mockk(), mockk())
TabSheetBehaviorManager(
behavior,
Configuration.ORIENTATION_LANDSCAPE,
4,
5,
mockk(),
)
assertEquals(STATE_EXPANDED, behavior.state)
}
@ -175,7 +562,13 @@ class TabSheetBehaviorManagerTest {
@Test
fun `GIVEN more tabs opened than the expanding limit and not landscape orientation WHEN updateBehaviorState is called THEN the behavior is set as expanded`() {
val behavior = BottomSheetBehavior<ConstraintLayout>()
val manager = TabSheetBehaviorManager(behavior, Configuration.ORIENTATION_UNDEFINED, 5, 4, mockk(), mockk())
val manager = TabSheetBehaviorManager(
behavior,
Configuration.ORIENTATION_UNDEFINED,
5,
4,
mockk(),
)
manager.updateBehaviorState(false)
@ -185,7 +578,13 @@ class TabSheetBehaviorManagerTest {
@Test
fun `GIVEN the number of tabs opened is exactly the expanding limit and portrait orientation WHEN updateBehaviorState is called THEN the behavior is set as expanded`() {
val behavior = BottomSheetBehavior<ConstraintLayout>()
val manager = TabSheetBehaviorManager(behavior, Configuration.ORIENTATION_UNDEFINED, 5, 5, mockk(), mockk())
val manager = TabSheetBehaviorManager(
behavior,
Configuration.ORIENTATION_UNDEFINED,
5,
5,
mockk(),
)
manager.updateBehaviorState(false)
@ -195,7 +594,13 @@ class TabSheetBehaviorManagerTest {
@Test
fun `GIVEN fewer tabs opened than the expanding limit and portrait orientation WHEN updateBehaviorState is called THEN the behavior is set as collapsed`() {
val behavior = BottomSheetBehavior<ConstraintLayout>()
val manager = TabSheetBehaviorManager(behavior, Configuration.ORIENTATION_UNDEFINED, 4, 5, mockk(), mockk())
val manager = TabSheetBehaviorManager(
behavior,
Configuration.ORIENTATION_UNDEFINED,
4,
5,
mockk(),
)
manager.updateBehaviorState(false)
@ -205,7 +610,13 @@ class TabSheetBehaviorManagerTest {
@Test
fun `GIVEN more tabs opened than the expanding limit and landscape orientation WHEN updateBehaviorState is called THEN the behavior is set as expanded`() {
val behavior = BottomSheetBehavior<ConstraintLayout>()
val manager = TabSheetBehaviorManager(behavior, Configuration.ORIENTATION_UNDEFINED, 5, 4, mockk(), mockk())
val manager = TabSheetBehaviorManager(
behavior,
Configuration.ORIENTATION_UNDEFINED,
5,
4,
mockk(),
)
manager.updateBehaviorState(true)
@ -215,7 +626,13 @@ class TabSheetBehaviorManagerTest {
@Test
fun `GIVEN the number of tabs opened is exactly the expanding limit and landscape orientation WHEN updateBehaviorState is called THEN the behavior is set as expanded`() {
val behavior = BottomSheetBehavior<ConstraintLayout>()
val manager = TabSheetBehaviorManager(behavior, Configuration.ORIENTATION_UNDEFINED, 5, 5, mockk(), mockk())
val manager = TabSheetBehaviorManager(
behavior,
Configuration.ORIENTATION_UNDEFINED,
5,
5,
mockk(),
)
manager.updateBehaviorState(true)
@ -225,7 +642,13 @@ class TabSheetBehaviorManagerTest {
@Test
fun `GIVEN fewer tabs opened than the expanding limit and landscape orientation WHEN updateBehaviorState is called THEN the behavior is set as expanded`() {
val behavior = BottomSheetBehavior<ConstraintLayout>()
val manager = TabSheetBehaviorManager(behavior, Configuration.ORIENTATION_UNDEFINED, 4, 5, mockk(), mockk())
val manager = TabSheetBehaviorManager(
behavior,
Configuration.ORIENTATION_UNDEFINED,
4,
5,
mockk(),
)
manager.updateBehaviorState(true)
@ -234,7 +657,15 @@ class TabSheetBehaviorManagerTest {
@Test
fun `WHEN updateDependingOnOrientation is called with the same orientation as the current one THEN nothing happens`() {
val manager = spyk(TabSheetBehaviorManager(mockk(relaxed = true), Configuration.ORIENTATION_PORTRAIT, 4, 5, mockk(), mockk()))
val manager = spyk(
TabSheetBehaviorManager(
mockk(relaxed = true),
Configuration.ORIENTATION_PORTRAIT,
4,
5,
mockk(),
),
)
manager.updateDependingOnOrientation(Configuration.ORIENTATION_PORTRAIT)
@ -245,7 +676,15 @@ class TabSheetBehaviorManagerTest {
@Test
fun `WHEN updateDependingOnOrientation is called with a new orientation THEN this is cached and updateBehaviorState is called`() {
val manager = spyk(TabSheetBehaviorManager(mockk(relaxed = true), Configuration.ORIENTATION_PORTRAIT, 4, 5, mockk(), mockk()))
val manager = spyk(
TabSheetBehaviorManager(
mockk(relaxed = true),
Configuration.ORIENTATION_PORTRAIT,
4,
5,
mockk(),
),
)
manager.updateDependingOnOrientation(Configuration.ORIENTATION_UNDEFINED)
assertEquals(Configuration.ORIENTATION_UNDEFINED, manager.currentOrientation)
@ -260,21 +699,45 @@ class TabSheetBehaviorManagerTest {
@Test
fun `WHEN isLandscape is called with Configuration#ORIENTATION_LANDSCAPE THEN it returns true`() {
val manager = spyk(TabSheetBehaviorManager(mockk(relaxed = true), Configuration.ORIENTATION_PORTRAIT, 4, 5, mockk(), mockk()))
val manager = spyk(
TabSheetBehaviorManager(
mockk(relaxed = true),
Configuration.ORIENTATION_PORTRAIT,
4,
5,
mockk(),
),
)
assertTrue(manager.isLandscape(Configuration.ORIENTATION_LANDSCAPE))
}
@Test
fun `WHEN isLandscape is called with Configuration#ORIENTATION_PORTRAIT THEN it returns false`() {
val manager = spyk(TabSheetBehaviorManager(mockk(relaxed = true), Configuration.ORIENTATION_PORTRAIT, 4, 5, mockk(), mockk()))
val manager = spyk(
TabSheetBehaviorManager(
mockk(relaxed = true),
Configuration.ORIENTATION_PORTRAIT,
4,
5,
mockk(),
),
)
assertFalse(manager.isLandscape(Configuration.ORIENTATION_PORTRAIT))
}
@Test
fun `WHEN isLandscape is called with Configuration#ORIENTATION_UNDEFINED THEN it returns false`() {
val manager = spyk(TabSheetBehaviorManager(mockk(relaxed = true), Configuration.ORIENTATION_PORTRAIT, 4, 5, mockk(), mockk()))
val manager = spyk(
TabSheetBehaviorManager(
mockk(relaxed = true),
Configuration.ORIENTATION_PORTRAIT,
4,
5,
mockk(),
),
)
assertFalse(manager.isLandscape(Configuration.ORIENTATION_UNDEFINED))
}
@ -290,7 +753,13 @@ class TabSheetBehaviorManagerTest {
mockkStatic("mozilla.components.support.ktx.android.util.DisplayMetricsKt")
every { EXPANDED_OFFSET_IN_LANDSCAPE_DP.dpToPx(displayMetrics) } returns EXPANDED_OFFSET_IN_LANDSCAPE_DP
TabSheetBehaviorManager(behavior, Configuration.ORIENTATION_LANDSCAPE, 5, 4, mockk(), displayMetrics)
TabSheetBehaviorManager(
behavior,
Configuration.ORIENTATION_LANDSCAPE,
5,
4,
displayMetrics,
)
} finally {
unmockkStatic("mozilla.components.support.ktx.android.util.DisplayMetricsKt")
}
@ -309,7 +778,13 @@ class TabSheetBehaviorManagerTest {
mockkStatic("mozilla.components.support.ktx.android.util.DisplayMetricsKt")
every { EXPANDED_OFFSET_IN_PORTRAIT_DP.dpToPx(displayMetrics) } returns EXPANDED_OFFSET_IN_PORTRAIT_DP
TabSheetBehaviorManager(behavior, Configuration.ORIENTATION_PORTRAIT, 5, 4, mockk(), displayMetrics)
TabSheetBehaviorManager(
behavior,
Configuration.ORIENTATION_PORTRAIT,
5,
4,
displayMetrics,
)
} finally {
unmockkStatic("mozilla.components.support.ktx.android.util.DisplayMetricsKt")
}
@ -328,7 +803,13 @@ class TabSheetBehaviorManagerTest {
mockkStatic("mozilla.components.support.ktx.android.util.DisplayMetricsKt")
every { EXPANDED_OFFSET_IN_PORTRAIT_DP.dpToPx(displayMetrics) } returns EXPANDED_OFFSET_IN_PORTRAIT_DP
TabSheetBehaviorManager(behavior, Configuration.ORIENTATION_UNDEFINED, 5, 4, mockk(), displayMetrics)
TabSheetBehaviorManager(
behavior,
Configuration.ORIENTATION_UNDEFINED,
5,
4,
displayMetrics,
)
} finally {
unmockkStatic("mozilla.components.support.ktx.android.util.DisplayMetricsKt")
}
@ -346,7 +827,13 @@ class TabSheetBehaviorManagerTest {
try {
mockkStatic("mozilla.components.support.ktx.android.util.DisplayMetricsKt")
every { EXPANDED_OFFSET_IN_PORTRAIT_DP.dpToPx(displayMetrics) } returns EXPANDED_OFFSET_IN_PORTRAIT_DP
val manager = TabSheetBehaviorManager(behavior, Configuration.ORIENTATION_LANDSCAPE, 5, 4, mockk(), displayMetrics)
val manager = TabSheetBehaviorManager(
behavior,
Configuration.ORIENTATION_LANDSCAPE,
5,
4,
displayMetrics,
)
manager.updateDependingOnOrientation(Configuration.ORIENTATION_PORTRAIT)
} finally {
@ -366,7 +853,13 @@ class TabSheetBehaviorManagerTest {
try {
mockkStatic("mozilla.components.support.ktx.android.util.DisplayMetricsKt")
every { EXPANDED_OFFSET_IN_PORTRAIT_DP.dpToPx(displayMetrics) } returns EXPANDED_OFFSET_IN_PORTRAIT_DP
val manager = TabSheetBehaviorManager(behavior, Configuration.ORIENTATION_LANDSCAPE, 5, 4, mockk(), displayMetrics)
val manager = TabSheetBehaviorManager(
behavior,
Configuration.ORIENTATION_LANDSCAPE,
5,
4,
displayMetrics,
)
manager.updateDependingOnOrientation(Configuration.ORIENTATION_UNDEFINED)
} finally {
@ -386,7 +879,13 @@ class TabSheetBehaviorManagerTest {
try {
mockkStatic("mozilla.components.support.ktx.android.util.DisplayMetricsKt")
every { EXPANDED_OFFSET_IN_LANDSCAPE_DP.dpToPx(displayMetrics) } returns EXPANDED_OFFSET_IN_LANDSCAPE_DP
val manager = TabSheetBehaviorManager(behavior, Configuration.ORIENTATION_UNDEFINED, 5, 4, mockk(), displayMetrics)
val manager = TabSheetBehaviorManager(
behavior,
Configuration.ORIENTATION_UNDEFINED,
5,
4,
displayMetrics,
)
manager.updateDependingOnOrientation(Configuration.ORIENTATION_LANDSCAPE)
} finally {

Loading…
Cancel
Save