Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WooPos][Non Simple Product types] Retry UI for pagination errors on variations screens #12972

Open
wants to merge 41 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
bddcae5
Add state to indicate error while paginating
AnirudhBhat Nov 21, 2024
9873533
Handle error while paginating in WooPosItemsList.kt
AnirudhBhat Nov 21, 2024
42f4e1a
Handle error while paginating in WooPosItemsScreen.kt
AnirudhBhat Nov 21, 2024
0fe310a
Remove snack bar implementation from WooPosVariationsScreen
AnirudhBhat Nov 21, 2024
d84a3a8
Override errorloadingMoreItems property in variations view state
AnirudhBhat Nov 21, 2024
455d396
Navigate to items list screen on payment success so that clicking on …
AnirudhBhat Nov 21, 2024
30b6d5d
Add tests for different state updates while paginating
AnirudhBhat Nov 21, 2024
53a1838
Remove unnecessary padding from the variations screen
AnirudhBhat Nov 21, 2024
bab7cbe
Add test to verify we navigate to the items list screen on payment su…
AnirudhBhat Nov 21, 2024
8ceaa5f
Remove unused imports
AnirudhBhat Nov 21, 2024
e5f7823
Make changes to string resource to include variable products as well …
AnirudhBhat Nov 22, 2024
a45bd6c
Refactor pagination state logic. Use sealed interface instead of bool…
AnirudhBhat Nov 25, 2024
71ee602
Yse 32 instead of 30 dp.
AnirudhBhat Nov 25, 2024
84febe1
Use MutableStateFlow's atomic operation to update the view state
AnirudhBhat Nov 25, 2024
5b60693
fix detekt error
AnirudhBhat Nov 25, 2024
20d14bd
Add string resource for pagination error messages
AnirudhBhat Nov 26, 2024
9685cd2
Add pagination error component for items list
AnirudhBhat Nov 26, 2024
0bd442d
Integrate the pagination error component in items and variations screens
AnirudhBhat Nov 26, 2024
e40c789
Fix detekt errors
AnirudhBhat Nov 26, 2024
e94d0e5
Use adaptive padding
AnirudhBhat Nov 28, 2024
3ed43d3
Move the modifier parameter near WooPosErrorScreen
AnirudhBhat Nov 28, 2024
187dfcd
Update the state to pagination error on items view model
AnirudhBhat Nov 28, 2024
6fe46f2
Refactor loadMore method for readability
AnirudhBhat Nov 28, 2024
0f5cf15
Refactor variation flow collection logic
AnirudhBhat Nov 28, 2024
d4d0060
Merge branch 'issue/12846-analytics-for-variations' into issue/12967-…
AnirudhBhat Nov 28, 2024
81cb158
Fix failing test
AnirudhBhat Nov 28, 2024
d03d6a2
Merge branch 'trunk' into issue/12967-retry-pagination-error
AnirudhBhat Nov 28, 2024
28584e8
Fix failing test
AnirudhBhat Nov 28, 2024
aa38f10
Rename WooPosPaginationErrorScreen.kt to WooPosPaginationErrorIndicator
AnirudhBhat Nov 29, 2024
6a3b777
Make the method private
AnirudhBhat Nov 29, 2024
6bb0870
Add preview for pagination error state
AnirudhBhat Nov 29, 2024
19a7ed5
Refactor WooPosPaginationErrorIndicator and add content description f…
AnirudhBhat Nov 29, 2024
ebbf621
Rename ItemList to WooPosItemList
AnirudhBhat Nov 29, 2024
623125f
Use string resource in preview
AnirudhBhat Nov 29, 2024
a9780a3
Use sealed class instead of interface for pagination state
AnirudhBhat Nov 29, 2024
45a1d7e
Fix detekt errors
AnirudhBhat Nov 29, 2024
ba90251
Revert change
AnirudhBhat Nov 29, 2024
4a920cb
Default canLoadMore value to false
AnirudhBhat Nov 29, 2024
8c3af25
Remove minOf logic
AnirudhBhat Nov 29, 2024
1eb6c32
Add list for WooPosPagina' preview
AnirudhBhat Nov 29, 2024
ef53ce9
Add margin for items loading in variations screen
AnirudhBhat Nov 29, 2024
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,112 @@
package com.woocommerce.android.ui.woopos.common.composeui.component
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noticed that in many places "toAdaptivePaddings" are not used, so the layout will look bad on different screen types

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Let me know if I have missed anywhere else - e94d0e5


import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
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.shape.RoundedCornerShape
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.woocommerce.android.R
import com.woocommerce.android.ui.woopos.common.composeui.WooPosCard
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

@Composable
fun WooPosPaginationErrorScreen(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

np: maybe call it somehow closer to reality? WooPosPaginationErrorIndicator?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done: aa38f10

modifier: Modifier = Modifier,
icon: Painter = painterResource(id = R.drawable.woo_pos_ic_error),
message: String,
primaryButton: Button,
) {
WooPosCard {
WooPosPaginationErrorScreenContent(
modifier = modifier,
icon = icon,
message = message,
primaryButton = primaryButton
)
}
}

@Composable
private fun WooPosPaginationErrorScreenContent(
modifier: Modifier,
icon: Painter,
message: String,
primaryButton: Button
) {
Row(
modifier = modifier
.fillMaxWidth()
.height(112.dp)
.clip(RoundedCornerShape(16.dp))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the goal was to mimic the product's items, then it doesn't match. Please take a look at WooPosItemsList and copy paste the card and row setup from there

Btw, in WooPosItemsList there is naming without WooPos of a public ItemList

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done: 19a7ed5

.padding(16.dp.toAdaptivePadding()),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Row(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need 3 rows nested here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored here: 19a7ed5

verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier.weight(1f)
) {
Icon(
modifier = Modifier.size(24.dp),
painter = icon,
contentDescription = stringResource(R.string.woopos_error_icon_content_description),
tint = Color.Unspecified,
)

Spacer(modifier = Modifier.width(24.dp.toAdaptivePadding()))

Text(
text = message,
style = MaterialTheme.typography.h5,
fontWeight = FontWeight.SemiBold,
color = MaterialTheme.colors.error
)
}

Row(
modifier = Modifier.weight(0.5f)
) {
WooPosButton(
text = primaryButton.text,
onClick = primaryButton.click,
modifier = Modifier
.height(50.dp)
.clip(RoundedCornerShape(16.dp))
)
}
}
}

@Composable
@WooPosPreview
fun WooPosPaginationErrorScreenPreview() {
WooPosTheme {
WooPosPaginationErrorScreen(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am considering whether a preview with a list or a list with outer padding would be better for development and debugging.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have a preview like this in WooPosItemsScreen. Let me know if I have misunderstood your query.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it a matter of personal preference, but switching between WooPosItemsScreen and the code in this file while changing card settings is not the most enjoyable experience. On top of that it takes time to rerender WooPosItemsScreen as it's huge and has multiple reviews

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done: 1eb6c32

message = "Error loading products",
primaryButton = Button(
text = "Load more",
click = {}
)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ sealed class WooPosBaseViewState(

interface ContentViewState {
val items: List<WooPosItem>
val loadingMore: Boolean
val reloadingProductsWithPullToRefresh: Boolean
val paginationState: PaginationState
}

sealed interface PaginationState {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious, why interface?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for flexibility as this paginationState will be used for different kind of items in future and I wasn't sure if i want to tie up the subtype into a restricted base class.

At this point. It doesn't make any difference whether it is a sealed class or interface.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point. It doesn't make any difference whether it is a sealed class or interface.

Imo sealed interface has to be used on purpose, and if there is no purpose, then it's better to use class to avoid confusion

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done: a9780a3

data object None : PaginationState
data object Loading : PaginationState
data object Error : PaginationState
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ fun ItemList(
listState: LazyListState,
onItemClicked: (item: WooPosItem) -> Unit,
onEndOfProductsListReached: () -> Unit,
onErrorWhilePaginating: @Composable () -> Unit,
) {
WooPosLazyColumn(
verticalArrangement = Arrangement.spacedBy(8.dp),
Expand Down Expand Up @@ -95,9 +96,19 @@ fun ItemList(
}
}

if (state.loadingMore) {
item {
ItemsLoadingItem()
when (state.paginationState) {
PaginationState.Error -> {
item {
onErrorWhilePaginating()
}
}
PaginationState.Loading -> {
item {
ItemsLoadingItem()
}
}
PaginationState.None -> {
// no op
}
}
item {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ 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.Button
import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosErrorScreen
import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosPaginationErrorScreen
import com.woocommerce.android.ui.woopos.common.composeui.toAdaptivePadding
import com.woocommerce.android.ui.woopos.home.items.WooPosItem.SimpleProduct
import com.woocommerce.android.ui.woopos.home.items.WooPosItem.VariableProduct
Expand Down Expand Up @@ -169,7 +170,13 @@ private fun MainItemsList(
listState,
onItemClicked,
onEndOfItemListReached,
)
) {
ProductsPaginationError(
onRetryClicked = {
onEndOfItemListReached()
}
)
}
}
}

Expand Down Expand Up @@ -317,6 +324,17 @@ fun ProductsError(onRetryClicked: () -> Unit) {
}
}

@Composable
fun ProductsPaginationError(onRetryClicked: () -> Unit) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if it's public then it should be called with WooPos...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And in other places the same

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done: 6a3b777

WooPosPaginationErrorScreen(
message = stringResource(id = R.string.woopos_items_pagination_error),
primaryButton = Button(
text = stringResource(id = R.string.woopos_items_pagination_load_more_label),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if it's missed but in both places it's still Failed to load more items. Please try again. with Load more, while in preview

    WooPosTheme {
        WooPosPaginationErrorScreen(
            message = "Error loading products",
            primaryButton = Button(
                text = "Load more",
                click = {}
            )
        )
    }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done: 623125f

click = onRetryClicked
),
)
}

@OptIn(ExperimentalMaterialApi::class)
@Composable
@WooPosPreview
Expand Down Expand Up @@ -353,7 +371,7 @@ fun WooPosItemsScreenPreview(modifier: Modifier = Modifier) {
imageUrl = null,
),
),
loadingMore = true,
paginationState = PaginationState.Loading,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shell we also have preview for the pagination error?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done: 6bb0870

reloadingProductsWithPullToRefresh = true,
bannerState = WooPosItemsViewState.Content.BannerState(
isBannerHiddenByUser = true,
Expand Down Expand Up @@ -472,7 +490,6 @@ fun WooPosHomeScreenItemsWithSimpleProductsOnlyBannerPreview() {
imageUrl = null,
),
),
loadingMore = false,
reloadingProductsWithPullToRefresh = true,
bannerState = WooPosItemsViewState.Content.BannerState(
isBannerHiddenByUser = false,
Expand Down Expand Up @@ -525,7 +542,6 @@ fun WooPosHomeScreenItemsWithInfoIconInToolbarPreview() {
imageUrl = null,
),
),
loadingMore = false,
reloadingProductsWithPullToRefresh = false,
bannerState = WooPosItemsViewState.Content.BannerState(
isBannerHiddenByUser = true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ class WooPosItemsViewModel @Inject constructor(
)
}
},
loadingMore = false,
paginationState = PaginationState.None,
reloadingProductsWithPullToRefresh = false,
bannerState = WooPosItemsViewState.Content.BannerState(
isBannerHiddenByUser = isBannerHiddenByUser(),
Expand All @@ -245,15 +245,15 @@ class WooPosItemsViewModel @Inject constructor(
return
}

_viewState.value = currentState.copy(loadingMore = true)
_viewState.value = currentState.copy(paginationState = PaginationState.Loading)

loadMoreProductsJob?.cancel()
loadMoreProductsJob = viewModelScope.launch {
val result = productsDataSource.loadMore()
_viewState.value = if (result.isSuccess) {
result.getOrThrow().toContentState()
} else {
WooPosItemsViewState.Error()
currentState.copy(paginationState = PaginationState.Error)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ sealed class WooPosItemsViewState(
) : WooPosBaseViewState(reloadingProductsWithPullToRefresh) {
data class Content(
override val items: List<WooPosItem>,
override val loadingMore: Boolean,
val bannerState: BannerState,
override val paginationState: PaginationState = PaginationState.None,
override val reloadingProductsWithPullToRefresh: Boolean = false
) : WooPosItemsViewState(reloadingProductsWithPullToRefresh), ContentViewState {
data class BannerState(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ sealed class WooPosVariationsViewState(

data class Content(
override val items: List<WooPosItem.Variation>,
override val loadingMore: Boolean,
override val reloadingProductsWithPullToRefresh: Boolean = false,
override val paginationState: PaginationState = PaginationState.None,
) : WooPosVariationsViewState(reloadingProductsWithPullToRefresh), ContentViewState

data class Loading(
Expand Down
Loading