Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package com.woocommerce.android.ui.woopos.home.items

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.scaleIn
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.woocommerce.android.R
import com.woocommerce.android.ui.woopos.common.composeui.WooPosPreview
import com.woocommerce.android.ui.woopos.common.composeui.component.ShadowType
import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosCard
import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosText
import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosCornerRadius
import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosElevation
import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosSpacing
import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTheme
import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTypography

@Composable
fun WooPosCatalogSyncOverdueBanner(
state: WooPosItemsViewModel.CatalogSyncOverdueBannerState,
modifier: Modifier = Modifier,
onDismiss: () -> Unit
) {
AnimatedVisibility(
visible = state is WooPosItemsViewModel.CatalogSyncOverdueBannerState.Visible,
enter = fadeIn(
animationSpec = tween(durationMillis = 180)
) + scaleIn(
animationSpec = tween(durationMillis = 180)
),
modifier = modifier.padding(horizontal = WooPosSpacing.Small.value)
) {
WooPosCard(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(WooPosCornerRadius.Medium.value),
backgroundColor = MaterialTheme.colorScheme.surfaceContainerLow,
elevation = WooPosElevation.Medium,
shadowType = ShadowType.Soft,
) {
Row(
horizontalArrangement = Arrangement.spacedBy(WooPosSpacing.Medium.value),
modifier = Modifier
.fillMaxWidth()
.padding(WooPosSpacing.Medium.value),
) {
Icon(
painter = painterResource(id = R.drawable.ic_woo_pos_info_banner),
tint = MaterialTheme.colorScheme.onSurface,
contentDescription = null,
modifier = Modifier
.size(48.dp)
.align(Alignment.CenterVertically)
)
Column(
verticalArrangement = Arrangement.spacedBy(WooPosSpacing.Small.value),
horizontalAlignment = Alignment.Start,
modifier = Modifier.weight(1f)
) {
WooPosText(
text = stringResource(R.string.woopos_refresh_catalog_banner_title),
style = WooPosTypography.BodyLarge,
color = MaterialTheme.colorScheme.onSurface,
)
WooPosText(
text = stringResource(R.string.woopos_refresh_catalog_banner_message),
style = WooPosTypography.BodySmall,
color = MaterialTheme.colorScheme.onSurface,
)
}
IconButton(
onClick = onDismiss,
modifier = Modifier.size(32.dp)
) {
Icon(
imageVector = Icons.Filled.Close,
contentDescription = stringResource(R.string.woopos_refresh_catalog_banner_dismiss),
tint = MaterialTheme.colorScheme.onSurface,
modifier = Modifier.size(24.dp)
)
}
}
}
}
}

@Composable
@WooPosPreview
fun WooPosRefreshCatalogBannerPreview() {
WooPosTheme {
WooPosCatalogSyncOverdueBanner(
state = WooPosItemsViewModel.CatalogSyncOverdueBannerState.Visible,
onDismiss = {}
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.lazy.LazyListState
Expand Down Expand Up @@ -45,6 +47,7 @@ fun WooPosItemsScreen(modifier: Modifier = Modifier) {
WooPosItemsScreen(
modifier = modifier,
itemsStateFlow = productsViewModel.viewState,
catalogSyncOverdueBannerStateFlow = productsViewModel.catalogSyncOverdueBannerState,
productsViewState = productsViewState,
couponsListState = couponsListState,
onUIEvent = { productsViewModel.onUIEvent(it) },
Expand All @@ -56,15 +59,18 @@ fun WooPosItemsScreen(modifier: Modifier = Modifier) {
private fun WooPosItemsScreen(
modifier: Modifier = Modifier,
itemsStateFlow: StateFlow<WooPosItemsToolbarViewState>,
catalogSyncOverdueBannerStateFlow: StateFlow<WooPosItemsViewModel.CatalogSyncOverdueBannerState>,
productsViewState: LazyListState,
couponsListState: LazyListState,
onUIEvent: (WooPosItemsUIEvent) -> Unit,
) {
val state = itemsStateFlow.collectAsState()
val catalogSyncOverdueBannerState = catalogSyncOverdueBannerStateFlow.collectAsState()

MainItemsList(
modifier = modifier,
state = state,
bannerState = catalogSyncOverdueBannerState,
productsViewState = productsViewState,
couponsListState = couponsListState,
onSearchEvent = {
Expand All @@ -86,6 +92,7 @@ private fun WooPosItemsScreen(
},
onTabClicked = { onUIEvent(WooPosItemsUIEvent.OnTabClicked(it)) },
onBackClicked = { onUIEvent(WooPosItemsUIEvent.BackFromVariationsClicked) },
onSyncWarningBannerDismissed = { onUIEvent(WooPosItemsUIEvent.SyncOverdueBannerDismissed) },
)
}

Expand All @@ -94,20 +101,17 @@ private fun WooPosItemsScreen(
private fun MainItemsList(
modifier: Modifier,
state: State<WooPosItemsToolbarViewState>,
bannerState: State<WooPosItemsViewModel.CatalogSyncOverdueBannerState>,
productsViewState: LazyListState,
couponsListState: LazyListState,
onSearchEvent: (WooPosSearchUIEvent) -> Unit,
onTabClicked: (WooPosItemsToolbarViewState.Tab) -> Unit,
onAddCouponEvent: () -> Unit,
onBackClicked: () -> Unit,
onSyncWarningBannerDismissed: () -> Unit,
) {
Box(
modifier = modifier
.fillMaxSize()
) {
Column(
modifier.fillMaxHeight()
) {
Box(modifier = modifier.fillMaxSize()) {
Column(modifier.fillMaxHeight()) {
WooPosItemsToolbar(
modifier = Modifier
.statusBarsPadding()
Expand All @@ -121,6 +125,20 @@ private fun MainItemsList(
onAddCouponEvent = onAddCouponEvent,
)

Spacer(
modifier =
Modifier
.height(WooPosSpacing.Small.value)
.padding(horizontal = WooPosSpacing.Medium.value.toAdaptivePadding())
)

WooPosCatalogSyncOverdueBanner(
state = bannerState.value,
onDismiss = onSyncWarningBannerDismissed
)

Spacer(modifier = Modifier.height(WooPosSpacing.Small.value))

val currentState = state.value

Crossfade(
Expand Down Expand Up @@ -216,10 +234,12 @@ fun WooPosItemsScreenSearchVisiblePreview(modifier: Modifier = Modifier) {
tabs = tabs()
)
)
val bannerState = MutableStateFlow(WooPosItemsViewModel.CatalogSyncOverdueBannerState.Visible)
WooPosTheme {
WooPosItemsScreen(
modifier = modifier,
itemsStateFlow = productState,
catalogSyncOverdueBannerStateFlow = bannerState,
productsViewState = rememberLazyListState(),
couponsListState = rememberLazyListState(),
onUIEvent = {},
Expand All @@ -242,10 +262,12 @@ fun WooPosItemsScreenSearchHiddenPreview(modifier: Modifier = Modifier) {
tabs = tabs()
)
)
val bannerState = MutableStateFlow(WooPosItemsViewModel.CatalogSyncOverdueBannerState.Visible)
WooPosTheme {
WooPosItemsScreen(
modifier = modifier,
itemsStateFlow = productState,
catalogSyncOverdueBannerStateFlow = bannerState,
productsViewState = rememberLazyListState(),
couponsListState = rememberLazyListState(),
onUIEvent = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ sealed class WooPosItemsUIEvent {
data object CloseSearchClicked : WooPosItemsUIEvent()
data object SearchIconClicked : WooPosItemsUIEvent()
data object AddCouponIconClicked : WooPosItemsUIEvent()
data object SyncOverdueBannerDismissed : WooPosItemsUIEvent()
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import com.woocommerce.android.ui.woopos.home.items.WooPosItemsToolbarViewState.
import com.woocommerce.android.ui.woopos.home.items.WooPosItemsToolbarViewState.Tab
import com.woocommerce.android.ui.woopos.home.items.coupons.creation.WooPosCouponCreationFacade
import com.woocommerce.android.ui.woopos.home.items.variations.WooPosVariationsNavigationData
import com.woocommerce.android.ui.woopos.localcatalog.WooPosFullSyncRequirement
import com.woocommerce.android.ui.woopos.localcatalog.WooPosFullSyncStatusChecker
import com.woocommerce.android.ui.woopos.util.analytics.WooPosAnalyticsEvent
import com.woocommerce.android.ui.woopos.util.analytics.WooPosAnalyticsEvent.Event.SearchButtonTapped
import com.woocommerce.android.ui.woopos.util.analytics.WooPosAnalyticsEventConstant
Expand All @@ -35,6 +37,7 @@ class WooPosItemsViewModel @Inject constructor(
private val parentToChildrenEventReceiver: WooPosParentToChildrenEventReceiver,
private val preferencesRepository: WooPosPreferencesRepository,
private val analyticsTracker: WooPosAnalyticsTracker,
private val syncStatusChecker: WooPosFullSyncStatusChecker,
) : ViewModel() {
private var preservedStateBeforeOpeningVariations: WooPosItemsToolbarViewState? = null
private val _viewState = MutableStateFlow<WooPosItemsToolbarViewState>(initialState())
Expand All @@ -45,6 +48,10 @@ class WooPosItemsViewModel @Inject constructor(
initialValue = _viewState.value,
)

private val _catalogSyncOverdueBannerState =
MutableStateFlow<CatalogSyncOverdueBannerState>(CatalogSyncOverdueBannerState.Hidden)
val catalogSyncOverdueBannerState: StateFlow<CatalogSyncOverdueBannerState> = _catalogSyncOverdueBannerState

init {
listenUpEvents()
searchHelper.initialize(
Expand All @@ -55,6 +62,18 @@ class WooPosItemsViewModel @Inject constructor(
viewModelScope.launch {
preferencesRepository.setWasOpenedOnce(true)
}

checkSyncStatusAndUpdateBanner()
}

private fun checkSyncStatusAndUpdateBanner() {
viewModelScope.launch {
val requirement = syncStatusChecker.checkSyncRequirement()
_catalogSyncOverdueBannerState.value = when (requirement) {
is WooPosFullSyncRequirement.Overdue -> CatalogSyncOverdueBannerState.Visible
else -> CatalogSyncOverdueBannerState.Hidden
}
}
}

fun onUIEvent(event: WooPosItemsUIEvent) {
Expand All @@ -77,6 +96,9 @@ class WooPosItemsViewModel @Inject constructor(
}

is WooPosItemsUIEvent.AddCouponIconClicked -> createAndAddCoupon()
WooPosItemsUIEvent.SyncOverdueBannerDismissed -> {
_catalogSyncOverdueBannerState.value = CatalogSyncOverdueBannerState.Hidden
}
}
}

Expand Down Expand Up @@ -241,4 +263,9 @@ class WooPosItemsViewModel @Inject constructor(
@Parcelize
data class Coupon(override val id: Long, val couponCode: String) : ItemClickedData(id), Parcelable
}

sealed class CatalogSyncOverdueBannerState {
data object Hidden : CatalogSyncOverdueBannerState()
data object Visible : CatalogSyncOverdueBannerState()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.woocommerce.android.ui.woopos.home.items.coupons

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.ExperimentalMaterialApi
Expand All @@ -22,7 +21,6 @@ import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosErrorS
import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosErrorScreenButtonState
import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosPaginationErrorIndicator
import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosIcons
import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosSpacing
import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTheme
import com.woocommerce.android.ui.woopos.home.items.WooPosCouponsViewState
import com.woocommerce.android.ui.woopos.home.items.WooPosItemList
Expand Down Expand Up @@ -74,7 +72,6 @@ private fun WooPosCouponsScreen(
when (val itemsState = state.value) {
is WooPosCouponsViewState.Content -> {
WooPosItemList(
modifier = Modifier.padding(top = WooPosSpacing.Large.value),
state = itemsState,
listState = listState,
onItemClicked = { item -> onUIEvent(WooPosCouponsUIEvent.CouponClicked(item.id, item.name)) },
Expand All @@ -88,9 +85,7 @@ private fun WooPosCouponsScreen(
}
}

is WooPosCouponsViewState.Loading -> WooPosItemsLoadingIndicator(
modifier = Modifier.padding(top = WooPosSpacing.Large.value)
)
is WooPosCouponsViewState.Loading -> WooPosItemsLoadingIndicator()

is WooPosCouponsViewState.Empty -> WooPosEmptyScreen(
modifier = Modifier.fillMaxSize(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,6 @@ private fun Content(
onEndOfItemListReached: () -> Unit
) {
WooPosItemList(
modifier = Modifier.padding(top = WooPosSpacing.Large.value),
state = itemsState,
listState = listState,
onItemClicked = onItemClicked,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ private fun WooPosVariationsScreens(
when (val itemsState = itemState.value) {
is WooPosVariationsViewState.Content -> {
WooPosItemList(
modifier = Modifier.padding(top = WooPosSpacing.Large.value),
state = itemsState,
listState = listState,
onItemClicked = {
Expand All @@ -122,16 +121,12 @@ private fun WooPosVariationsScreens(
}

is WooPosVariationsViewState.Loading -> {
WooPosItemsLoadingIndicator(
modifier = Modifier.padding(top = WooPosSpacing.Large.value),
)
WooPosItemsLoadingIndicator()
}

is WooPosVariationsViewState.Error -> {
VariationsError(
modifier = Modifier
.width(640.dp)
.padding(top = WooPosSpacing.Large.value)
modifier = Modifier.width(640.dp)
) {
onRetryClicked()
}
Expand Down
9 changes: 9 additions & 0 deletions WooCommerce/src/main/res/drawable/ic_woo_pos_info_banner.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="48"
android:viewportHeight="48">
<path
android:pathData="M24.199,39.302C22.09,39.302 20.112,38.901 18.267,38.101C16.421,37.31 14.795,36.216 13.389,34.819C11.992,33.423 10.898,31.802 10.107,29.956C9.316,28.11 8.921,26.133 8.921,24.023C8.921,21.914 9.316,19.937 10.107,18.091C10.898,16.245 11.992,14.624 13.389,13.227C14.795,11.821 16.421,10.723 18.267,9.932C20.112,9.141 22.09,8.745 24.199,8.745C26.309,8.745 28.286,9.141 30.132,9.932C31.978,10.723 33.599,11.821 34.995,13.227C36.392,14.624 37.485,16.245 38.276,18.091C39.077,19.937 39.478,21.914 39.478,24.023C39.478,26.133 39.077,28.11 38.276,29.956C37.485,31.802 36.392,33.423 34.995,34.819C33.599,36.216 31.978,37.31 30.132,38.101C28.286,38.901 26.309,39.302 24.199,39.302ZM24.199,35.947C25.85,35.947 27.393,35.64 28.828,35.024C30.273,34.409 31.538,33.555 32.622,32.461C33.716,31.357 34.57,30.088 35.186,28.652C35.811,27.207 36.123,25.664 36.123,24.023C36.123,22.373 35.811,20.83 35.186,19.395C34.57,17.949 33.716,16.68 32.622,15.586C31.538,14.492 30.273,13.638 28.828,13.023C27.393,12.407 25.85,12.1 24.199,12.1C22.549,12.1 21.001,12.407 19.556,13.023C18.12,13.638 16.855,14.492 15.762,15.586C14.668,16.68 13.814,17.949 13.198,19.395C12.583,20.83 12.275,22.373 12.275,24.023C12.275,25.664 12.583,27.207 13.198,28.652C13.814,30.088 14.668,31.357 15.762,32.461C16.855,33.555 18.12,34.409 19.556,35.024C21.001,35.64 22.549,35.947 24.199,35.947ZM21.636,31.963C21.294,31.963 21.006,31.855 20.771,31.641C20.537,31.416 20.42,31.128 20.42,30.776C20.42,30.444 20.537,30.166 20.771,29.941C21.006,29.717 21.294,29.604 21.636,29.604H23.32V23.921H21.899C21.558,23.921 21.27,23.813 21.035,23.599C20.801,23.374 20.684,23.086 20.684,22.734C20.684,22.402 20.801,22.124 21.035,21.899C21.27,21.675 21.558,21.563 21.899,21.563H24.668C25.098,21.563 25.425,21.704 25.649,21.987C25.874,22.261 25.986,22.627 25.986,23.086V29.604H27.495C27.837,29.604 28.125,29.717 28.359,29.941C28.594,30.166 28.711,30.444 28.711,30.776C28.711,31.128 28.594,31.416 28.359,31.641C28.125,31.855 27.837,31.963 27.495,31.963H21.636ZM24.141,19.409C23.584,19.409 23.105,19.214 22.705,18.823C22.305,18.423 22.104,17.944 22.104,17.388C22.104,16.812 22.305,16.328 22.705,15.938C23.105,15.537 23.584,15.337 24.141,15.337C24.707,15.337 25.185,15.537 25.576,15.938C25.967,16.328 26.162,16.812 26.162,17.388C26.162,17.944 25.967,18.423 25.576,18.823C25.185,19.214 24.707,19.409 24.141,19.409Z"
android:fillColor="#101517"/>
</vector>
3 changes: 3 additions & 0 deletions WooCommerce/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3604,6 +3604,9 @@
<string name="woopos_home_sync_failed_title">Unable to sync</string>
<string name="woopos_home_sync_failed_message">We are unable to sync your product catalog. Please check your internet connection and retry.</string>
<string name="woopos_home_sync_failed_retry_button">Retry</string>
<string name="woopos_refresh_catalog_banner_title">Refresh catalog</string>
<string name="woopos_refresh_catalog_banner_message">The catalog hasn\'t been synced in the last 7 days. Either connect your device to WiFi or enable syncing over cellular network in POS settings.</string>
<string name="woopos_refresh_catalog_banner_dismiss">Dismiss banner</string>

<string name="woopos_reader_connected">Reader connected</string>
<string name="woopos_reader_disconnected">Connect your reader</string>
Expand Down
Loading