From cfb24652e877b1b24aa07350f2210786bb984b32 Mon Sep 17 00:00:00 2001 From: Vitaly Zayankovsky Date: Wed, 18 Jan 2023 17:03:07 +0300 Subject: [PATCH 1/2] ignore ime insets in navigation view --- changelog/unreleased/bugfixes/6845.md | 1 + .../navigation/dropin/NavigationView.kt | 2 +- .../dropin/infopanel/InfoPanelCoordinator.kt | 37 +-- .../extensions/NavigationViewContextEx.kt | 6 +- .../mapbox_navigation_view_layout.xml | 224 +++++++++--------- .../layout/mapbox_navigation_view_layout.xml | 208 ++++++++-------- .../infopanel/InfoPanelCoordinatorTest.kt | 6 +- 7 files changed, 231 insertions(+), 253 deletions(-) create mode 100644 changelog/unreleased/bugfixes/6845.md diff --git a/changelog/unreleased/bugfixes/6845.md b/changelog/unreleased/bugfixes/6845.md new file mode 100644 index 00000000000..c0b4a136faf --- /dev/null +++ b/changelog/unreleased/bugfixes/6845.md @@ -0,0 +1 @@ +- Improved `NavigationView` camera behavior to ignore keyboard insets. diff --git a/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/NavigationView.kt b/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/NavigationView.kt index d3d443b4ab4..3437ad19e76 100644 --- a/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/NavigationView.kt +++ b/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/NavigationView.kt @@ -134,7 +134,7 @@ class NavigationView @JvmOverloads constructor( backPressedComponent(activity), scalebarPlaceholderCoordinator(binding.scalebarLayout), maneuverCoordinator(binding.guidanceLayout), - infoPanelCoordinator(binding.infoPanelLayout, binding.guidelineBottom), + infoPanelCoordinator(binding), actionButtonsCoordinator(binding.actionListLayout), speedLimitCoordinator(binding.speedLimitLayout), roadNameCoordinator(binding.roadNameLayout), diff --git a/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/infopanel/InfoPanelCoordinator.kt b/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/infopanel/InfoPanelCoordinator.kt index 5feeec66f09..9724ccb36be 100644 --- a/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/infopanel/InfoPanelCoordinator.kt +++ b/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/infopanel/InfoPanelCoordinator.kt @@ -3,11 +3,11 @@ package com.mapbox.navigation.dropin.infopanel import android.view.View import android.view.ViewGroup import android.view.ViewTreeObserver -import androidx.constraintlayout.widget.Guideline import androidx.core.graphics.Insets import androidx.core.view.ViewCompat import com.google.android.material.bottomsheet.BottomSheetBehavior import com.mapbox.navigation.core.MapboxNavigation +import com.mapbox.navigation.dropin.databinding.MapboxNavigationViewLayoutBinding import com.mapbox.navigation.dropin.navigationview.NavigationViewContext import com.mapbox.navigation.ui.app.internal.navigation.NavigationState import com.mapbox.navigation.ui.base.lifecycle.UIBinder @@ -27,11 +27,10 @@ import kotlinx.coroutines.launch */ internal class InfoPanelCoordinator( private val context: NavigationViewContext, - private val infoPanel: ViewGroup, - private val guidelineBottom: Guideline -) : UICoordinator(infoPanel) { + private val binding: MapboxNavigationViewLayoutBinding, +) : UICoordinator(binding.infoPanelLayout) { private val store = context.store - private val behavior = BottomSheetBehavior.from(infoPanel) + private val behavior = BottomSheetBehavior.from(binding.infoPanelLayout) private val updateGuideline = object : BottomSheetBehavior.BottomSheetCallback() { override fun onStateChanged(bottomSheet: View, newState: Int) { @@ -48,15 +47,15 @@ internal class InfoPanelCoordinator( @OptIn(ExperimentalCoroutinesApi::class) private val infoPanelTop = callbackFlow { val onGlobalLayoutListener = ViewTreeObserver.OnGlobalLayoutListener { - trySend(infoPanel.top) + trySend(binding.infoPanelLayout.top) } - val viewTreeObserver = infoPanel.viewTreeObserver + val viewTreeObserver = binding.infoPanelLayout.viewTreeObserver viewTreeObserver.addOnGlobalLayoutListener(onGlobalLayoutListener) awaitClose { viewTreeObserver.removeOnGlobalLayoutListener(onGlobalLayoutListener) } }.distinctUntilChanged() init { - infoPanel.addOnLayoutChangeListener(FixBottomSheetLayoutWhenHidden(infoPanel, behavior)) + binding.infoPanelLayout.addOnLayoutChangeListener(FixBottomSheetLayoutWhenHidden()) behavior.peekHeight = context.styles.infoPanelPeekHeight.value behavior.hide() } @@ -64,6 +63,7 @@ internal class InfoPanelCoordinator( override fun onAttached(mapboxNavigation: MapboxNavigation) { super.onAttached(mapboxNavigation) + context.behavior.infoPanelBehavior.updateBottomSheetState(behavior.state) behavior.addBottomSheetCallback(updateGuideline) coroutineScope.launch { bottomSheetState().collect { state -> @@ -79,7 +79,10 @@ internal class InfoPanelCoordinator( } } coroutineScope.launch { - context.systemBarsInsets.collect { updateGuidelinePosition(systemBarsInsets = it) } + context.systemBarsInsets.collect { insets -> + binding.container.setPadding(insets.left, insets.top, insets.right, insets.bottom) + updateGuidelinePosition(systemBarsInsets = insets) + } } coroutineScope.launch { context.styles.infoPanelGuidelineMaxPosPercent.collect { @@ -162,14 +165,14 @@ internal class InfoPanelCoordinator( private fun updateGuidelinePosition( systemBarsInsets: Insets = context.systemBarsInsets.value, - infoPanelTop: Int = infoPanel.top, + infoPanelTop: Int = binding.infoPanelLayout.top, maxPosPercent: Float = context.styles.infoPanelGuidelineMaxPosPercent.value ) { - val parentHeight = (infoPanel.parent as ViewGroup).height + val parentHeight = binding.coordinatorLayout.height val maxPos = (parentHeight * maxPosPercent).toInt() - systemBarsInsets.bottom if (0 < maxPos) { val pos = parentHeight - infoPanelTop - systemBarsInsets.bottom - guidelineBottom.setGuidelineEnd(pos.coerceIn(0, maxPos)) + binding.guidelineBottom.setGuidelineEnd(pos.coerceIn(0, maxPos)) } } @@ -193,10 +196,7 @@ internal class InfoPanelCoordinator( * An OnLayoutChangeListener that ensures the bottom sheet is always laid out at the bottom of * the parent view when in STATE_HIDDEN. */ - private class FixBottomSheetLayoutWhenHidden( - private val layout: ViewGroup, - private val behavior: BottomSheetBehavior - ) : View.OnLayoutChangeListener { + private inner class FixBottomSheetLayoutWhenHidden : View.OnLayoutChangeListener { override fun onLayoutChange( v: View?, @@ -210,7 +210,10 @@ internal class InfoPanelCoordinator( oldBottom: Int ) { if (behavior.state == BottomSheetBehavior.STATE_HIDDEN) { - ViewCompat.offsetTopAndBottom(layout, (layout.parent as? View)?.height ?: 0) + ViewCompat.offsetTopAndBottom( + binding.infoPanelLayout, + binding.coordinatorLayout.height, + ) } } } diff --git a/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/internal/extensions/NavigationViewContextEx.kt b/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/internal/extensions/NavigationViewContextEx.kt index b173d368ddd..d6163dee45d 100644 --- a/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/internal/extensions/NavigationViewContextEx.kt +++ b/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/internal/extensions/NavigationViewContextEx.kt @@ -5,7 +5,6 @@ package com.mapbox.navigation.dropin.internal.extensions import android.view.ViewGroup import androidx.activity.ComponentActivity import androidx.annotation.Px -import androidx.constraintlayout.widget.Guideline import com.mapbox.maps.MapView import com.mapbox.maps.plugin.locationcomponent.location import com.mapbox.navigation.core.MapboxNavigation @@ -269,9 +268,8 @@ internal fun NavigationViewContext.maneuverCoordinator(guidanceLayout: ViewGroup ManeuverCoordinator(this, guidanceLayout) internal fun NavigationViewContext.infoPanelCoordinator( - infoPanelLayout: ViewGroup, - guidelineBottom: Guideline -) = InfoPanelCoordinator(this, infoPanelLayout, guidelineBottom) + binding: MapboxNavigationViewLayoutBinding, +) = InfoPanelCoordinator(this, binding) internal fun NavigationViewContext.actionButtonsCoordinator(actionListLayout: ViewGroup) = ActionButtonsCoordinator(this, actionListLayout) diff --git a/libnavui-dropin/src/main/res/layout-land/mapbox_navigation_view_layout.xml b/libnavui-dropin/src/main/res/layout-land/mapbox_navigation_view_layout.xml index d9a9993c457..bef634b5fa0 100644 --- a/libnavui-dropin/src/main/res/layout-land/mapbox_navigation_view_layout.xml +++ b/libnavui-dropin/src/main/res/layout-land/mapbox_navigation_view_layout.xml @@ -13,131 +13,121 @@ tools:background="#00ccff" /> - - - - - - - - - - - - - - - - - - - - - - - - - + android:layout_height="match_parent"> + + + + + + + + + + + + + + + + + + + + - - - + + + + - - - - - - - - - - - - - - - - - - - - + android:layout_height="0dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHeight_max="350dp" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:background="@color/mapbox_main_maneuver_background_color" + tools:layout_height="120dp" /> + + + + + + + + + + + + + + Date: Fri, 20 Jan 2023 00:28:44 +0300 Subject: [PATCH 2/2] improve camera layout observer --- .../dropin/camera/CameraLayoutObserver.kt | 64 +++----- .../navigation/dropin/map/MapViewBinder.kt | 2 +- .../src/main/res/values-land/dimens.xml | 6 + .../src/main/res/values/dimens.xml | 4 +- .../dropin/camera/CameraLayoutObserverTest.kt | 148 ++++++------------ 5 files changed, 78 insertions(+), 146 deletions(-) create mode 100644 libnavui-dropin/src/main/res/values-land/dimens.xml diff --git a/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/camera/CameraLayoutObserver.kt b/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/camera/CameraLayoutObserver.kt index 2fd00484ab5..e49460fc8cc 100644 --- a/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/camera/CameraLayoutObserver.kt +++ b/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/camera/CameraLayoutObserver.kt @@ -2,17 +2,17 @@ package com.mapbox.navigation.dropin.camera import android.content.res.Configuration import android.view.View +import com.google.android.material.bottomsheet.BottomSheetBehavior import com.mapbox.maps.EdgeInsets import com.mapbox.navigation.core.MapboxNavigation import com.mapbox.navigation.dropin.R import com.mapbox.navigation.dropin.databinding.MapboxNavigationViewLayoutBinding -import com.mapbox.navigation.ui.app.internal.Store +import com.mapbox.navigation.dropin.navigationview.NavigationViewContext import com.mapbox.navigation.ui.app.internal.camera.CameraAction -import com.mapbox.navigation.ui.app.internal.navigation.NavigationState import com.mapbox.navigation.ui.base.lifecycle.UIComponent internal class CameraLayoutObserver( - private val store: Store, + private val context: NavigationViewContext, private val mapView: View, private val binding: MapboxNavigationViewLayoutBinding, ) : UIComponent() { @@ -21,22 +21,15 @@ internal class CameraLayoutObserver( .getDimensionPixelSize(R.dimen.mapbox_camera_overview_padding_v).toDouble() private val hPadding = binding.root.resources .getDimensionPixelSize(R.dimen.mapbox_camera_overview_padding_h).toDouble() - private val vPaddingLandscape = binding.root.resources - .getDimensionPixelSize(R.dimen.mapbox_camera_overview_padding_landscape_v).toDouble() - private val hPaddingLandscape = binding.root.resources - .getDimensionPixelSize(R.dimen.mapbox_camera_overview_padding_landscape_h).toDouble() private val layoutListener = View.OnLayoutChangeListener { _, _, _, _, _, _, _, _, _ -> - val edgeInsets = when (deviceOrientation()) { - Configuration.ORIENTATION_LANDSCAPE -> getLandscapePadding() - else -> getPortraitPadding() - } - store.dispatch(CameraAction.UpdatePadding(edgeInsets)) + updateCameraPadding() } override fun onAttached(mapboxNavigation: MapboxNavigation) { super.onAttached(mapboxNavigation) binding.coordinatorLayout.addOnLayoutChangeListener(layoutListener) + context.behavior.infoPanelBehavior.bottomSheetState.observe { updateCameraPadding() } } override fun onDetached(mapboxNavigation: MapboxNavigation) { @@ -44,40 +37,27 @@ internal class CameraLayoutObserver( binding.coordinatorLayout.removeOnLayoutChangeListener(layoutListener) } - private fun getPortraitPadding(): EdgeInsets { - val top = binding.guidanceLayout.height.toDouble() - val bottom = mapView.height.toDouble() - binding.roadNameLayout.top.toDouble() - return when (store.state.value.navigation) { - is NavigationState.DestinationPreview, - is NavigationState.FreeDrive, - is NavigationState.RoutePreview -> { - EdgeInsets(vPadding, hPadding, bottom, hPadding) - } - is NavigationState.ActiveNavigation, - is NavigationState.Arrival -> { - EdgeInsets(vPadding + top, hPadding, bottom, hPadding) - } + private fun updateCameraPadding() { + val edgeInsets = when (deviceOrientation()) { + Configuration.ORIENTATION_LANDSCAPE -> getLandscapePadding() + else -> getPortraitPadding() } + context.store.dispatch(CameraAction.UpdatePadding(edgeInsets)) + } + + private fun getPortraitPadding(): EdgeInsets { + val top = binding.guidanceLayout.bottom + val bottom = mapView.height - binding.roadNameLayout.top + return EdgeInsets(vPadding + top, hPadding, vPadding + bottom, hPadding) } private fun getLandscapePadding(): EdgeInsets { - val bottom = mapView.height.toDouble() - binding.roadNameLayout.top.toDouble() - return when (store.state.value.navigation) { - is NavigationState.FreeDrive -> { - EdgeInsets(vPaddingLandscape, hPaddingLandscape, bottom, hPaddingLandscape) - } - is NavigationState.DestinationPreview, - is NavigationState.RoutePreview, - is NavigationState.ActiveNavigation, - is NavigationState.Arrival -> { - EdgeInsets( - vPaddingLandscape, - hPaddingLandscape + binding.infoPanelLayout.right.toDouble(), - bottom, - hPaddingLandscape - ) - } - } + val bottomSheetState = context.behavior.infoPanelBehavior.bottomSheetState.value + val isBottomSheetVisible = + bottomSheetState != null && bottomSheetState != BottomSheetBehavior.STATE_HIDDEN + val bottomSheetWidth = if (isBottomSheetVisible) binding.infoPanelLayout.right else 0 + val bottom = mapView.height - binding.roadNameLayout.top + return EdgeInsets(vPadding, hPadding + bottomSheetWidth, vPadding + bottom, hPadding) } private fun deviceOrientation() = binding.root.resources.configuration.orientation diff --git a/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/map/MapViewBinder.kt b/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/map/MapViewBinder.kt index 60d574ec105..0b738544d72 100644 --- a/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/map/MapViewBinder.kt +++ b/libnavui-dropin/src/main/java/com/mapbox/navigation/dropin/map/MapViewBinder.kt @@ -67,7 +67,7 @@ abstract class MapViewBinder : UIBinder { val store = context.store val navigationState = store.select { it.navigation } return navigationListOf( - CameraLayoutObserver(store, mapView, navigationViewBinding), + CameraLayoutObserver(context, mapView, navigationViewBinding), LocationComponent(context.locationProvider), context.locationPuckComponent(mapView), LogoAttributionComponent(mapView, context.systemBarsInsets), diff --git a/libnavui-dropin/src/main/res/values-land/dimens.xml b/libnavui-dropin/src/main/res/values-land/dimens.xml new file mode 100644 index 00000000000..f3f8bbfd6d6 --- /dev/null +++ b/libnavui-dropin/src/main/res/values-land/dimens.xml @@ -0,0 +1,6 @@ + + + + 30dp + 35dp + diff --git a/libnavui-dropin/src/main/res/values/dimens.xml b/libnavui-dropin/src/main/res/values/dimens.xml index 46ff31249ff..7ac2c449268 100644 --- a/libnavui-dropin/src/main/res/values/dimens.xml +++ b/libnavui-dropin/src/main/res/values/dimens.xml @@ -25,10 +25,8 @@ 4dp - 50dp - 35dp + 30dp 50dp - 35dp 72dp 52dp diff --git a/libnavui-dropin/src/test/java/com/mapbox/navigation/dropin/camera/CameraLayoutObserverTest.kt b/libnavui-dropin/src/test/java/com/mapbox/navigation/dropin/camera/CameraLayoutObserverTest.kt index 7a8c5a31a2c..6e979aa0e57 100644 --- a/libnavui-dropin/src/test/java/com/mapbox/navigation/dropin/camera/CameraLayoutObserverTest.kt +++ b/libnavui-dropin/src/test/java/com/mapbox/navigation/dropin/camera/CameraLayoutObserverTest.kt @@ -1,27 +1,29 @@ -@file:Suppress("PrivatePropertyName", "MaxLineLength") - package com.mapbox.navigation.dropin.camera import android.app.Service import android.content.Context import android.view.LayoutInflater import android.view.View -import android.view.View.OnLayoutChangeListener import android.widget.FrameLayout +import androidx.core.view.doOnNextLayout import androidx.test.core.app.ApplicationProvider +import com.google.android.material.bottomsheet.BottomSheetBehavior import com.mapbox.navigation.dropin.R import com.mapbox.navigation.dropin.databinding.MapboxNavigationViewLayoutBinding +import com.mapbox.navigation.dropin.infopanel.InfoPanelBehavior +import com.mapbox.navigation.dropin.navigationview.NavigationViewContext +import com.mapbox.navigation.dropin.navigationview.NavigationViewModel +import com.mapbox.navigation.dropin.testutil.TestLifecycleOwner import com.mapbox.navigation.dropin.util.TestStore +import com.mapbox.navigation.testing.LoggingFrontendTestRule import com.mapbox.navigation.testing.MainCoroutineRule import com.mapbox.navigation.ui.app.internal.camera.CameraAction -import com.mapbox.navigation.ui.app.internal.navigation.NavigationState import io.mockk.mockk import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch import kotlinx.coroutines.suspendCancellableCoroutine import org.junit.Assert.assertEquals -import org.junit.Assert.assertNotEquals import org.junit.Before import org.junit.Rule import org.junit.Test @@ -37,9 +39,13 @@ class CameraLayoutObserverTest { @get:Rule val coroutineRule = MainCoroutineRule() + @get:Rule + val loggerRule = LoggingFrontendTestRule() + private lateinit var store: TestStore private lateinit var binding: MapboxNavigationViewLayoutBinding private lateinit var mapView: View + private lateinit var infoPanelBehavior: InfoPanelBehavior private lateinit var sut: CameraLayoutObserver @Before @@ -51,103 +57,66 @@ class CameraLayoutObserverTest { ).apply { // slightly modifying default layout to simulate layout changes guidanceLayout.bottom = 100 - roadNameLayout.top = 100 - actionListLayout.left = 100 - infoPanelLayout.right = 100 + roadNameLayout.top = 900 + infoPanelLayout.right = 500 } - mapView = View(context) + mapView = View(context).apply { bottom = 1000 } store = TestStore() - sut = CameraLayoutObserver(store, mapView, binding) + val navContext = NavigationViewContext( + context, + TestLifecycleOwner(), + NavigationViewModel(), + ) { store } + infoPanelBehavior = navContext.behavior.infoPanelBehavior + sut = CameraLayoutObserver(navContext, mapView, binding) } @Test @Config(qualifiers = "port") - fun `portrait - should update bottom padding for DestinationPreview, FreeDrive and RoutePreview state`() = + fun `portrait - should update camera paddings`() = coroutineRule.runBlockingTest { sut.onAttached(mockk()) - triggerLayoutChangesAndVerifyDispatchedActions( - givenNavigationStates = listOf( - NavigationState.DestinationPreview, - NavigationState.FreeDrive, - NavigationState.RoutePreview, - ) - ) { state, action -> - assertEquals("$state|top", action.padding.top, PADDING_V_PORT, 0.001) - assertNotEquals("$state|bottom", action.padding.bottom, PADDING_V_PORT, 0.001) - assertEquals("$state|left", action.padding.left, PADDING_H_PORT, 0.001) - assertEquals("$state|right", action.padding.right, PADDING_H_PORT, 0.001) - } - } - - @Test - @Config(qualifiers = "port") - fun `portrait - should update top and bottom padding for ActiveNavigation and Arrival state`() = - coroutineRule.runBlockingTest { - sut.onAttached(mockk()) + binding.coordinatorLayout.triggerLayoutChange() - triggerLayoutChangesAndVerifyDispatchedActions( - givenNavigationStates = listOf( - NavigationState.ActiveNavigation, - NavigationState.Arrival, - ) - ) { s, action -> - assertNotEquals("$s|top", action.padding.top, PADDING_V_PORT, 0.001) - assertNotEquals("$s|bottom", action.padding.bottom, PADDING_V_PORT, 0.001) - assertEquals("$s|left", action.padding.left, PADDING_H_PORT, 0.001) - assertEquals("$s|right", action.padding.right, PADDING_H_PORT, 0.001) - } + val action = store.actions.last() as CameraAction.UpdatePadding + assertEquals("left", paddingH, action.padding.left, 0.001) + assertEquals("top", 100 + paddingV, action.padding.top, 0.001) + assertEquals("right", paddingH, action.padding.right, 0.001) + assertEquals("bottom", 100 + paddingV, action.padding.bottom, 0.001) } @Test @Config(qualifiers = "land") - fun `landscape - should update bottom padding for FreeDrive state`() = + fun `landscape - should update camera paddings when bottom sheet is collapsed`() = coroutineRule.runBlockingTest { sut.onAttached(mockk()) - triggerLayoutChangesAndVerifyDispatchedActions( - givenNavigationStates = listOf( - NavigationState.FreeDrive - ) - ) { s, action -> - assertEquals("$s|top", action.padding.top, PADDING_V_LAND, 0.001) - assertNotEquals("$s|bottom", action.padding.bottom, PADDING_V_LAND, 0.001) - assertEquals("$s|left", action.padding.left, PADDING_H_LAND, 0.001) - assertEquals("$s|right", action.padding.right, PADDING_H_LAND, 0.001) - } + infoPanelBehavior.updateBottomSheetState(BottomSheetBehavior.STATE_COLLAPSED) + binding.coordinatorLayout.triggerLayoutChange() + + val action = store.actions.last() as CameraAction.UpdatePadding + assertEquals("left", 500 + paddingH, action.padding.left, 0.001) + assertEquals("top", paddingV, action.padding.top, 0.001) + assertEquals("right", paddingH, action.padding.right, 0.001) + assertEquals("bottom", 100 + paddingV, action.padding.bottom, 0.001) } @Test @Config(qualifiers = "land") - fun `landscape - should update left and bottom padding for all states except FreeDrive`() = + fun `landscape - should update camera paddings when bottom sheet is hidden`() = coroutineRule.runBlockingTest { sut.onAttached(mockk()) - triggerLayoutChangesAndVerifyDispatchedActions( - givenNavigationStates = listOf( - NavigationState.DestinationPreview, - NavigationState.RoutePreview, - NavigationState.ActiveNavigation, - NavigationState.Arrival, - ) - ) { s, action -> - assertEquals("$s|top", action.padding.top, PADDING_V_LAND, 0.001) - assertNotEquals("$s|bottom", action.padding.bottom, PADDING_V_LAND, 0.001) - assertNotEquals("$s|left", action.padding.left, PADDING_H_LAND, 0.001) - assertEquals("$s|right", action.padding.right, PADDING_H_LAND, 0.001) - } - } - - private suspend fun triggerLayoutChangesAndVerifyDispatchedActions( - givenNavigationStates: List, - assertAction: (state: NavigationState, action: CameraAction.UpdatePadding) -> Unit - ) { - givenNavigationStates.forEachIndexed { index, navState -> - store.updateState { it.copy(navigation = navState) } + infoPanelBehavior.updateBottomSheetState(BottomSheetBehavior.STATE_HIDDEN) binding.coordinatorLayout.triggerLayoutChange() - assertAction(navState, store.actions[index] as CameraAction.UpdatePadding) + + val action = store.actions.last() as CameraAction.UpdatePadding + assertEquals("left", paddingH, action.padding.left, 0.001) + assertEquals("top", paddingV, action.padding.top, 0.001) + assertEquals("right", paddingH, action.padding.right, 0.001) + assertEquals("bottom", 100 + paddingV, action.padding.bottom, 0.001) } - } private suspend fun View.triggerLayoutChange() = coroutineScope { launch { @@ -158,34 +127,13 @@ class CameraLayoutObserverTest { } private suspend fun View.waitForLayoutChange() = suspendCancellableCoroutine { cont -> - addOnLayoutChangeListener(object : OnLayoutChangeListener { - override fun onLayoutChange( - v: View?, - left: Int, - top: Int, - right: Int, - bottom: Int, - oldLeft: Int, - oldTop: Int, - oldRight: Int, - oldBottom: Int - ) { - cont.resume(Unit) - removeOnLayoutChangeListener(this) - } - }) + doOnNextLayout { cont.resume(Unit) } } - private val PADDING_V_PORT: Double + private val paddingV: Double get() = binding.root.resources .getDimensionPixelSize(R.dimen.mapbox_camera_overview_padding_v).toDouble() - private val PADDING_H_PORT: Double + private val paddingH: Double get() = binding.root.resources .getDimensionPixelSize(R.dimen.mapbox_camera_overview_padding_h).toDouble() - private val PADDING_V_LAND: Double - get() = binding.root.resources - .getDimensionPixelSize(R.dimen.mapbox_camera_overview_padding_landscape_v).toDouble() - private val PADDING_H_LAND: Double - get() = binding.root.resources - .getDimensionPixelSize(R.dimen.mapbox_camera_overview_padding_landscape_h).toDouble() }