woocommerce-android icon indicating copy to clipboard operation
woocommerce-android copied to clipboard

[Woo POS] Disable product list item animation

Open samiuelson opened this issue 7 months ago • 11 comments

Closes: #WOOPRD-505

Description

This PR disables animation of product list items in POS, resulting in unexpected shadow artifact when switching between Products and Coupons tab in POS.

Steps to reproduce

  1. Go to POS
  2. Switch between Coupons and Products, back and forth

https://github.com/user-attachments/assets/83312bde-7779-460e-a40c-30e163704470

Testing information

The tests that have been performed

Verified the animation is not visible.

Images/gif

N/A

  • [x] I have considered if this change warrants release notes and have added them to RELEASE-NOTES.txt if necessary. Use the "[Internal]" label for non-user-facing changes.

Reviewer (or Author, in the case of optional code reviews):

Please make sure these conditions are met before approving the PR, or request changes if the PR needs improvement:

  • [ ] The PR is small and has a clear, single focus, or a valid explanation is provided in the description. If needed, please request to split it into smaller PRs.
  • [ ] Ensure Adequate Unit Test Coverage: The changes are reasonably covered by unit tests or an explanation is provided in the PR description.
  • [ ] Manual Testing: The author listed all the tests they ran, including smoke tests when needed (e.g., for refactorings). The reviewer confirmed that the PR works as expected on big (tablet) and small (phone) in case of UI changes, and no regressions are added.

samiuelson avatar May 14 '25 18:05 samiuelson

1 Message
:book: This PR is still a Draft: some checks will be skipped.

Generated by :no_entry_sign: Danger

dangermattic avatar May 14 '25 18:05 dangermattic

📲 You can test the changes from this Pull Request in WooCommerce-Wear Android by scanning the QR code below to install the corresponding build.
App Name WooCommerce-Wear Android
Platform⌚️ Wear OS
FlavorJalapeno
Build TypeDebug
Commit4c07907ec656f3d9401ee9ddedad57d537396356
Direct Downloadwoocommerce-wear-prototype-build-pr14067-4c07907.apk

wpmobilebot avatar May 14 '25 18:05 wpmobilebot

📲 You can test the changes from this Pull Request in WooCommerce Android by scanning the QR code below to install the corresponding build.

App Name WooCommerce Android
Platform📱 Mobile
FlavorJalapeno
Build TypeDebug
Commit4c07907ec656f3d9401ee9ddedad57d537396356
Direct Downloadwoocommerce-prototype-build-pr14067-4c07907.apk

wpmobilebot avatar May 14 '25 18:05 wpmobilebot

@samiuelson 👋

I am not completely certain that the solution is better than the bug in this case. Keep in mind that we are losing the visual indication to a user that new products have been added or that some of them have been removed.

https://github.com/user-attachments/assets/767ca6e5-6ab7-497b-b5eb-322d704305e1


Notice that the coupons are not flashing, but they have enabled animation, so I guess there is something we can do without disabling the animation

kidinov avatar May 15 '25 12:05 kidinov

@samiuelson that's interesting. After merging from Trunk, it started to flash on the coupons too, so my guess is that the issue comes from listState we pass from outside

//cc @malinajirka

kidinov avatar May 15 '25 13:05 kidinov

Codecov Report

All modified and coverable lines are covered by tests :white_check_mark:

Project coverage is 37.62%. Comparing base (4d21c75) to head (4c07907).

Additional details and impacted files
@@            Coverage Diff            @@
##              trunk   #14067   +/-   ##
=========================================
  Coverage     37.62%   37.62%           
  Complexity     8812     8812           
=========================================
  Files          1933     1933           
  Lines        108130   108130           
  Branches      14091    14091           
=========================================
  Hits          40682    40682           
  Misses        63762    63762           
  Partials       3686     3686           

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

:rocket: New features to boost your workflow:
  • :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

codecov-commenter avatar May 15 '25 14:05 codecov-commenter

Good point, @kidinov! I didn't realize it will break other lazy list's animations. Reverted: 6667d56.

After merging from Trunk, it started to flash on the coupons too, so my guess is that the issue comes from listState we pass from outside

Yeah, indeed the issue is present because the lazylist state is created higher up in the hierarchy (which helps with remembering scroll position).

I'm out of ideas for now. Let me know if you have any clues, @malinajirka.

samiuelson avatar May 15 '25 15:05 samiuelson

What we could try - not sure if it helps, is to replace crossFade with AnimatedVisibility. Something like

AnimatedScreenContent(visible = screenState == ScreenState.PRODUCTS) {
                WooPosProductsScreen(
                    modifier = Modifier.padding(
                        horizontal = WooPosSpacing.Medium.value.toAdaptivePadding(),
                    ),
                    listState = productsListState
                )
            }

            AnimatedScreenContent(visible = screenState == ScreenState.PRODUCTS_SEARCH) {
                WooPosItemsSearchScreen()
            }

            AnimatedScreenContent(visible = screenState == ScreenState.COUPONS) {
                WooPosCouponsScreen(
                    modifier = Modifier.padding(
                        horizontal = WooPosSpacing.Medium.value.toAdaptivePadding()
                    ),
                    listState = couponsListState,
                )
            }
            
            
           
@Composable
private fun AnimatedScreenContent(
    visible: Boolean,
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit
) {
    AnimatedVisibility(
        visible = visible,
        enter = androidx.compose.animation.fadeIn(animationSpec = tween(150, easing = LinearEasing)),
        exit = androidx.compose.animation.fadeOut(animationSpec = tween(150, easing = LinearEasing)),
        modifier = modifier
    ) {
        content()
    }
}

There are two CrossFade animations in our hierarchy, we'd need to do it for both. I'm not sure if it helps, but it should keep the lists in the compose tree even when they are not visible, so it could potentially help. I haven't tried it for this bug, it's just an idea.

malinajirka avatar May 15 '25 17:05 malinajirka

@samiuelson 👋

My understanding of the issue comes from the fact that we store the lazy list state outside of the recomposition; therefore, it's applied after causing the list to be redrawn. So, for instance, this code fixes the flashing:

@Composable
fun WooPosItemsScreens(modifier: Modifier) {
    val viewModel: WooPosItemsScreenViewModel = hiltViewModel()
    val itemsViewModel: WooPosItemsViewModel = hiltViewModel()
    val currentState = itemsViewModel.viewState.collectAsState()

    val productListState = key("products_list_${currentState.value is WooPosItemsViewState.ProductList}") {
        rememberLazyListState()
    }
    val couponsListState = key("coupons_list_${currentState.value is WooPosItemsViewState.CouponList}") {
        rememberLazyListState()
    }

    WooPosItemsScreens(
        modifier = modifier,
        itemsScreens = viewModel.screenState,
        productListState = productListState,
        couponsListState = couponsListState
    ) {
        viewModel.onUiEvent(WooPosItemsNavigator.WooPosItemsScreenNavigationEvent.NavigateBackToItemListScreen)
    }
}

@Composable
fun WooPosItemsScreens(
    modifier: Modifier,
    itemsScreens: StateFlow<WooPosItemsScreenViewModel.ItemsScreens>,
    productListState: LazyListState,
    couponsListState: LazyListState,
    onNavigateToItemsListScreen: () -> Unit
) {
    val currentNavigationState = itemsScreens.collectAsState()
    Box(modifier = modifier.fillMaxSize()) {
        Crossfade(targetState = currentNavigationState.value, label = "LeftPaneScreen") { navigationState ->
            when (navigationState) {
                is WooPosItemsScreenViewModel.ItemsScreens.ItemListScreen -> {
                    WooPosItemsScreen(modifier = modifier, productListState, couponsListState)
                }

                is WooPosItemsScreenViewModel.ItemsScreens.VariationsScreen -> {
                    WooPosVariationsScreen(
                        modifier = modifier,
                        variableProductData = navigationState.product,
                        onBackClicked = { onNavigateToItemsListScreen() }
                    )
                }
            }
        }
    }
}

BUT it means that we loose scrolling position everytime the screens changed. We could go further and save scrolling position and restore manually but not sure how it will look like. It feels like it should be simplier solution here

kidinov avatar May 22 '25 12:05 kidinov

Version 22.5 has now entered code-freeze, so the milestone of this PR has been updated to 22.6.

wpmobilebot avatar May 30 '25 08:05 wpmobilebot

Version 22.6 has now entered code-freeze, so the milestone of this PR has been updated to 22.7.

wpmobilebot avatar Jun 13 '25 11:06 wpmobilebot

Version 22.7 has now entered code-freeze, so the milestone of this PR has been updated to 22.8.

wpmobilebot avatar Jun 27 '25 14:06 wpmobilebot

This needs to be approached different way, from scratch.

samiuelson avatar Jul 02 '25 09:07 samiuelson