diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeChildToParentCommunication.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeChildToParentCommunication.kt index 1fc093e7c06..b03713dd438 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeChildToParentCommunication.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeChildToParentCommunication.kt @@ -23,6 +23,7 @@ sealed class ChildToParentEvent { data class ItemClickedInProductSelector(val productId: Long) : ChildToParentEvent() data object NewTransactionClicked : ChildToParentEvent() data object OrderSuccessfullyPaid : ChildToParentEvent() + data object ExitPosClicked : ChildToParentEvent() sealed class CartStatusChanged : ChildToParentEvent() { data object Empty : CartStatusChanged() data object NotEmpty : CartStatusChanged() diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeScreen.kt index e8ed1649d7e..2ecb281488e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeScreen.kt @@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width @@ -21,19 +22,24 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import com.woocommerce.android.ui.woopos.common.composeui.WooPosPreview import com.woocommerce.android.ui.woopos.common.composeui.WooPosTheme +import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosConfirmationDialog import com.woocommerce.android.ui.woopos.common.composeui.isPreviewMode import com.woocommerce.android.ui.woopos.common.composeui.toAdaptivePadding import com.woocommerce.android.ui.woopos.home.cart.WooPosCartScreen import com.woocommerce.android.ui.woopos.home.cart.WooPosCartScreenProductsPreview import com.woocommerce.android.ui.woopos.home.products.WooPosProductsScreen import com.woocommerce.android.ui.woopos.home.products.WooPosProductsScreenPreview +import com.woocommerce.android.ui.woopos.home.toolbar.PreviewWooPosFloatingToolbarStatusConnectedWithMenu +import com.woocommerce.android.ui.woopos.home.toolbar.WooPosFloatingToolbar import com.woocommerce.android.ui.woopos.home.totals.WooPosTotalsScreen import com.woocommerce.android.ui.woopos.home.totals.WooPosTotalsScreenPreview import com.woocommerce.android.ui.woopos.root.navigation.WooPosNavigationEvent @@ -56,13 +62,21 @@ fun WooPosHomeScreen( private fun WooPosHomeScreen( state: WooPosHomeState, onNavigationEvent: (WooPosNavigationEvent) -> Unit, - onHomeUIEvent: (WooPosHomeUIEvent) -> Boolean, + onHomeUIEvent: (WooPosHomeUIEvent) -> Unit, ) { BackHandler { - val result = onHomeUIEvent(WooPosHomeUIEvent.SystemBackClicked) - if (!result) { - onNavigationEvent(WooPosNavigationEvent.BackFromHomeClicked) - } + onHomeUIEvent(WooPosHomeUIEvent.SystemBackClicked) + } + + state.exitConfirmationDialog?.let { + WooPosConfirmationDialog( + title = stringResource(id = it.title), + message = stringResource(id = it.message), + confirmButtonText = stringResource(id = it.confirmButton), + dismissButtonText = stringResource(id = it.dismissButton), + onDismiss = { onHomeUIEvent(WooPosHomeUIEvent.ExitConfirmationDialogDismissed) }, + onConfirm = { onNavigationEvent(WooPosNavigationEvent.ExitPosClicked) } + ) } val current = LocalConfiguration.current @@ -72,35 +86,35 @@ private fun WooPosHomeScreen( val totalsWidthDp = remember(screenWidthDp, cartWidthDp) { screenWidthDp - cartWidthDp } val totalsWidthAnimatedDp by animateDpAsState( - when (state) { - is WooPosHomeState.Checkout.Paid -> screenWidthDp - is WooPosHomeState.Cart, - WooPosHomeState.Checkout.NotPaid -> totalsWidthDp + when (state.screenPositionState) { + is WooPosHomeState.ScreenPositionState.Checkout.Paid -> screenWidthDp + is WooPosHomeState.ScreenPositionState.Cart, + WooPosHomeState.ScreenPositionState.Checkout.NotPaid -> totalsWidthDp }, label = "totalsWidthAnimatedDp" ) val cartOverlayIntensityAnimated by animateFloatAsState( - when (state) { - is WooPosHomeState.Cart.Empty -> .6f - WooPosHomeState.Cart.NotEmpty, - WooPosHomeState.Checkout.NotPaid, - WooPosHomeState.Checkout.Paid -> 0f + when (state.screenPositionState) { + is WooPosHomeState.ScreenPositionState.Cart.Empty -> .6f + WooPosHomeState.ScreenPositionState.Cart.NotEmpty, + WooPosHomeState.ScreenPositionState.Checkout.NotPaid, + WooPosHomeState.ScreenPositionState.Checkout.Paid -> 0f }, label = "cartOverlayAnimated" ) val totalsStartPaddingAnimatedDp by animateDpAsState( - when (state) { - is WooPosHomeState.Cart, - WooPosHomeState.Checkout.NotPaid -> 0.dp.toAdaptivePadding() + when (state.screenPositionState) { + is WooPosHomeState.ScreenPositionState.Cart, + WooPosHomeState.ScreenPositionState.Checkout.NotPaid -> 0.dp.toAdaptivePadding() - WooPosHomeState.Checkout.Paid -> 24.dp.toAdaptivePadding() + WooPosHomeState.ScreenPositionState.Checkout.Paid -> 24.dp.toAdaptivePadding() }, label = "totalsStartPaddingAnimatedDp" ) - val scrollState = buildScrollStateForNavigationBetweenState(state) + val scrollState = buildScrollStateForNavigationBetweenState(state.screenPositionState) WooPosHomeScreen( scrollState = scrollState, productsWidthDp = productsWidthDp, @@ -120,46 +134,54 @@ private fun WooPosHomeScreen( totalsWidthDp: Dp, totalsStartPaddingDp: Dp, ) { - Row( - modifier = Modifier - .horizontalScroll(scrollState, enabled = false) - .fillMaxWidth(), - ) { - Row(modifier = Modifier.width(productsWidthDp)) { - WooPosHomeScreenProducts( - modifier = Modifier - .width(productsWidthDp) - ) - } + Box(modifier = Modifier.fillMaxSize()) { Row( modifier = Modifier - .width(cartWidthDp) - .background(MaterialTheme.colors.surface) + .horizontalScroll(scrollState, enabled = false) + .fillMaxWidth(), ) { - Box { - WooPosHomeScreenCart( + Row(modifier = Modifier.width(productsWidthDp)) { + WooPosHomeScreenProducts( modifier = Modifier - .width(cartWidthDp) + .width(productsWidthDp) ) - Box( + } + Row( + modifier = Modifier + .width(cartWidthDp) + .background(MaterialTheme.colors.surface) + ) { + Box { + WooPosHomeScreenCart( + modifier = Modifier + .width(cartWidthDp) + ) + Box( + modifier = Modifier + .width(cartWidthDp) + .fillMaxHeight() + .background( + color = MaterialTheme.colors.background.copy(alpha = cartOverlayIntensity), + ) + ) + } + } + Row(modifier = Modifier.width(totalsWidthDp)) { + Spacer(modifier = Modifier.width(totalsStartPaddingDp)) + WooPosHomeScreenTotals( modifier = Modifier - .width(cartWidthDp) - .fillMaxHeight() - .background( - color = MaterialTheme.colors.background.copy(alpha = cartOverlayIntensity), - ) + .width(totalsWidthDp - 24.dp.toAdaptivePadding() - totalsStartPaddingDp) + .padding(vertical = 24.dp.toAdaptivePadding()) ) + Spacer(modifier = Modifier.width(24.dp.toAdaptivePadding())) } } - Row(modifier = Modifier.width(totalsWidthDp)) { - Spacer(modifier = Modifier.width(totalsStartPaddingDp)) - WooPosHomeScreenTotals( - modifier = Modifier - .width(totalsWidthDp - 24.dp.toAdaptivePadding() - totalsStartPaddingDp) - .padding(vertical = 24.dp.toAdaptivePadding()) - ) - Spacer(modifier = Modifier.width(24.dp.toAdaptivePadding())) - } + + WooPosHomeScreenToolbar( + modifier = Modifier + .padding(24.dp.toAdaptivePadding()) + .align(Alignment.BottomStart), + ) } } @@ -191,19 +213,27 @@ private fun WooPosHomeScreenTotals(modifier: Modifier) { } @Composable -private fun buildScrollStateForNavigationBetweenState(state: WooPosHomeState): ScrollState { +private fun WooPosHomeScreenToolbar(modifier: Modifier) { + if (isPreviewMode()) { + PreviewWooPosFloatingToolbarStatusConnectedWithMenu() + } else { + WooPosFloatingToolbar(modifier = modifier) + } +} + +@Composable +private fun buildScrollStateForNavigationBetweenState(state: WooPosHomeState.ScreenPositionState): ScrollState { val scrollState = rememberScrollState() LaunchedEffect(state) { val animationSpec = spring(dampingRatio = 0.8f, stiffness = 200f) when (state) { - is WooPosHomeState.Cart -> { + is WooPosHomeState.ScreenPositionState.Cart -> scrollState.animateScrollTo( 0, animationSpec = animationSpec ) - } - is WooPosHomeState.Checkout -> scrollState.animateScrollTo( + is WooPosHomeState.ScreenPositionState.Checkout -> scrollState.animateScrollTo( scrollState.maxValue, animationSpec = animationSpec ) @@ -217,8 +247,8 @@ private fun buildScrollStateForNavigationBetweenState(state: WooPosHomeState): S fun WooPosHomeCartScreenPreview() { WooPosTheme { WooPosHomeScreen( - state = WooPosHomeState.Cart.NotEmpty, - onHomeUIEvent = { true }, + state = WooPosHomeState(screenPositionState = WooPosHomeState.ScreenPositionState.Cart.NotEmpty), + onHomeUIEvent = { }, onNavigationEvent = {}, ) } @@ -229,8 +259,10 @@ fun WooPosHomeCartScreenPreview() { fun WooPosHomeCartEmptyScreenPreview() { WooPosTheme { WooPosHomeScreen( - state = WooPosHomeState.Cart.Empty, - onHomeUIEvent = { true }, + state = WooPosHomeState( + screenPositionState = WooPosHomeState.ScreenPositionState.Cart.Empty + ), + onHomeUIEvent = { }, onNavigationEvent = {}, ) } @@ -241,8 +273,8 @@ fun WooPosHomeCartEmptyScreenPreview() { fun WooPosHomeCheckoutScreenPreview() { WooPosTheme { WooPosHomeScreen( - state = WooPosHomeState.Checkout.NotPaid, - onHomeUIEvent = { true }, + state = WooPosHomeState(screenPositionState = WooPosHomeState.ScreenPositionState.Checkout.NotPaid), + onHomeUIEvent = { }, onNavigationEvent = {}, ) } @@ -253,8 +285,8 @@ fun WooPosHomeCheckoutScreenPreview() { fun WooPosHomeCheckoutPaidScreenPreview() { WooPosTheme { WooPosHomeScreen( - state = WooPosHomeState.Checkout.Paid, - onHomeUIEvent = { true }, + state = WooPosHomeState(screenPositionState = WooPosHomeState.ScreenPositionState.Checkout.Paid), + onHomeUIEvent = { }, onNavigationEvent = {}, ) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeState.kt index 78048a5767d..787f26cd847 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeState.kt @@ -1,13 +1,27 @@ package com.woocommerce.android.ui.woopos.home -sealed class WooPosHomeState { - sealed class Cart : WooPosHomeState() { - data object Empty : Cart() - data object NotEmpty : Cart() - } +import com.woocommerce.android.R + +data class WooPosHomeState( + val screenPositionState: ScreenPositionState, + val exitConfirmationDialog: WooPosExitConfirmationDialog? = null, +) { + sealed class ScreenPositionState { + sealed class Cart : ScreenPositionState() { + data object Empty : Cart() + data object NotEmpty : Cart() + } - sealed class Checkout : WooPosHomeState() { - data object NotPaid : Checkout() - data object Paid : Checkout() + sealed class Checkout : ScreenPositionState() { + data object NotPaid : Checkout() + data object Paid : Checkout() + } } } + +data object WooPosExitConfirmationDialog { + val title: Int = R.string.woopos_exit_confirmation_title + val message: Int = R.string.woopos_exit_confirmation_message + val confirmButton: Int = R.string.woopos_exit_confirmation_confirm_button + val dismissButton: Int = R.string.woopos_exit_confirmation_dismiss_button +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeUIEvent.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeUIEvent.kt index 5357e5e8a1d..2bad9be9ae1 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeUIEvent.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeUIEvent.kt @@ -2,4 +2,5 @@ package com.woocommerce.android.ui.woopos.home sealed class WooPosHomeUIEvent { data object SystemBackClicked : WooPosHomeUIEvent() + data object ExitConfirmationDialogDismissed : WooPosHomeUIEvent() } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt index cbc166c874f..7bf89c98432 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModel.kt @@ -13,34 +13,47 @@ class WooPosHomeViewModel @Inject constructor( private val childrenToParentEventReceiver: WooPosChildrenToParentEventReceiver, private val parentToChildrenEventSender: WooPosParentToChildrenEventSender, ) : ViewModel() { - private val _state = MutableStateFlow(WooPosHomeState.Cart.Empty) + private val _state = MutableStateFlow( + WooPosHomeState( + screenPositionState = WooPosHomeState.ScreenPositionState.Cart.Empty, + exitConfirmationDialog = null + ) + ) val state: StateFlow = _state init { listenBottomEvents() } - fun onUIEvent(event: WooPosHomeUIEvent): Boolean { + fun onUIEvent(event: WooPosHomeUIEvent) { return when (event) { WooPosHomeUIEvent.SystemBackClicked -> { - when (_state.value) { - WooPosHomeState.Checkout.NotPaid -> { - _state.value = WooPosHomeState.Cart.NotEmpty + when (_state.value.screenPositionState) { + WooPosHomeState.ScreenPositionState.Checkout.NotPaid -> { + _state.value = _state.value.copy( + screenPositionState = WooPosHomeState.ScreenPositionState.Cart.NotEmpty + ) sendEventToChildren(ParentToChildrenEvent.BackFromCheckoutToCartClicked) - true } - WooPosHomeState.Checkout.Paid -> { - _state.value = WooPosHomeState.Cart.Empty + WooPosHomeState.ScreenPositionState.Checkout.Paid -> { + _state.value = _state.value.copy( + screenPositionState = WooPosHomeState.ScreenPositionState.Cart.Empty + ) sendEventToChildren(ParentToChildrenEvent.OrderSuccessfullyPaid) - true } - is WooPosHomeState.Cart -> { - false + is WooPosHomeState.ScreenPositionState.Cart -> { + _state.value = _state.value.copy( + exitConfirmationDialog = WooPosExitConfirmationDialog + ) } } } + + WooPosHomeUIEvent.ExitConfirmationDialogDismissed -> { + _state.value = _state.value.copy(exitConfirmationDialog = null) + } } } @@ -49,12 +62,16 @@ class WooPosHomeViewModel @Inject constructor( childrenToParentEventReceiver.events.collect { event -> when (event) { is ChildToParentEvent.CheckoutClicked -> { - _state.value = WooPosHomeState.Checkout.NotPaid + _state.value = _state.value.copy( + screenPositionState = WooPosHomeState.ScreenPositionState.Checkout.NotPaid + ) sendEventToChildren(ParentToChildrenEvent.CheckoutClicked(event.productIds)) } is ChildToParentEvent.BackFromCheckoutToCartClicked -> { - _state.value = WooPosHomeState.Cart.NotEmpty + _state.value = _state.value.copy( + screenPositionState = WooPosHomeState.ScreenPositionState.Cart.NotEmpty + ) } is ChildToParentEvent.ItemClickedInProductSelector -> { @@ -64,27 +81,43 @@ class WooPosHomeViewModel @Inject constructor( } is ChildToParentEvent.NewTransactionClicked -> { - _state.value = WooPosHomeState.Cart.Empty + _state.value = _state.value.copy( + screenPositionState = WooPosHomeState.ScreenPositionState.Cart.Empty + ) sendEventToChildren(ParentToChildrenEvent.OrderSuccessfullyPaid) } is ChildToParentEvent.OrderSuccessfullyPaid -> { - _state.value = WooPosHomeState.Checkout.Paid + _state.value = _state.value.copy( + screenPositionState = WooPosHomeState.ScreenPositionState.Checkout.Paid + ) } is ChildToParentEvent.CartStatusChanged -> { - if (_state.value is WooPosHomeState.Checkout.Paid) return@collect + if (_state.value.screenPositionState is WooPosHomeState.ScreenPositionState.Checkout.Paid) { + return@collect + } when (event) { ChildToParentEvent.CartStatusChanged.Empty -> { - _state.value = WooPosHomeState.Cart.Empty + _state.value = _state.value.copy( + screenPositionState = WooPosHomeState.ScreenPositionState.Cart.Empty + ) } ChildToParentEvent.CartStatusChanged.NotEmpty -> { - _state.value = WooPosHomeState.Cart.NotEmpty + _state.value = _state.value.copy( + screenPositionState = WooPosHomeState.ScreenPositionState.Cart.NotEmpty + ) } } } + + ChildToParentEvent.ExitPosClicked -> { + _state.value = _state.value.copy( + exitConfirmationDialog = WooPosExitConfirmationDialog + ) + } } } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosRootFloatingToolbar.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbar.kt similarity index 81% rename from WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosRootFloatingToolbar.kt rename to WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbar.kt index 7048390a4f8..c3cd283c908 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosRootFloatingToolbar.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbar.kt @@ -1,4 +1,4 @@ -package com.woocommerce.android.ui.woopos.root +package com.woocommerce.android.ui.woopos.home.toolbar import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.animateColor @@ -8,6 +8,7 @@ import androidx.compose.animation.core.updateTransition import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.background +import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement @@ -20,7 +21,6 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.ButtonDefaults @@ -32,6 +32,7 @@ import androidx.compose.material.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.State +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -46,18 +47,30 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.constraintlayout.compose.ConstraintLayout import androidx.constraintlayout.compose.Dimension +import androidx.hilt.navigation.compose.hiltViewModel import com.woocommerce.android.R import com.woocommerce.android.ui.woopos.common.composeui.WooPosPreview import com.woocommerce.android.ui.woopos.common.composeui.WooPosTheme import com.woocommerce.android.ui.woopos.common.composeui.toAdaptivePadding -import com.woocommerce.android.ui.woopos.root.WooPosRootScreenState.Menu.MenuItem -import com.woocommerce.android.ui.woopos.root.WooPosRootScreenState.WooPosCardReaderStatus +import com.woocommerce.android.ui.woopos.home.toolbar.WooPosToolbarState.Menu +import com.woocommerce.android.ui.woopos.home.toolbar.WooPosToolbarState.WooPosCardReaderStatus @Composable -fun WooPosFloatingToolbar( +fun WooPosFloatingToolbar(modifier: Modifier = Modifier) { + val viewModel: WooPosToolbarViewModel = hiltViewModel() + WooPosFloatingToolbar( + modifier = modifier, + state = viewModel.state.collectAsState(), + ) { uiEvent -> + viewModel.onUiEvent(uiEvent) + } +} + +@Composable +private fun WooPosFloatingToolbar( modifier: Modifier = Modifier, - state: State, - onUIEvent: (WooPosRootUIEvent) -> Unit, + state: State, + onUIEvent: (WooPosToolbarUIEvent) -> Unit, ) { val cardReaderStatus = state.value.cardReaderStatus val menu = state.value.menu @@ -70,15 +83,15 @@ fun WooPosFloatingToolbar( .clickable( indication = null, interactionSource = remember { MutableInteractionSource() } - ) { onUIEvent(WooPosRootUIEvent.OnOutsideOfToolbarMenuClicked) }, - isVisible = menu is WooPosRootScreenState.Menu.Visible, + ) { onUIEvent(WooPosToolbarUIEvent.OnOutsideOfToolbarMenuClicked) }, + isVisible = menu is Menu.Visible, ) ConstraintLayout(modifier = modifier) { val (toolbar, popupMenu) = createRefs() when (menu) { - is WooPosRootScreenState.Menu.Hidden -> { + is Menu.Hidden -> { Toolbar( modifier = Modifier.constrainAs(toolbar) { bottom.linkTo(parent.bottom) @@ -90,7 +103,7 @@ fun WooPosFloatingToolbar( ) } - is WooPosRootScreenState.Menu.Visible -> { + is Menu.Visible -> { Toolbar( modifier = Modifier.constrainAs(toolbar) { bottom.linkTo(parent.bottom) @@ -109,7 +122,7 @@ fun WooPosFloatingToolbar( }, menuItems = menu.items, onClick = { menuItem -> - onUIEvent(WooPosRootUIEvent.MenuItemClicked(menuItem)) + onUIEvent(WooPosToolbarUIEvent.MenuItemClicked(menuItem)) } ) } @@ -137,7 +150,7 @@ private fun Toolbar( modifier: Modifier, menuCardDisabled: Boolean, cardReaderStatus: WooPosCardReaderStatus, - onUIEvent: (WooPosRootUIEvent) -> Unit + onUIEvent: (WooPosToolbarUIEvent) -> Unit ) { ConstraintLayout(modifier = modifier) { val (menuCard, cardReaderStatusCard) = createRefs() @@ -152,7 +165,7 @@ private fun Toolbar( bottom.linkTo(parent.bottom) }, state = cardReaderStatus, - ) { onUIEvent(WooPosRootUIEvent.ConnectToAReaderClicked) } + ) { onUIEvent(WooPosToolbarUIEvent.ConnectToAReaderClicked) } MenuButtonWithPopUpMenu( modifier = Modifier @@ -163,7 +176,7 @@ private fun Toolbar( height = Dimension.fillToConstraints }, menuCardDisabled = menuCardDisabled, - ) { onUIEvent(WooPosRootUIEvent.OnToolbarMenuClicked) } + ) { onUIEvent(WooPosToolbarUIEvent.OnToolbarMenuClicked) } } } @@ -208,8 +221,8 @@ private fun MenuButtonWithPopUpMenu( @Composable private fun PopUpMenu( modifier: Modifier, - menuItems: List, - onClick: (MenuItem) -> Unit + menuItems: List, + onClick: (Menu.MenuItem) -> Unit ) { Card( modifier = modifier.width(214.dp), @@ -227,8 +240,8 @@ private fun PopUpMenu( @Composable private fun PopUpMenuItem( - menuItem: MenuItem, - onClick: (MenuItem) -> Unit + menuItem: Menu.MenuItem, + onClick: (Menu.MenuItem) -> Unit ) { TextButton(onClick = { onClick(menuItem) }) { Spacer(modifier = Modifier.width(20.dp.toAdaptivePadding())) @@ -281,9 +294,7 @@ private fun CardReaderStatusButton( ) { status -> when (status) { WooPosCardReaderStatus.Connected -> MaterialTheme.colors.secondary - WooPosCardReaderStatus.NotConnected -> MaterialTheme.colors.secondaryVariant.copy( - alpha = 0.8f - ) + WooPosCardReaderStatus.NotConnected -> MaterialTheme.colors.primary } } @@ -294,14 +305,34 @@ private fun CardReaderStatusButton( } ) + val borderColor by transition.animateColor( + transitionSpec = { tween(durationMillis = animationDuration) }, + label = "BorderColorTransition" + ) { status -> + when (status) { + WooPosCardReaderStatus.Connected -> Color.Transparent + WooPosCardReaderStatus.NotConnected -> MaterialTheme.colors.primary + } + } + Card( modifier = modifier - .wrapContentSize(Alignment.Center), + .height(56.dp), backgroundColor = MaterialTheme.colors.surface, elevation = 8.dp, shape = RoundedCornerShape(8.dp), ) { - TextButton(onClick = onClick) { + TextButton( + onClick = onClick, + modifier = Modifier + .padding(8.dp.toAdaptivePadding()) + .border( + width = 2.dp, + color = borderColor, + shape = RoundedCornerShape(4.dp) + ) + .height(40.dp), + ) { Spacer(modifier = Modifier.width(16.dp.toAdaptivePadding())) Circle(size = 12.dp, color = illustrationColor) Spacer(modifier = Modifier.width(4.dp.toAdaptivePadding())) @@ -322,7 +353,7 @@ private fun ReaderStatusText( color: Color ) { Text( - modifier = modifier.padding(8.dp.toAdaptivePadding()), + modifier = modifier.padding(horizontal = 8.dp.toAdaptivePadding()), text = title, color = color, style = MaterialTheme.typography.button @@ -346,10 +377,9 @@ private fun Circle( fun PreviewWooPosFloatingToolbarStatusNotConnected() { val state = remember { mutableStateOf( - WooPosRootScreenState( - WooPosCardReaderStatus.NotConnected, - menu = WooPosRootScreenState.Menu.Hidden, - null + WooPosToolbarState( + cardReaderStatus = WooPosCardReaderStatus.NotConnected, + menu = Menu.Hidden ) ) } @@ -361,21 +391,20 @@ fun PreviewWooPosFloatingToolbarStatusNotConnected() { fun PreviewWooPosFloatingToolbarStatusConnectedWithMenu() { val state = remember { mutableStateOf( - WooPosRootScreenState( - WooPosCardReaderStatus.Connected, - menu = WooPosRootScreenState.Menu.Visible( + WooPosToolbarState( + cardReaderStatus = WooPosCardReaderStatus.Connected, + menu = Menu.Visible( listOf( - MenuItem( + Menu.MenuItem( title = R.string.woopos_exit_confirmation_message, icon = R.drawable.woopos_ic_exit_pos, ), - MenuItem( + Menu.MenuItem( title = R.string.woopos_get_support_title, icon = R.drawable.woopos_ic_get_support, ) ) ), - null ) ) } @@ -383,7 +412,7 @@ fun PreviewWooPosFloatingToolbarStatusConnectedWithMenu() { } @Composable -private fun Preview(state: MutableState) { +private fun Preview(state: MutableState) { WooPosTheme { Box( modifier = Modifier.fillMaxSize(), diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosRootScreenState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarState.kt similarity index 58% rename from WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosRootScreenState.kt rename to WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarState.kt index b38977b7385..dd3ec45ab82 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosRootScreenState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarState.kt @@ -1,26 +1,18 @@ -package com.woocommerce.android.ui.woopos.root +package com.woocommerce.android.ui.woopos.home.toolbar import androidx.annotation.DrawableRes import androidx.annotation.StringRes import com.woocommerce.android.R -data class WooPosRootScreenState( +data class WooPosToolbarState( val cardReaderStatus: WooPosCardReaderStatus, val menu: Menu, - val exitConfirmationDialog: WooPosExitConfirmationDialog?, ) { sealed class WooPosCardReaderStatus(@StringRes val title: Int) { data object NotConnected : WooPosCardReaderStatus(title = R.string.woopos_reader_disconnected) data object Connected : WooPosCardReaderStatus(title = R.string.woopos_reader_connected) } - data object WooPosExitConfirmationDialog { - val title: Int = R.string.woopos_exit_confirmation_title - val message: Int = R.string.woopos_exit_confirmation_message - val confirmButton: Int = R.string.woopos_exit_confirmation_confirm_button - val dismissButton: Int = R.string.woopos_exit_confirmation_dismiss_button - } - sealed class Menu { data object Hidden : Menu() data class Visible(val items: List) : Menu() diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarUIEvent.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarUIEvent.kt new file mode 100644 index 00000000000..7085daada3e --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarUIEvent.kt @@ -0,0 +1,8 @@ +package com.woocommerce.android.ui.woopos.home.toolbar + +sealed class WooPosToolbarUIEvent { + data object OnToolbarMenuClicked : WooPosToolbarUIEvent() + data object OnOutsideOfToolbarMenuClicked : WooPosToolbarUIEvent() + data object ConnectToAReaderClicked : WooPosToolbarUIEvent() + data class MenuItemClicked(val menuItem: WooPosToolbarState.Menu.MenuItem) : WooPosToolbarUIEvent() +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarViewModel.kt new file mode 100644 index 00000000000..73782fcd6d1 --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarViewModel.kt @@ -0,0 +1,111 @@ +package com.woocommerce.android.ui.woopos.home.toolbar + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.woocommerce.android.R +import com.woocommerce.android.cardreader.connection.CardReaderStatus +import com.woocommerce.android.cardreader.connection.CardReaderStatus.Connected +import com.woocommerce.android.cardreader.connection.CardReaderStatus.Connecting +import com.woocommerce.android.cardreader.connection.CardReaderStatus.NotConnected +import com.woocommerce.android.ui.woopos.cardreader.WooPosCardReaderFacade +import com.woocommerce.android.ui.woopos.home.ChildToParentEvent +import com.woocommerce.android.ui.woopos.home.WooPosChildrenToParentEventSender +import com.woocommerce.android.ui.woopos.home.toolbar.WooPosToolbarUIEvent.ConnectToAReaderClicked +import com.woocommerce.android.ui.woopos.home.toolbar.WooPosToolbarUIEvent.MenuItemClicked +import com.woocommerce.android.ui.woopos.home.toolbar.WooPosToolbarUIEvent.OnOutsideOfToolbarMenuClicked +import com.woocommerce.android.ui.woopos.home.toolbar.WooPosToolbarUIEvent.OnToolbarMenuClicked +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class WooPosToolbarViewModel @Inject constructor( + private val cardReaderFacade: WooPosCardReaderFacade, + private val childrenToParentEventSender: WooPosChildrenToParentEventSender, +) : ViewModel() { + private val _state = MutableStateFlow( + WooPosToolbarState( + cardReaderStatus = WooPosToolbarState.WooPosCardReaderStatus.NotConnected, + menu = WooPosToolbarState.Menu.Hidden, + ) + ) + val state: StateFlow = _state + + init { + viewModelScope.launch { + cardReaderFacade.readerStatus.collect { + _state.value = _state.value.copy( + cardReaderStatus = mapCardReaderStatusToUiState(it) + ) + } + } + } + + fun onUiEvent(event: WooPosToolbarUIEvent) { + val currentState = _state.value + if (currentState.menu is WooPosToolbarState.Menu.Visible && event !is MenuItemClicked) { + hideMenu() + return + } + + when (event) { + is OnToolbarMenuClicked -> { + _state.value = currentState.copy( + menu = WooPosToolbarState.Menu.Visible(toolbarMenuItems) + ) + } + + ConnectToAReaderClicked -> handleConnectToReaderButtonClicked() + + is MenuItemClicked -> handleMenuItemClicked(event) + + is OnOutsideOfToolbarMenuClicked -> { + // Do nothing as the menu is hidden already, but we need to pass the event here anyway + } + } + } + + private fun handleMenuItemClicked(event: MenuItemClicked) { + hideMenu() + + when (event.menuItem.title) { + R.string.woopos_get_support_title -> TODO() + R.string.woopos_exit_confirmation_title -> + viewModelScope.launch { + childrenToParentEventSender.sendToParent(ChildToParentEvent.ExitPosClicked) + } + } + } + + private fun hideMenu() { + _state.value = _state.value.copy(menu = WooPosToolbarState.Menu.Hidden) + } + + private fun handleConnectToReaderButtonClicked() { + if (_state.value.cardReaderStatus != WooPosToolbarState.WooPosCardReaderStatus.Connected) { + cardReaderFacade.connectToReader() + } + } + + private fun mapCardReaderStatusToUiState(status: CardReaderStatus): WooPosToolbarState.WooPosCardReaderStatus { + return when (status) { + is Connected -> WooPosToolbarState.WooPosCardReaderStatus.Connected + is NotConnected, Connecting -> WooPosToolbarState.WooPosCardReaderStatus.NotConnected + } + } + + private companion object { + val toolbarMenuItems = listOf( + WooPosToolbarState.Menu.MenuItem( + title = R.string.woopos_get_support_title, + icon = R.drawable.woopos_ic_get_support, + ), + WooPosToolbarState.Menu.MenuItem( + title = R.string.woopos_exit_confirmation_title, + icon = R.drawable.woopos_ic_exit_pos, + ), + ) + } +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosRootScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosRootScreen.kt index 93b701da677..f046f0f78ca 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosRootScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosRootScreen.kt @@ -4,98 +4,34 @@ import androidx.activity.ComponentActivity import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.runtime.State -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp -import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.compose.rememberNavController import com.woocommerce.android.ui.woopos.common.composeui.WooPosPreview import com.woocommerce.android.ui.woopos.common.composeui.WooPosTheme -import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosConfirmationDialog -import com.woocommerce.android.ui.woopos.common.composeui.toAdaptivePadding -import com.woocommerce.android.ui.woopos.root.navigation.WooPosNavigationEvent import com.woocommerce.android.ui.woopos.root.navigation.WooPosRootHost import com.woocommerce.android.ui.woopos.root.navigation.handleNavigationEvent @Composable fun WooPosRootScreen(modifier: Modifier = Modifier) { - val viewModel: WooPosRootViewModel = hiltViewModel() - WooPosRootScreen( - modifier = modifier, - state = viewModel.rootScreenState.collectAsState(), - onUIEvent = viewModel::onUiEvent, - ) -} - -@Composable -private fun WooPosRootScreen( - modifier: Modifier = Modifier, - state: State, - onUIEvent: (WooPosRootUIEvent) -> Unit -) { val rootController = rememberNavController() val activity = LocalContext.current as ComponentActivity - state.value.exitConfirmationDialog?.let { - WooPosConfirmationDialog( - title = stringResource(id = it.title), - message = stringResource(id = it.message), - confirmButtonText = stringResource(id = it.confirmButton), - dismissButtonText = stringResource(id = it.dismissButton), - onDismiss = { onUIEvent(WooPosRootUIEvent.ExitConfirmationDialogDismissed) }, - onConfirm = { - rootController.handleNavigationEvent( - WooPosNavigationEvent.ExitPosClicked, - activity, - onUIEvent - ) - } - ) - } - Box(modifier = modifier.background(MaterialTheme.colors.background)) { WooPosRootHost( modifier = Modifier.fillMaxSize(), rootController = rootController, onNavigationEvent = { event -> - rootController.handleNavigationEvent(event, activity, onUIEvent) + rootController.handleNavigationEvent(event, activity) } ) - WooPosFloatingToolbar( - modifier = Modifier - .padding(24.dp.toAdaptivePadding()) - .align(Alignment.BottomStart), - state, - onUIEvent, - ) } } @WooPosPreview @Composable fun PreviewWooPosRootScreen() { - val state = remember { - mutableStateOf( - WooPosRootScreenState( - WooPosRootScreenState.WooPosCardReaderStatus.NotConnected, - menu = WooPosRootScreenState.Menu.Hidden, - null, - ) - ) - } - WooPosTheme { - WooPosRootScreen( - state = state, - onUIEvent = {} - ) - } + WooPosTheme { WooPosRootScreen() } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosRootUIEvent.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosRootUIEvent.kt deleted file mode 100644 index ab960fa09c6..00000000000 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosRootUIEvent.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.woocommerce.android.ui.woopos.root - -sealed class WooPosRootUIEvent { - data object OnToolbarMenuClicked : WooPosRootUIEvent() - data object OnOutsideOfToolbarMenuClicked : WooPosRootUIEvent() - data object ConnectToAReaderClicked : WooPosRootUIEvent() - data object ExitConfirmationDialogDismissed : WooPosRootUIEvent() - data object OnBackFromHomeClicked : WooPosRootUIEvent() - data class MenuItemClicked(val menuItem: WooPosRootScreenState.Menu.MenuItem) : WooPosRootUIEvent() -} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosRootViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosRootViewModel.kt deleted file mode 100644 index 2bb268bf217..00000000000 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/WooPosRootViewModel.kt +++ /dev/null @@ -1,119 +0,0 @@ -package com.woocommerce.android.ui.woopos.root - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.woocommerce.android.R -import com.woocommerce.android.cardreader.connection.CardReaderStatus -import com.woocommerce.android.cardreader.connection.CardReaderStatus.Connected -import com.woocommerce.android.cardreader.connection.CardReaderStatus.Connecting -import com.woocommerce.android.cardreader.connection.CardReaderStatus.NotConnected -import com.woocommerce.android.ui.woopos.cardreader.WooPosCardReaderFacade -import com.woocommerce.android.ui.woopos.root.WooPosRootScreenState.Menu.MenuItem -import com.woocommerce.android.ui.woopos.root.WooPosRootUIEvent.ConnectToAReaderClicked -import com.woocommerce.android.ui.woopos.root.WooPosRootUIEvent.ExitConfirmationDialogDismissed -import com.woocommerce.android.ui.woopos.root.WooPosRootUIEvent.MenuItemClicked -import com.woocommerce.android.ui.woopos.root.WooPosRootUIEvent.OnBackFromHomeClicked -import com.woocommerce.android.ui.woopos.root.WooPosRootUIEvent.OnToolbarMenuClicked -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.launch -import javax.inject.Inject - -@HiltViewModel -class WooPosRootViewModel @Inject constructor( - private val cardReaderFacade: WooPosCardReaderFacade, -) : ViewModel() { - private val _rootScreenState = MutableStateFlow( - WooPosRootScreenState( - cardReaderStatus = WooPosRootScreenState.WooPosCardReaderStatus.NotConnected, - menu = WooPosRootScreenState.Menu.Hidden, - exitConfirmationDialog = null, - ) - ) - val rootScreenState: StateFlow = _rootScreenState - - init { - viewModelScope.launch { - cardReaderFacade.readerStatus.collect { - _rootScreenState.value = _rootScreenState.value.copy( - cardReaderStatus = mapCardReaderStatusToUiState(it) - ) - } - } - } - - fun onUiEvent(event: WooPosRootUIEvent) { - val currentState = _rootScreenState.value - if (currentState.menu is WooPosRootScreenState.Menu.Visible && event !is MenuItemClicked) { - hideMenu() - return - } - - when (event) { - is OnToolbarMenuClicked -> { - _rootScreenState.value = currentState.copy( - menu = WooPosRootScreenState.Menu.Visible(toolbarMenuItems) - ) - } - - ConnectToAReaderClicked -> handleConnectToReaderButtonClicked() - - ExitConfirmationDialogDismissed -> _rootScreenState.value = currentState.copy( - exitConfirmationDialog = null - ) - - OnBackFromHomeClicked -> _rootScreenState.value = currentState.copy( - exitConfirmationDialog = WooPosRootScreenState.WooPosExitConfirmationDialog - ) - - is MenuItemClicked -> handleMenuItemClicked(event) - - is WooPosRootUIEvent.OnOutsideOfToolbarMenuClicked -> { - // Do nothing as the menu is hidden already, but we need to pass the event here anyway - } - } - } - - private fun handleMenuItemClicked(event: MenuItemClicked) { - hideMenu() - - when (event.menuItem.title) { - R.string.woopos_get_support_title -> TODO() - R.string.woopos_exit_confirmation_title -> - _rootScreenState.value = _rootScreenState.value.copy( - exitConfirmationDialog = WooPosRootScreenState.WooPosExitConfirmationDialog - ) - } - } - - private fun hideMenu() { - _rootScreenState.value = _rootScreenState.value.copy(menu = WooPosRootScreenState.Menu.Hidden) - } - - private fun handleConnectToReaderButtonClicked() { - if (_rootScreenState.value.cardReaderStatus != WooPosRootScreenState.WooPosCardReaderStatus.Connected) { - cardReaderFacade.connectToReader() - } - } - - private fun mapCardReaderStatusToUiState(status: CardReaderStatus): WooPosRootScreenState.WooPosCardReaderStatus { - return when (status) { - is Connected -> WooPosRootScreenState.WooPosCardReaderStatus.Connected - is NotConnected, Connecting -> WooPosRootScreenState.WooPosCardReaderStatus.NotConnected - } - } - - private companion object { - val toolbarMenuItems = listOf( - MenuItem( - title = R.string.woopos_get_support_title, - icon = R.drawable.woopos_ic_get_support, - ), - MenuItem( - title = R.string.woopos_exit_confirmation_title, - icon = R.drawable.woopos_ic_exit_pos, - ), - ) - } -} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/navigation/WooPosNavigationEvent.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/navigation/WooPosNavigationEvent.kt index 92986d30b3b..7c57b8c6838 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/navigation/WooPosNavigationEvent.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/navigation/WooPosNavigationEvent.kt @@ -2,7 +2,6 @@ package com.woocommerce.android.ui.woopos.root.navigation sealed class WooPosNavigationEvent { data object ExitPosClicked : WooPosNavigationEvent() - data object BackFromHomeClicked : WooPosNavigationEvent() data object BackFromSplashClicked : WooPosNavigationEvent() data object OpenHomeFromSplash : WooPosNavigationEvent() } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/navigation/WooPosNavigationEventHandler.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/navigation/WooPosNavigationEventHandler.kt index 4981841ba55..867b71b97f9 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/navigation/WooPosNavigationEventHandler.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/root/navigation/WooPosNavigationEventHandler.kt @@ -3,19 +3,15 @@ package com.woocommerce.android.ui.woopos.root.navigation import androidx.activity.ComponentActivity import androidx.navigation.NavHostController import com.woocommerce.android.ui.woopos.home.navigateToHomeScreen -import com.woocommerce.android.ui.woopos.root.WooPosRootUIEvent -import com.woocommerce.android.ui.woopos.root.WooPosRootUIEvent.OnBackFromHomeClicked fun NavHostController.handleNavigationEvent( event: WooPosNavigationEvent, activity: ComponentActivity, - onUIEvent: (WooPosRootUIEvent) -> Unit, ) { when (event) { is WooPosNavigationEvent.ExitPosClicked, is WooPosNavigationEvent.BackFromSplashClicked -> activity.finish() - is WooPosNavigationEvent.BackFromHomeClicked -> onUIEvent(OnBackFromHomeClicked) is WooPosNavigationEvent.OpenHomeFromSplash -> navigateToHomeScreen() } } diff --git a/WooCommerce/src/main/res/values/strings.xml b/WooCommerce/src/main/res/values/strings.xml index fb012015c1e..c4e86a6344f 100644 --- a/WooCommerce/src/main/res/values/strings.xml +++ b/WooCommerce/src/main/res/values/strings.xml @@ -4171,7 +4171,7 @@ --> Exit POS Reader Connected - Reader Disconnected + Connect your reader Checkout Reader Status Unknown Check out diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModelTest.kt index 8947641b0f0..afad87ff8f3 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/WooPosHomeViewModelTest.kt @@ -1,24 +1,19 @@ package com.woocommerce.android.ui.woopos.home -import com.woocommerce.android.ui.woopos.home.WooPosHomeUIEvent.SystemBackClicked import com.woocommerce.android.ui.woopos.util.WooPosCoroutineTestRule import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.runTest +import org.assertj.core.api.Assertions.assertThat import org.junit.Rule -import org.junit.runner.RunWith -import org.mockito.junit.MockitoJUnitRunner import org.mockito.kotlin.mock import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import kotlin.test.Test -import kotlin.test.assertFalse @ExperimentalCoroutinesApi -@RunWith(MockitoJUnitRunner::class) class WooPosHomeViewModelTest { - @Rule @JvmField val coroutinesTestRule = WooPosCoroutineTestRule() @@ -36,24 +31,26 @@ class WooPosHomeViewModelTest { val viewModel = createViewModel() // WHEN - viewModel.onUIEvent(SystemBackClicked) + viewModel.onUIEvent(WooPosHomeUIEvent.SystemBackClicked) // THEN verify(parentToChildrenEventSender).sendToChildren(ParentToChildrenEvent.BackFromCheckoutToCartClicked) + assertThat(viewModel.state.value.screenPositionState) + .isEqualTo(WooPosHomeState.ScreenPositionState.Cart.NotEmpty) } @Test - fun `given state is Cart, when SystemBackClicked passed, then should propagate the event down`() = runTest { + fun `given state is Cart, when SystemBackClicked passed, then should show exit confirmation dialog`() = runTest { // GIVEN val eventsFlow = MutableSharedFlow() whenever(childrenToParentEventReceiver.events).thenReturn(eventsFlow) val viewModel = createViewModel() // WHEN - val result = viewModel.onUIEvent(SystemBackClicked) + viewModel.onUIEvent(WooPosHomeUIEvent.SystemBackClicked) // THEN - assertFalse(result) + assertThat(viewModel.state.value.exitConfirmationDialog).isEqualTo(WooPosExitConfirmationDialog) } @Test @@ -65,10 +62,58 @@ class WooPosHomeViewModelTest { val viewModel = createViewModel() // WHEN - viewModel.onUIEvent(SystemBackClicked) + viewModel.onUIEvent(WooPosHomeUIEvent.SystemBackClicked) // THEN verify(parentToChildrenEventSender).sendToChildren(ParentToChildrenEvent.OrderSuccessfullyPaid) + assertThat(viewModel.state.value.screenPositionState) + .isEqualTo(WooPosHomeState.ScreenPositionState.Cart.Empty) + } + + @Test + fun `given state is Checkout NotPaid, when ExitConfirmationDialogDismissed passed, then exit confirmation dialog should be dismissed`() = runTest { + // GIVEN + whenever(childrenToParentEventReceiver.events).thenReturn( + flowOf(ChildToParentEvent.CheckoutClicked(emptyList())) + ) + val viewModel = createViewModel() + + // WHEN + viewModel.onUIEvent(WooPosHomeUIEvent.ExitConfirmationDialogDismissed) + + // THEN + assertThat(viewModel.state.value.exitConfirmationDialog).isNull() + } + + @Test + fun `given state is Cart Empty, when ExitPosClicked passed, then exit confirmation dialog should be shown`() = runTest { + // GIVEN + val eventsFlow = MutableSharedFlow() + whenever(childrenToParentEventReceiver.events).thenReturn(eventsFlow) + val viewModel = createViewModel() + + // WHEN + eventsFlow.emit(ChildToParentEvent.ExitPosClicked) + + // THEN + assertThat(viewModel.state.value.exitConfirmationDialog) + .isEqualTo(WooPosExitConfirmationDialog) + } + + @Test + fun `given state is Cart NotEmpty, when ExitPosClicked passed, then exit confirmation dialog should be shown`() = runTest { + // GIVEN + val eventsFlow = MutableSharedFlow() + whenever(childrenToParentEventReceiver.events).thenReturn(eventsFlow) + val viewModel = createViewModel() + + // WHEN + eventsFlow.emit(ChildToParentEvent.CartStatusChanged.NotEmpty) + eventsFlow.emit(ChildToParentEvent.ExitPosClicked) + + // THEN + assertThat(viewModel.state.value.exitConfirmationDialog) + .isEqualTo(WooPosExitConfirmationDialog) } private fun createViewModel() = WooPosHomeViewModel( diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/cart/WooPosCartViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/cart/WooPosCartViewModelTest.kt index c788d7bb759..a04323fb393 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/cart/WooPosCartViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/cart/WooPosCartViewModelTest.kt @@ -17,8 +17,6 @@ import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.test.runTest import org.assertj.core.api.Assertions.assertThat import org.junit.Rule -import org.junit.runner.RunWith -import org.mockito.junit.MockitoJUnitRunner import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.whenever @@ -26,9 +24,7 @@ import java.math.BigDecimal import kotlin.test.Test @ExperimentalCoroutinesApi -@RunWith(MockitoJUnitRunner::class) class WooPosCartViewModelTest { - @Rule @JvmField val rule = InstantTaskExecutorRule() diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModelTest.kt index 35699339bd9..3d20d903534 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/products/WooPosProductsViewModelTest.kt @@ -10,8 +10,6 @@ import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.runTest import org.assertj.core.api.Assertions.assertThat import org.junit.Rule -import org.junit.runner.RunWith -import org.mockito.junit.MockitoJUnitRunner import org.mockito.kotlin.any import org.mockito.kotlin.eq import org.mockito.kotlin.mock @@ -21,7 +19,6 @@ import java.math.BigDecimal import kotlin.test.Test @ExperimentalCoroutinesApi -@RunWith(MockitoJUnitRunner::class) class WooPosProductsViewModelTest { @Rule diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarViewModelTest.kt new file mode 100644 index 00000000000..3c3fbc7cc2f --- /dev/null +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/toolbar/WooPosToolbarViewModelTest.kt @@ -0,0 +1,136 @@ +package com.woocommerce.android.ui.woopos.home.toolbar + +import com.woocommerce.android.R +import com.woocommerce.android.cardreader.connection.CardReaderStatus +import com.woocommerce.android.ui.woopos.cardreader.WooPosCardReaderFacade +import com.woocommerce.android.ui.woopos.home.ChildToParentEvent +import com.woocommerce.android.ui.woopos.home.WooPosChildrenToParentEventSender +import com.woocommerce.android.ui.woopos.util.WooPosCoroutineTestRule +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.runTest +import org.assertj.core.api.Assertions.assertThat +import org.junit.Rule +import org.junit.Test +import org.mockito.kotlin.mock +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +@ExperimentalCoroutinesApi +class WooPosToolbarViewModelTest { + @Rule + @JvmField + val coroutinesTestRule = WooPosCoroutineTestRule() + private val cardReaderFacade: WooPosCardReaderFacade = mock { + onBlocking { readerStatus }.thenReturn(flowOf(CardReaderStatus.NotConnected())) + } + private val childrenToParentEventSender: WooPosChildrenToParentEventSender = mock() + + @Test + fun `given card reader status is NotConnected, when initialized, then state should be NotConnected`() = runTest { + // GIVEN + whenever(cardReaderFacade.readerStatus).thenReturn(flowOf(CardReaderStatus.NotConnected())) + val viewModel = createViewModel() + + // THEN + assertThat(viewModel.state.value.cardReaderStatus) + .isEqualTo(WooPosToolbarState.WooPosCardReaderStatus.NotConnected) + } + + @Test + fun `given card reader status is Connected, when initialized, then state should be Connected`() = runTest { + // GIVEN + whenever(cardReaderFacade.readerStatus).thenReturn(flowOf(CardReaderStatus.Connected(mock()))) + val viewModel = createViewModel() + + // THEN + assertThat(viewModel.state.value.cardReaderStatus) + .isEqualTo(WooPosToolbarState.WooPosCardReaderStatus.Connected) + } + + @Test + fun `given card reader status is Connecting, when initialized, then state should be NotConnected`() = runTest { + // GIVEN + whenever(cardReaderFacade.readerStatus).thenReturn(flowOf(CardReaderStatus.Connecting)) + val viewModel = createViewModel() + + // THEN + assertThat(viewModel.state.value.cardReaderStatus) + .isEqualTo(WooPosToolbarState.WooPosCardReaderStatus.NotConnected) + } + + @Test + fun `when OnToolbarMenuClicked passed, then menu should be visible`() = runTest { + // GIVEN + val viewModel = createViewModel() + + // WHEN + viewModel.onUiEvent(WooPosToolbarUIEvent.OnToolbarMenuClicked) + + // THEN + assertThat(viewModel.state.value.menu) + .isEqualTo( + WooPosToolbarState.Menu.Visible( + listOf( + WooPosToolbarState.Menu.MenuItem( + title = R.string.woopos_get_support_title, + icon = R.drawable.woopos_ic_get_support, + ), + WooPosToolbarState.Menu.MenuItem( + title = R.string.woopos_exit_confirmation_title, + icon = R.drawable.woopos_ic_exit_pos, + ), + ) + ) + ) + } + + @Test + fun `when OnOutsideOfToolbarMenuClicked passed and menu is visible, then menu should be hidden`() = runTest { + // GIVEN + val viewModel = createViewModel() + viewModel.onUiEvent(WooPosToolbarUIEvent.OnToolbarMenuClicked) + + // WHEN + viewModel.onUiEvent(WooPosToolbarUIEvent.OnOutsideOfToolbarMenuClicked) + + // THEN + assertThat(viewModel.state.value.menu) + .isEqualTo(WooPosToolbarState.Menu.Hidden) + } + + @Test + fun `when ConnectToAReaderClicked passed, then connect to reader should be called`() = runTest { + // GIVEN + whenever(cardReaderFacade.readerStatus).thenReturn(flowOf(CardReaderStatus.NotConnected())) + val viewModel = createViewModel() + + // WHEN + viewModel.onUiEvent(WooPosToolbarUIEvent.ConnectToAReaderClicked) + + // THEN + verify(cardReaderFacade).connectToReader() + } + + @Test + fun `when MenuItemClicked with ExitPosClicked, then ExitPosClicked event should be sent`() = runTest { + // GIVEN + val viewModel = createViewModel() + val menuItem = WooPosToolbarState.Menu.MenuItem( + title = R.string.woopos_exit_confirmation_title, + icon = R.drawable.woopos_ic_exit_pos + ) + + // WHEN + viewModel.onUiEvent(WooPosToolbarUIEvent.MenuItemClicked(menuItem)) + + // THEN + verify(childrenToParentEventSender).sendToParent(ChildToParentEvent.ExitPosClicked) + assertThat(viewModel.state.value.menu).isEqualTo(WooPosToolbarState.Menu.Hidden) + } + + private fun createViewModel() = WooPosToolbarViewModel( + cardReaderFacade, + childrenToParentEventSender + ) +} diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModelTest.kt index 4e49d529d78..3ca80dd620f 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/home/totals/WooPosTotalsViewModelTest.kt @@ -15,8 +15,6 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.runTest import org.assertj.core.api.Assertions.assertThat import org.junit.Rule -import org.junit.runner.RunWith -import org.mockito.junit.MockitoJUnitRunner import org.mockito.kotlin.mock import org.mockito.kotlin.verify import java.math.BigDecimal @@ -24,7 +22,6 @@ import java.util.Date import kotlin.test.Test @ExperimentalCoroutinesApi -@RunWith(MockitoJUnitRunner.Silent::class) class WooPosTotalsViewModelTest { @Rule diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/root/WooPosRootViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/root/WooPosRootViewModelTest.kt deleted file mode 100644 index 422797a30b8..00000000000 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/woopos/root/WooPosRootViewModelTest.kt +++ /dev/null @@ -1,257 +0,0 @@ -package com.woocommerce.android.ui.woopos.root - -import com.woocommerce.android.R -import com.woocommerce.android.cardreader.connection.CardReader -import com.woocommerce.android.cardreader.connection.CardReaderStatus.Connected -import com.woocommerce.android.cardreader.connection.CardReaderStatus.NotConnected -import com.woocommerce.android.ui.woopos.cardreader.WooPosCardReaderFacade -import com.woocommerce.android.ui.woopos.root.WooPosRootScreenState.Menu.MenuItem -import com.woocommerce.android.ui.woopos.root.WooPosRootScreenState.WooPosCardReaderStatus -import com.woocommerce.android.ui.woopos.util.WooPosCoroutineTestRule -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.drop -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.launch -import kotlinx.coroutines.test.runTest -import org.assertj.core.api.Assertions.assertThat -import org.junit.Rule -import org.mockito.kotlin.mock -import org.mockito.kotlin.never -import org.mockito.kotlin.verify -import org.mockito.kotlin.whenever -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertNotEquals - -@ExperimentalCoroutinesApi -class WooPosRootViewModelTest { - private val cardReaderFacade: WooPosCardReaderFacade = mock { - onBlocking { readerStatus }.thenReturn(flowOf(NotConnected())) - } - - @Rule - @JvmField - val coroutinesTestRule = WooPosCoroutineTestRule() - - @Test - fun `given reader disconnected, when status button clicked, then should connect`() = runTest { - whenever(cardReaderFacade.readerStatus).thenReturn(flowOf(NotConnected())) - val sut = createSut() - assertNotEquals(WooPosCardReaderStatus.Connected, sut.rootScreenState.value.cardReaderStatus) - - sut.onUiEvent(WooPosRootUIEvent.ConnectToAReaderClicked) - - verify(cardReaderFacade).connectToReader() - } - - @Test - fun `given reader connected, when status button clicked, then should not connect`() = runTest { - whenever(cardReaderFacade.readerStatus).thenReturn(flowOf(NotConnected())) - val cardReader: CardReader = mock() - whenever(cardReaderFacade.readerStatus).thenReturn(flow { emit(Connected(cardReader)) }) - val sut = createSut() - val job = launch { - sut.rootScreenState.drop(1).collect { - assertEquals(WooPosCardReaderStatus.Connected, it.cardReaderStatus) - } - } - - sut.onUiEvent(WooPosRootUIEvent.ConnectToAReaderClicked) - - verify(cardReaderFacade, never()).connectToReader() - job.cancel() - } - - @Test - fun `when exit confirmation dialog dismissed, then dialog should be null`() = runTest { - // GIVEN - whenever(cardReaderFacade.readerStatus).thenReturn(flowOf(NotConnected())) - val sut = createSut() - sut.onUiEvent(WooPosRootUIEvent.ExitConfirmationDialogDismissed) - - // THEN - assertThat(sut.rootScreenState.value.exitConfirmationDialog).isNull() - } - - @Test - fun `when exit confirmation dialog clicked, then dialog should be shown`() = runTest { - // GIVEN - whenever(cardReaderFacade.readerStatus).thenReturn(flowOf(NotConnected())) - val sut = createSut() - - // WHEN - sut.onUiEvent(WooPosRootUIEvent.OnBackFromHomeClicked) - - // THEN - assertThat(sut.rootScreenState.value.exitConfirmationDialog).isEqualTo( - WooPosRootScreenState.WooPosExitConfirmationDialog - ) - assertThat(sut.rootScreenState.value.exitConfirmationDialog?.confirmButton).isEqualTo( - R.string.woopos_exit_confirmation_confirm_button - ) - assertThat(sut.rootScreenState.value.exitConfirmationDialog?.dismissButton).isEqualTo( - R.string.woopos_exit_confirmation_dismiss_button - ) - assertThat(sut.rootScreenState.value.exitConfirmationDialog?.message).isEqualTo( - R.string.woopos_exit_confirmation_message - ) - assertThat(sut.rootScreenState.value.exitConfirmationDialog?.title).isEqualTo( - R.string.woopos_exit_confirmation_title - ) - } - - @Test - fun `given OnBackFromHomeClicked, should update exit confirmation dialog`() { - // GIVEN - whenever(cardReaderFacade.readerStatus).thenReturn(flowOf(NotConnected())) - val sut = createSut() - - // WHEN - sut.onUiEvent(WooPosRootUIEvent.OnBackFromHomeClicked) - - // THEN - assertThat(sut.rootScreenState.value.exitConfirmationDialog).isEqualTo( - WooPosRootScreenState.WooPosExitConfirmationDialog - ) - } - - @Test - fun `given reader status as not connected, should update state with not connected status`() = runTest { - // GIVEN - whenever(cardReaderFacade.readerStatus).thenReturn(flowOf(NotConnected())) - val notConnectedStatus = NotConnected() - - whenever(cardReaderFacade.readerStatus).thenReturn(flowOf(notConnectedStatus)) - - val sut = createSut() - val job = launch { - sut.rootScreenState.drop(1).collect { - val state = it.cardReaderStatus as WooPosCardReaderStatus.NotConnected - assertThat(state.title).isEqualTo(R.string.woopos_reader_disconnected) - } - } - - job.cancel() - } - - @Test - fun `given reader status as connected, should update state with connected status`() = runTest { - // GIVEN - val cardReader: CardReader = mock() - val connectedStatus = Connected(cardReader) - - whenever(cardReaderFacade.readerStatus).thenReturn(flowOf(connectedStatus)) - - val sut = createSut() - val job = launch { - sut.rootScreenState.drop(1).collect { - assertEquals(WooPosCardReaderStatus.Connected, it.cardReaderStatus) - } - } - - job.cancel() - } - - @Test - fun `when toolbar menu clicked, should show menu`() = runTest { - // GIVEN - val sut = createSut() - - // WHEN - sut.onUiEvent(WooPosRootUIEvent.OnToolbarMenuClicked) - - // THEN - assertThat(sut.rootScreenState.value.menu).isEqualTo( - WooPosRootScreenState.Menu.Visible( - listOf( - MenuItem( - title = R.string.woopos_get_support_title, - icon = R.drawable.woopos_ic_get_support, - ), - MenuItem( - title = R.string.woopos_exit_confirmation_title, - icon = R.drawable.woopos_ic_exit_pos, - ), - ) - ) - ) - } - - @Test - fun `when menu item clicked, should handle accordingly`() = runTest { - // GIVEN - val sut = createSut() - - // WHEN - val menuItem = MenuItem( - title = R.string.woopos_exit_confirmation_title, - icon = R.drawable.woopos_ic_exit_pos - ) - sut.onUiEvent(WooPosRootUIEvent.MenuItemClicked(menuItem)) - - // THEN - assertThat(sut.rootScreenState.value.exitConfirmationDialog).isEqualTo( - WooPosRootScreenState.WooPosExitConfirmationDialog - ) - assertThat(sut.rootScreenState.value.menu).isEqualTo(WooPosRootScreenState.Menu.Hidden) - } - - @Test - fun `when OnOutsideOfToolbarMenuClicked, should hide menu if visible`() = runTest { - // GIVEN - val sut = createSut() - sut.onUiEvent(WooPosRootUIEvent.OnToolbarMenuClicked) - assertThat(sut.rootScreenState.value.menu).isEqualTo( - WooPosRootScreenState.Menu.Visible( - listOf( - MenuItem( - title = R.string.woopos_get_support_title, - icon = R.drawable.woopos_ic_get_support, - ), - MenuItem( - title = R.string.woopos_exit_confirmation_title, - icon = R.drawable.woopos_ic_exit_pos, - ), - ) - ) - ) - - // WHEN - sut.onUiEvent(WooPosRootUIEvent.OnOutsideOfToolbarMenuClicked) - - // THEN - assertThat(sut.rootScreenState.value.menu).isEqualTo(WooPosRootScreenState.Menu.Hidden) - } - - @Test - fun `when OnOutsideOfToolbarMenuClicked, should do nothing if menu already hidden`() = runTest { - // GIVEN - val sut = createSut() - assertThat(sut.rootScreenState.value.menu).isEqualTo(WooPosRootScreenState.Menu.Hidden) - - // WHEN - sut.onUiEvent(WooPosRootUIEvent.OnOutsideOfToolbarMenuClicked) - - // THEN - assertThat(sut.rootScreenState.value.menu).isEqualTo(WooPosRootScreenState.Menu.Hidden) - } - - @Test - fun `when ExitConfirmationDialogDismissed, should set exitConfirmationDialog to null`() = runTest { - // GIVEN - val sut = createSut() - sut.onUiEvent(WooPosRootUIEvent.OnBackFromHomeClicked) - assertThat(sut.rootScreenState.value.exitConfirmationDialog).isEqualTo( - WooPosRootScreenState.WooPosExitConfirmationDialog - ) - - // WHEN - sut.onUiEvent(WooPosRootUIEvent.ExitConfirmationDialogDismissed) - - // THEN - assertThat(sut.rootScreenState.value.exitConfirmationDialog).isNull() - } - - private fun createSut() = WooPosRootViewModel(cardReaderFacade) -}