From 873b542c9603b5780bad91bb13e77a8bbbfd3a59 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 13 May 2024 15:24:59 -0300 Subject: [PATCH 01/45] Introduce OrderDetailsScreen.kt --- .../woocommerce/android/ui/orders/details/OrderDetailsScreen.kt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt new file mode 100644 index 00000000000..a6e5ab08df9 --- /dev/null +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt @@ -0,0 +1,2 @@ +package com.woocommerce.android.ui.orders.details + From 87099d12d8a6778e7bc0526fdd9beeb83ebf86e6 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 13 May 2024 15:25:13 -0300 Subject: [PATCH 02/45] Refactor Orders packages --- .../java/com/woocommerce/android/ui/mystore/MyStoreScreen.kt | 4 ++-- .../woocommerce/android/ui/orders/{ => list}/FetchOrders.kt | 3 ++- .../android/ui/orders/{ => list}/OrdersListScreen.kt | 4 ++-- .../android/ui/orders/{ => list}/OrdersListViewModel.kt | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) rename WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/{ => list}/FetchOrders.kt (94%) rename WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/{ => list}/OrdersListScreen.kt (98%) rename WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/{ => list}/OrdersListViewModel.kt (98%) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/mystore/MyStoreScreen.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/mystore/MyStoreScreen.kt index b90da867e1d..c3b7f5239ee 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/mystore/MyStoreScreen.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/mystore/MyStoreScreen.kt @@ -5,8 +5,8 @@ import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import com.google.android.horologist.compose.pager.PagerScreen -import com.woocommerce.android.ui.orders.OrdersListScreen -import com.woocommerce.android.ui.orders.OrdersListViewModel +import com.woocommerce.android.ui.orders.list.OrdersListScreen +import com.woocommerce.android.ui.orders.list.OrdersListViewModel import com.woocommerce.android.ui.stats.StoreStatsScreen import com.woocommerce.android.ui.stats.StoreStatsViewModel diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/FetchOrders.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/FetchOrders.kt similarity index 94% rename from WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/FetchOrders.kt rename to WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/FetchOrders.kt index eb47c4f3b5a..98b20381891 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/FetchOrders.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/FetchOrders.kt @@ -1,8 +1,9 @@ -package com.woocommerce.android.ui.orders +package com.woocommerce.android.ui.orders.list import com.woocommerce.android.phone.PhoneConnectionRepository import com.woocommerce.android.system.NetworkStatus import com.woocommerce.android.ui.login.ObserveLoginRequest.Companion.TIMEOUT_MILLIS +import com.woocommerce.android.ui.orders.OrdersRepository import com.woocommerce.commons.wear.MessagePath.REQUEST_ORDERS import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersListScreen.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListScreen.kt similarity index 98% rename from WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersListScreen.kt rename to WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListScreen.kt index 751cc0f1d26..4c479007690 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersListScreen.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListScreen.kt @@ -1,4 +1,4 @@ -package com.woocommerce.android.ui.orders +package com.woocommerce.android.ui.orders.list import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -32,7 +32,7 @@ import com.woocommerce.android.presentation.component.LoadingScreen import com.woocommerce.android.presentation.theme.WooColors import com.woocommerce.android.presentation.theme.WooTheme import com.woocommerce.android.presentation.theme.WooTypography -import com.woocommerce.android.ui.orders.OrdersListViewModel.OrderItem +import com.woocommerce.android.ui.orders.list.OrdersListViewModel.OrderItem @Composable fun OrdersListScreen(viewModel: OrdersListViewModel) { diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersListViewModel.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt similarity index 98% rename from WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersListViewModel.kt rename to WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt index 91ca0928919..a7352788f82 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersListViewModel.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt @@ -1,4 +1,4 @@ -package com.woocommerce.android.ui.orders +package com.woocommerce.android.ui.orders.list import android.os.Parcelable import androidx.lifecycle.SavedStateHandle From a5d1eed3b8ed51295b6066f75723add5afff3bbf Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 13 May 2024 15:29:00 -0300 Subject: [PATCH 03/45] Define Order Details scaffolds --- .../ui/orders/details/OrderDetailsScreen.kt | 31 +++++++++++++++++++ .../orders/details/OrderDetailsViewModel.kt | 26 ++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt index a6e5ab08df9..fe74513898c 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt @@ -1,2 +1,33 @@ package com.woocommerce.android.ui.orders.details +import androidx.compose.foundation.layout.Column +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.livedata.observeAsState +import com.woocommerce.android.presentation.component.LoadingScreen + +@Composable +fun OrderDetailsScreen(viewModel: OrderDetailsViewModel) { + val viewState = viewModel.viewState.observeAsState() + OrderDetailsScreen( + isLoading = viewState.value?.isLoading ?: false + ) +} + +@Composable +fun OrderDetailsScreen( + isLoading: Boolean +) { + Column { + if (isLoading) { + LoadingScreen() + } else { + OrderDetailsContent() + } + } +} + +@Composable +fun OrderDetailsContent() { + Text("Order Details Content") +} diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt new file mode 100644 index 00000000000..5565c7b9f0e --- /dev/null +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt @@ -0,0 +1,26 @@ +package com.woocommerce.android.ui.orders.details + +import android.os.Parcelable +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.asLiveData +import com.woocommerce.commons.viewmodel.ScopedViewModel +import com.woocommerce.commons.viewmodel.getStateFlow +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject +import kotlinx.parcelize.Parcelize + +@HiltViewModel +class OrderDetailsViewModel @Inject constructor( + savedState: SavedStateHandle +): ScopedViewModel(savedState) { + private val _viewState = savedState.getStateFlow( + scope = this, + initialValue = ViewState() + ) + val viewState = _viewState.asLiveData() + + @Parcelize + data class ViewState( + val isLoading: Boolean = false + ) : Parcelable +} From 8365bd50a55bd6d9d5cf4b391b3ccd41dbf3dfa5 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 13 May 2024 15:31:12 -0300 Subject: [PATCH 04/45] Refactor OrdersListViewModel to support order ID control --- .../android/ui/orders/list/OrdersListViewModel.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt index a7352788f82..6786f87cc35 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt @@ -46,6 +46,10 @@ class OrdersListViewModel @AssistedInject constructor( .launchIn(this) } + fun onOrderItemClick(orderId: Long) { + navController.navigate("order_details/${orderId}") + } + private suspend fun requestOrdersData(selectedSite: SiteModel) { _viewState.update { it.copy(isLoading = true) } fetchOrders(selectedSite) @@ -84,6 +88,7 @@ class OrdersListViewModel @AssistedInject constructor( } return OrderItem( + id = orderId, date = formattedCreationDate, number = number, customerName = formattedBillingName, @@ -100,6 +105,7 @@ class OrdersListViewModel @AssistedInject constructor( @Parcelize data class OrderItem( + val id: Long, val date: String, val number: String, val customerName: String?, From 8ccc8846d661d26a6042a3dd27a76855b1fc7b95 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 13 May 2024 15:36:42 -0300 Subject: [PATCH 05/45] Wire Order item click event with ViewModel --- .../ui/orders/list/OrdersListScreen.kt | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListScreen.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListScreen.kt index 4c479007690..0b982b2094d 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListScreen.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListScreen.kt @@ -1,6 +1,7 @@ package com.woocommerce.android.ui.orders.list import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -39,7 +40,8 @@ fun OrdersListScreen(viewModel: OrdersListViewModel) { val viewState by viewModel.viewState.observeAsState() OrdersListScreen( isLoading = viewState?.isLoading ?: false, - orders = viewState?.orders.orEmpty() + orders = viewState?.orders.orEmpty(), + onOrderClicked = viewModel::onOrderItemClick ) } @@ -47,6 +49,7 @@ fun OrdersListScreen(viewModel: OrdersListViewModel) { fun OrdersListScreen( isLoading: Boolean, orders: List, + onOrderClicked: (orderId: Long) -> Unit, modifier: Modifier = Modifier ) { WooTheme { @@ -70,7 +73,7 @@ fun OrdersListScreen( if (isLoading) { LoadingScreen() } else { - OrdersLazyColumn(orders, modifier) + OrdersLazyColumn(orders, onOrderClicked, modifier) } } } @@ -80,6 +83,7 @@ fun OrdersListScreen( @Composable private fun OrdersLazyColumn( orders: List, + onOrderClicked: (orderId: Long) -> Unit, modifier: Modifier ) { ScalingLazyColumn( @@ -91,8 +95,9 @@ private fun OrdersLazyColumn( ) { items(orders) { OrderListItem( - modifier = modifier, - order = it + order = it, + onOrderClicked = onOrderClicked, + modifier = modifier ) } } @@ -100,8 +105,9 @@ private fun OrdersLazyColumn( @Composable fun OrderListItem( - modifier: Modifier, - order: OrderItem + order: OrderItem, + onOrderClicked: (orderId: Long) -> Unit, + modifier: Modifier ) { Box( modifier = modifier @@ -109,6 +115,7 @@ fun OrderListItem( .background(Color.DarkGray) .padding(10.dp) .fillMaxWidth() + .clickable { onOrderClicked(order.id) } ) { Column(verticalArrangement = Arrangement.spacedBy(4.dp)) { Row( @@ -160,8 +167,10 @@ fun OrderListItem( fun Preview() { OrdersListScreen( isLoading = false, + onOrderClicked = {}, orders = listOf( OrderItem( + id = 0L, date = "25 Feb", number = "#125", customerName = "John Doe", @@ -169,6 +178,7 @@ fun Preview() { status = "Processing" ), OrderItem( + id = 1L, date = "31 Dec", number = "#124", customerName = "Jane Doe", @@ -176,6 +186,7 @@ fun Preview() { status = "Completed" ), OrderItem( + id = 2L, date = "4 Oct", number = "#123", customerName = "John Smith", From 0be211fd198cba2d61084291dcdc118b46b27c05 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 13 May 2024 15:49:21 -0300 Subject: [PATCH 06/45] Introduce Order Details navigation route with parameters --- .../com/woocommerce/android/ui/Navigation.kt | 22 +++++++++++++++++-- .../ui/orders/list/OrdersListViewModel.kt | 3 ++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/Navigation.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/Navigation.kt index b9c6d1858a4..56f13deb0eb 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/Navigation.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/Navigation.kt @@ -3,15 +3,19 @@ package com.woocommerce.android.ui import androidx.compose.runtime.Composable import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavHostController +import androidx.navigation.NavType import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController +import androidx.navigation.navArgument +import com.woocommerce.android.ui.NavArgs.ORDER_ID import com.woocommerce.android.ui.NavRoutes.LOGIN import com.woocommerce.android.ui.NavRoutes.MY_STORE +import com.woocommerce.android.ui.NavRoutes.ORDER_DETAILS import com.woocommerce.android.ui.login.LoginScreen import com.woocommerce.android.ui.login.LoginViewModel import com.woocommerce.android.ui.mystore.MyStoreScreen -import com.woocommerce.android.ui.orders.OrdersListViewModel +import com.woocommerce.android.ui.orders.list.OrdersListViewModel import com.woocommerce.android.ui.stats.StoreStatsViewModel @Composable @@ -39,10 +43,24 @@ fun WooWearNavHost( ordersListViewModel = ordersListViewModel ) } + composable( + route = ORDER_DETAILS.withArgs(ORDER_ID.key), + arguments = listOf(navArgument(ORDER_ID.key) { type = NavType.LongType }) + ) { + } } } enum class NavRoutes(val route: String) { LOGIN("login"), - MY_STORE("myStore") + MY_STORE("myStore"), + ORDER_DETAILS("orderDetails"); + + fun withArgs(args: Any): String { + return "$route/{${args}}" + } +} + +enum class NavArgs(val key: String) { + ORDER_ID("orderId") } diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt index 6786f87cc35..66de343a608 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt @@ -4,6 +4,7 @@ import android.os.Parcelable import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.asLiveData import androidx.navigation.NavHostController +import com.woocommerce.android.ui.NavRoutes.ORDER_DETAILS import com.woocommerce.android.ui.login.LoginRepository import com.woocommerce.android.util.DateUtils import com.woocommerce.commons.viewmodel.ScopedViewModel @@ -47,7 +48,7 @@ class OrdersListViewModel @AssistedInject constructor( } fun onOrderItemClick(orderId: Long) { - navController.navigate("order_details/${orderId}") + navController.navigate(ORDER_DETAILS.withArgs(orderId)) } private suspend fun requestOrdersData(selectedSite: SiteModel) { From 14dd210df937ad90256be1f47273e30c5ccbbb05 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 13 May 2024 17:27:55 -0300 Subject: [PATCH 07/45] Fix lint issues --- .../src/main/java/com/woocommerce/android/ui/Navigation.kt | 2 +- .../android/ui/orders/details/OrderDetailsViewModel.kt | 4 ++-- .../woocommerce/android/ui/orders/list/OrdersListViewModel.kt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/Navigation.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/Navigation.kt index 56f13deb0eb..75c08abde0e 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/Navigation.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/Navigation.kt @@ -57,7 +57,7 @@ enum class NavRoutes(val route: String) { ORDER_DETAILS("orderDetails"); fun withArgs(args: Any): String { - return "$route/{${args}}" + return "$route/{$args}" } } diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt index 5565c7b9f0e..bdf29f32bf3 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt @@ -6,13 +6,13 @@ import androidx.lifecycle.asLiveData import com.woocommerce.commons.viewmodel.ScopedViewModel import com.woocommerce.commons.viewmodel.getStateFlow import dagger.hilt.android.lifecycle.HiltViewModel -import javax.inject.Inject import kotlinx.parcelize.Parcelize +import javax.inject.Inject @HiltViewModel class OrderDetailsViewModel @Inject constructor( savedState: SavedStateHandle -): ScopedViewModel(savedState) { +) : ScopedViewModel(savedState) { private val _viewState = savedState.getStateFlow( scope = this, initialValue = ViewState() diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt index 66de343a608..9d3c84582f1 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt @@ -23,7 +23,7 @@ import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.WooCommerceStore import java.util.Locale -@Suppress("UnusedPrivateProperty", "LongParameterList") +@Suppress("LongParameterList") @HiltViewModel(assistedFactory = OrdersListViewModel.Factory::class) class OrdersListViewModel @AssistedInject constructor( @Assisted private val navController: NavHostController, From 077090137731cf130b7e92d43bf26e7c308559af Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 13 May 2024 17:57:59 -0300 Subject: [PATCH 08/45] Introduce Order retrieval for OrderDetails --- .../android/ui/orders/OrdersRepository.kt | 8 ++++++++ .../ui/orders/details/OrderDetailsViewModel.kt | 13 +++++++++++++ 2 files changed, 21 insertions(+) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt index 775d6d8b38a..d8baf6d731b 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt @@ -31,6 +31,14 @@ class OrdersRepository @Inject constructor( shouldStoreData = true ) + suspend fun getOrderFromId(orderId: Long): OrderEntity? { + val site = loginRepository.selectedSite ?: return null + return orderStore.getOrderByIdAndSite( + orderId = orderId, + site = site + ) + } + fun observeOrdersDataChanges() = ordersDataStore.data .mapNotNull { it[stringPreferencesKey(generateOrdersKey())] } .map { gson.fromJson(it, Array::class.java).toList() } diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt index bdf29f32bf3..3f9847871a6 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt @@ -3,14 +3,18 @@ package com.woocommerce.android.ui.orders.details import android.os.Parcelable import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.asLiveData +import com.woocommerce.android.ui.NavArgs.ORDER_ID +import com.woocommerce.android.ui.orders.OrdersRepository import com.woocommerce.commons.viewmodel.ScopedViewModel import com.woocommerce.commons.viewmodel.getStateFlow import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.parcelize.Parcelize import javax.inject.Inject +import kotlinx.coroutines.launch @HiltViewModel class OrderDetailsViewModel @Inject constructor( + private val ordersRepository: OrdersRepository, savedState: SavedStateHandle ) : ScopedViewModel(savedState) { private val _viewState = savedState.getStateFlow( @@ -19,6 +23,15 @@ class OrderDetailsViewModel @Inject constructor( ) val viewState = _viewState.asLiveData() + init { + launch { + savedState.get(ORDER_ID.key) + ?.let { ordersRepository.getOrderFromId(it) } + ?.let { /* map OrderEntity to UI model */ } + } + + } + @Parcelize data class ViewState( val isLoading: Boolean = false From abfc82cfca3e452ea03f2101cc159565443a7ef5 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 13 May 2024 19:17:30 -0300 Subject: [PATCH 09/45] Create ParseOrderData use case --- .../android/ui/orders/ParseOrderData.kt | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/ParseOrderData.kt diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/ParseOrderData.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/ParseOrderData.kt new file mode 100644 index 00000000000..1a95e730590 --- /dev/null +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/ParseOrderData.kt @@ -0,0 +1,68 @@ +package com.woocommerce.android.ui.orders + +import android.os.Parcelable +import com.woocommerce.android.util.DateUtils +import java.util.Locale +import javax.inject.Inject +import kotlinx.parcelize.Parcelize +import org.wordpress.android.fluxc.model.OrderEntity +import org.wordpress.android.fluxc.model.SiteModel +import org.wordpress.android.fluxc.store.WooCommerceStore + +class ParseOrderData @Inject constructor( + private val wooCommerceStore: WooCommerceStore, + private val dateUtils: DateUtils, + private val locale: Locale, +) { + operator fun invoke( + selectedSite: SiteModel, + order: OrderEntity + ) = order.toOrderItem(selectedSite) + + operator fun invoke( + selectedSite: SiteModel, + orders: List + ) = orders.map { it.toOrderItem(selectedSite) } + + private fun OrderEntity.toOrderItem( + selectedSite: SiteModel + ): OrderItem { + val formattedOrderTotals = wooCommerceStore.formatCurrencyForDisplay( + amount = total.toDoubleOrNull() ?: 0.0, + site = selectedSite, + currencyCode = null, + applyDecimalFormatting = true + ) + + val formattedCreationDate = dateUtils.getFormattedDateWithSiteTimeZone( + dateCreated + ) ?: dateCreated + + val formattedBillingName = takeUnless { + billingFirstName.isEmpty() && billingLastName.isEmpty() + }?.let { "$billingFirstName $billingLastName" } + + val formattedStatus = status.replaceFirstChar { + if (it.isLowerCase()) it.titlecase(locale) else it.toString() + } + + return OrderItem( + id = orderId, + date = formattedCreationDate, + number = number, + customerName = formattedBillingName, + total = formattedOrderTotals, + status = formattedStatus + ) + } + + @Parcelize + data class OrderItem( + val id: Long, + val date: String, + val number: String, + val customerName: String?, + val total: String, + val status: String + ) : Parcelable +} From d053f1724da4ddad789b3b98cce9197640117272 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 13 May 2024 19:19:33 -0300 Subject: [PATCH 10/45] Remove OrderItem usage from ViewModel and use the Use case one --- .../ui/orders/list/OrdersListScreen.kt | 2 +- .../ui/orders/list/OrdersListViewModel.kt | 57 ++----------------- 2 files changed, 5 insertions(+), 54 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListScreen.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListScreen.kt index 0b982b2094d..ca2bb941855 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListScreen.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListScreen.kt @@ -33,7 +33,7 @@ import com.woocommerce.android.presentation.component.LoadingScreen import com.woocommerce.android.presentation.theme.WooColors import com.woocommerce.android.presentation.theme.WooTheme import com.woocommerce.android.presentation.theme.WooTypography -import com.woocommerce.android.ui.orders.list.OrdersListViewModel.OrderItem +import com.woocommerce.android.ui.orders.ParseOrderData.OrderItem @Composable fun OrdersListScreen(viewModel: OrdersListViewModel) { diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt index 9d3c84582f1..d0a24ea8031 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt @@ -6,7 +6,8 @@ import androidx.lifecycle.asLiveData import androidx.navigation.NavHostController import com.woocommerce.android.ui.NavRoutes.ORDER_DETAILS import com.woocommerce.android.ui.login.LoginRepository -import com.woocommerce.android.util.DateUtils +import com.woocommerce.android.ui.orders.ParseOrderData +import com.woocommerce.android.ui.orders.ParseOrderData.OrderItem import com.woocommerce.commons.viewmodel.ScopedViewModel import com.woocommerce.commons.viewmodel.getStateFlow import dagger.assisted.Assisted @@ -18,19 +19,13 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.update import kotlinx.parcelize.Parcelize -import org.wordpress.android.fluxc.model.OrderEntity import org.wordpress.android.fluxc.model.SiteModel -import org.wordpress.android.fluxc.store.WooCommerceStore -import java.util.Locale -@Suppress("LongParameterList") @HiltViewModel(assistedFactory = OrdersListViewModel.Factory::class) class OrdersListViewModel @AssistedInject constructor( @Assisted private val navController: NavHostController, private val fetchOrders: FetchOrders, - private val wooCommerceStore: WooCommerceStore, - private val dateUtils: DateUtils, - private val locale: Locale, + private val parseOrders: ParseOrderData, loginRepository: LoginRepository, savedState: SavedStateHandle ) : ScopedViewModel(savedState) { @@ -57,63 +52,19 @@ class OrdersListViewModel @AssistedInject constructor( .onEach { orders -> _viewState.update { viewState -> viewState.copy( - orders = orders.map { - it.toOrderItem(selectedSite) - }, + orders = parseOrders(selectedSite, orders), isLoading = false ) } }.launchIn(this) } - private fun OrderEntity.toOrderItem( - selectedSite: SiteModel - ): OrderItem { - val formattedOrderTotals = wooCommerceStore.formatCurrencyForDisplay( - amount = total.toDoubleOrNull() ?: 0.0, - site = selectedSite, - currencyCode = null, - applyDecimalFormatting = true - ) - - val formattedCreationDate = dateUtils.getFormattedDateWithSiteTimeZone( - dateCreated - ) ?: dateCreated - - val formattedBillingName = takeUnless { - billingFirstName.isEmpty() && billingLastName.isEmpty() - }?.let { "$billingFirstName $billingLastName" } - - val formattedStatus = status.replaceFirstChar { - if (it.isLowerCase()) it.titlecase(locale) else it.toString() - } - - return OrderItem( - id = orderId, - date = formattedCreationDate, - number = number, - customerName = formattedBillingName, - total = formattedOrderTotals, - status = formattedStatus - ) - } - @Parcelize data class ViewState( val isLoading: Boolean = false, val orders: List = emptyList() ) : Parcelable - @Parcelize - data class OrderItem( - val id: Long, - val date: String, - val number: String, - val customerName: String?, - val total: String, - val status: String - ) : Parcelable - @AssistedFactory interface Factory { fun create(navController: NavHostController): OrdersListViewModel From c3a4000ea22b3ee384f73efa2a2438a588b8a9ca Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 13 May 2024 19:25:30 -0300 Subject: [PATCH 11/45] Configure OrderDetailsViewModel order parsing and handling --- .../orders/details/OrderDetailsViewModel.kt | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt index 3f9847871a6..d61d16043e3 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt @@ -4,17 +4,23 @@ import android.os.Parcelable import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.asLiveData import com.woocommerce.android.ui.NavArgs.ORDER_ID +import com.woocommerce.android.ui.login.LoginRepository import com.woocommerce.android.ui.orders.OrdersRepository +import com.woocommerce.android.ui.orders.ParseOrderData +import com.woocommerce.android.ui.orders.ParseOrderData.OrderItem import com.woocommerce.commons.viewmodel.ScopedViewModel import com.woocommerce.commons.viewmodel.getStateFlow import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.parcelize.Parcelize import javax.inject.Inject +import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch @HiltViewModel class OrderDetailsViewModel @Inject constructor( - private val ordersRepository: OrdersRepository, + ordersRepository: OrdersRepository, + parseOrder: ParseOrderData, + loginRepository: LoginRepository, savedState: SavedStateHandle ) : ScopedViewModel(savedState) { private val _viewState = savedState.getStateFlow( @@ -24,16 +30,27 @@ class OrderDetailsViewModel @Inject constructor( val viewState = _viewState.asLiveData() init { + _viewState.update { it.copy(isLoading = true) } launch { savedState.get(ORDER_ID.key) ?.let { ordersRepository.getOrderFromId(it) } - ?.let { /* map OrderEntity to UI model */ } + ?.let { + val site = loginRepository.selectedSite ?: return@let null + parseOrder(site, it) + }.let { presentOrderData(it) } } } + private fun presentOrderData(order: OrderItem?) { + _viewState.update { + it.copy(isLoading = false, orderItem = order) + } + } + @Parcelize data class ViewState( - val isLoading: Boolean = false + val isLoading: Boolean = false, + val orderItem: OrderItem? = null ) : Parcelable } From 3d06d083b63d501de5cc7f2c348b268b103e6e1d Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 13 May 2024 19:34:28 -0300 Subject: [PATCH 12/45] Adjust OrderDetailsScreen to listen to Order data changes --- .../ui/orders/details/OrderDetailsScreen.kt | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt index fe74513898c..bd768cb5754 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt @@ -5,29 +5,38 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.livedata.observeAsState import com.woocommerce.android.presentation.component.LoadingScreen +import com.woocommerce.android.ui.orders.ParseOrderData +import com.woocommerce.android.ui.orders.ParseOrderData.OrderItem @Composable fun OrderDetailsScreen(viewModel: OrderDetailsViewModel) { val viewState = viewModel.viewState.observeAsState() OrderDetailsScreen( - isLoading = viewState.value?.isLoading ?: false + isLoading = viewState.value?.isLoading ?: false, + order = viewState.value?.orderItem ) } @Composable fun OrderDetailsScreen( - isLoading: Boolean + isLoading: Boolean, + order: OrderItem? ) { Column { - if (isLoading) { - LoadingScreen() - } else { - OrderDetailsContent() + when { + isLoading -> LoadingScreen() + order == null -> OrderLoadingFailed() + else -> OrderDetailsContent(order) } } } @Composable -fun OrderDetailsContent() { - Text("Order Details Content") +fun OrderDetailsContent(order: OrderItem) { + Text(order.number) +} + +@Composable +fun OrderLoadingFailed() { + Text("Failed to load Order data") } From d9aa510dddc0c71e7f1ef518adaf5affbc515468 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 13 May 2024 19:36:13 -0300 Subject: [PATCH 13/45] Fix lint issues --- .../java/com/woocommerce/android/ui/orders/ParseOrderData.kt | 4 ++-- .../android/ui/orders/details/OrderDetailsScreen.kt | 1 - .../android/ui/orders/details/OrderDetailsViewModel.kt | 5 ++--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/ParseOrderData.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/ParseOrderData.kt index 1a95e730590..6f47a20c3ea 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/ParseOrderData.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/ParseOrderData.kt @@ -2,12 +2,12 @@ package com.woocommerce.android.ui.orders import android.os.Parcelable import com.woocommerce.android.util.DateUtils -import java.util.Locale -import javax.inject.Inject import kotlinx.parcelize.Parcelize import org.wordpress.android.fluxc.model.OrderEntity import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.WooCommerceStore +import java.util.Locale +import javax.inject.Inject class ParseOrderData @Inject constructor( private val wooCommerceStore: WooCommerceStore, diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt index bd768cb5754..99ee65ee572 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt @@ -5,7 +5,6 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.livedata.observeAsState import com.woocommerce.android.presentation.component.LoadingScreen -import com.woocommerce.android.ui.orders.ParseOrderData import com.woocommerce.android.ui.orders.ParseOrderData.OrderItem @Composable diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt index d61d16043e3..beebeca93de 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt @@ -11,10 +11,10 @@ import com.woocommerce.android.ui.orders.ParseOrderData.OrderItem import com.woocommerce.commons.viewmodel.ScopedViewModel import com.woocommerce.commons.viewmodel.getStateFlow import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.parcelize.Parcelize -import javax.inject.Inject import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import kotlinx.parcelize.Parcelize +import javax.inject.Inject @HiltViewModel class OrderDetailsViewModel @Inject constructor( @@ -39,7 +39,6 @@ class OrderDetailsViewModel @Inject constructor( parseOrder(site, it) }.let { presentOrderData(it) } } - } private fun presentOrderData(order: OrderItem?) { From 9398db5fd32d12c36eb6abded0c4689535a2814e Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 13 May 2024 19:46:13 -0300 Subject: [PATCH 14/45] Fix navigation crashes --- .../main/java/com/woocommerce/android/ui/Navigation.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/Navigation.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/Navigation.kt index 75c08abde0e..1d5e3ceb5d1 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/Navigation.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/Navigation.kt @@ -15,6 +15,8 @@ import com.woocommerce.android.ui.NavRoutes.ORDER_DETAILS import com.woocommerce.android.ui.login.LoginScreen import com.woocommerce.android.ui.login.LoginViewModel import com.woocommerce.android.ui.mystore.MyStoreScreen +import com.woocommerce.android.ui.orders.details.OrderDetailsScreen +import com.woocommerce.android.ui.orders.details.OrderDetailsViewModel import com.woocommerce.android.ui.orders.list.OrdersListViewModel import com.woocommerce.android.ui.stats.StoreStatsViewModel @@ -44,9 +46,11 @@ fun WooWearNavHost( ) } composable( - route = ORDER_DETAILS.withArgs(ORDER_ID.key), + route = ORDER_DETAILS.withArgs("{${ORDER_ID.key}}"), arguments = listOf(navArgument(ORDER_ID.key) { type = NavType.LongType }) ) { + val viewModel: OrderDetailsViewModel = hiltViewModel() + OrderDetailsScreen(viewModel) } } } @@ -57,7 +61,7 @@ enum class NavRoutes(val route: String) { ORDER_DETAILS("orderDetails"); fun withArgs(args: Any): String { - return "$route/{$args}" + return "$route/$args" } } From bd365e91e6002e59d3cf7325a033de06f79b1e39 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 13 May 2024 19:53:04 -0300 Subject: [PATCH 15/45] Improve Navigation args declaration --- .../src/main/java/com/woocommerce/android/ui/Navigation.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/Navigation.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/Navigation.kt index 1d5e3ceb5d1..8209dc1e638 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/Navigation.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/Navigation.kt @@ -46,7 +46,7 @@ fun WooWearNavHost( ) } composable( - route = ORDER_DETAILS.withArgs("{${ORDER_ID.key}}"), + route = ORDER_DETAILS.withArgs(ORDER_ID), arguments = listOf(navArgument(ORDER_ID.key) { type = NavType.LongType }) ) { val viewModel: OrderDetailsViewModel = hiltViewModel() @@ -63,6 +63,10 @@ enum class NavRoutes(val route: String) { fun withArgs(args: Any): String { return "$route/$args" } + + fun withArgs(navArgs: NavArgs): String { + return "$route/{${navArgs.key}}" + } } enum class NavArgs(val key: String) { From 3cb6d9468c6aaba80a6eb1a475f441156af0e47b Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 13 May 2024 19:53:20 -0300 Subject: [PATCH 16/45] Add preview and initial style adjustments to OrderDetailsScreen --- .../ui/orders/details/OrderDetailsScreen.kt | 54 ++++++++++++++++--- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt index 99ee65ee572..a2e0e2ad56e 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt @@ -1,10 +1,18 @@ package com.woocommerce.android.ui.orders.details +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.wear.tooling.preview.devices.WearDevices import com.woocommerce.android.presentation.component.LoadingScreen +import com.woocommerce.android.presentation.theme.WooTheme import com.woocommerce.android.ui.orders.ParseOrderData.OrderItem @Composable @@ -18,24 +26,56 @@ fun OrderDetailsScreen(viewModel: OrderDetailsViewModel) { @Composable fun OrderDetailsScreen( + modifier: Modifier = Modifier, isLoading: Boolean, order: OrderItem? ) { - Column { - when { - isLoading -> LoadingScreen() - order == null -> OrderLoadingFailed() - else -> OrderDetailsContent(order) + WooTheme { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + modifier = modifier.fillMaxSize() + ) { + when { + isLoading -> LoadingScreen() + order == null -> OrderLoadingFailed() + else -> OrderDetailsContent(order) + } } } } @Composable fun OrderDetailsContent(order: OrderItem) { - Text(order.number) + Text( + text = order.number, + color = Color.White + ) } @Composable fun OrderLoadingFailed() { - Text("Failed to load Order data") + Text( + text = "Failed to load Order data", + color = Color.White + ) +} + +@Preview(device = WearDevices.LARGE_ROUND, showSystemUi = true) +@Preview(device = WearDevices.SMALL_ROUND, showSystemUi = true) +@Preview(device = WearDevices.SQUARE, showSystemUi = true) +@Preview(device = WearDevices.RECT, showSystemUi = true) +@Composable +fun Preview() { + OrderDetailsScreen( + isLoading = false, + order = OrderItem( + id = 0L, + date = "25 Feb", + number = "#125", + customerName = "John Doe", + total = "$100.00", + status = "Processing" + ) + ) } From 9b1e7dd72060440e79f3e9a54a4ddf21c969bfc4 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 13 May 2024 20:19:50 -0300 Subject: [PATCH 17/45] Fix and improve Order details data fetching --- .../android/ui/orders/OrdersRepository.kt | 14 ++++++------- .../orders/details/OrderDetailsViewModel.kt | 20 ++++++++++--------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt index d8baf6d731b..0aa270fa2c6 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt @@ -31,13 +31,13 @@ class OrdersRepository @Inject constructor( shouldStoreData = true ) - suspend fun getOrderFromId(orderId: Long): OrderEntity? { - val site = loginRepository.selectedSite ?: return null - return orderStore.getOrderByIdAndSite( - orderId = orderId, - site = site - ) - } + suspend fun getOrderFromId( + selectedSite: SiteModel, + orderId: Long + ) = orderStore.getOrderByIdAndSite( + site = selectedSite, + orderId = orderId + ) fun observeOrdersDataChanges() = ordersDataStore.data .mapNotNull { it[stringPreferencesKey(generateOrdersKey())] } diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt index beebeca93de..41ba8c25bc8 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt @@ -12,9 +12,11 @@ import com.woocommerce.commons.viewmodel.ScopedViewModel import com.woocommerce.commons.viewmodel.getStateFlow import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.update -import kotlinx.coroutines.launch import kotlinx.parcelize.Parcelize import javax.inject.Inject +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach @HiltViewModel class OrderDetailsViewModel @Inject constructor( @@ -31,14 +33,14 @@ class OrderDetailsViewModel @Inject constructor( init { _viewState.update { it.copy(isLoading = true) } - launch { - savedState.get(ORDER_ID.key) - ?.let { ordersRepository.getOrderFromId(it) } - ?.let { - val site = loginRepository.selectedSite ?: return@let null - parseOrder(site, it) - }.let { presentOrderData(it) } - } + loginRepository.selectedSiteFlow + .filterNotNull() + .onEach { site -> + savedState.get(ORDER_ID.key) + ?.let { ordersRepository.getOrderFromId(site, it) } + ?.let { parseOrder(site, it) } + .let { presentOrderData(it) } + }.launchIn(this) } private fun presentOrderData(order: OrderItem?) { From b1a4720dc1c734349facc5823162ecb0f43061e0 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 13 May 2024 20:21:41 -0300 Subject: [PATCH 18/45] Fix lint issues --- .../android/ui/orders/details/OrderDetailsViewModel.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt index 41ba8c25bc8..b8ab4292438 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt @@ -11,12 +11,12 @@ import com.woocommerce.android.ui.orders.ParseOrderData.OrderItem import com.woocommerce.commons.viewmodel.ScopedViewModel import com.woocommerce.commons.viewmodel.getStateFlow import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.update -import kotlinx.parcelize.Parcelize -import javax.inject.Inject import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.update +import kotlinx.parcelize.Parcelize +import javax.inject.Inject @HiltViewModel class OrderDetailsViewModel @Inject constructor( From 2730a21ce2a17c8fcc9e076c45202b23eef1e215 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 14 May 2024 16:40:47 -0300 Subject: [PATCH 19/45] Add initial header structure for OrderDetailsScreen --- .../ui/orders/details/OrderDetailsScreen.kt | 58 +++++++++++++++---- 1 file changed, 48 insertions(+), 10 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt index a2e0e2ad56e..5ffc6d2de95 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt @@ -1,16 +1,25 @@ package com.woocommerce.android.ui.orders.details import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.wear.compose.material.TimeText import androidx.wear.tooling.preview.devices.WearDevices +import com.woocommerce.android.R import com.woocommerce.android.presentation.component.LoadingScreen import com.woocommerce.android.presentation.theme.WooTheme import com.woocommerce.android.ui.orders.ParseOrderData.OrderItem @@ -31,26 +40,55 @@ fun OrderDetailsScreen( order: OrderItem? ) { WooTheme { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, - modifier = modifier.fillMaxSize() + Box( + contentAlignment = Alignment.TopCenter, + modifier = modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .padding(16.dp) ) { when { isLoading -> LoadingScreen() order == null -> OrderLoadingFailed() - else -> OrderDetailsContent(order) + else -> OrderDetailsContent(order, modifier) } } } } @Composable -fun OrderDetailsContent(order: OrderItem) { - Text( - text = order.number, - color = Color.White - ) +fun OrderDetailsContent( + order: OrderItem, + modifier: Modifier +) { + Column { + Text( + text = order.date, + color = Color.White + ) + Text( + text = order.number, + color = Color.White + ) + Text( + text = order.customerName ?: stringResource(id = R.string.orders_list_guest_customer), + textAlign = TextAlign.Center, + color = Color.White + ) + Text( /* Needs proper handling */ + text = "3 Products", + textAlign = TextAlign.Center, + color = Color.White + ) + Text( + text = order.total, + color = Color.White + ) + Text( + text = order.status, + color = Color.White + ) + } } @Composable From 4c5ae03f1fd7947668658d2d8168a1d5bacc718a Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 14 May 2024 16:46:42 -0300 Subject: [PATCH 20/45] Add TimeText and text alignments --- .../ui/orders/details/OrderDetailsScreen.kt | 74 +++++++++++-------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt index 5ffc6d2de95..7c02444bb7f 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt @@ -1,7 +1,5 @@ package com.woocommerce.android.ui.orders.details -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding @@ -40,12 +38,14 @@ fun OrderDetailsScreen( order: OrderItem? ) { WooTheme { - Box( - contentAlignment = Alignment.TopCenter, + TimeText() + Column( + horizontalAlignment = Alignment.CenterHorizontally, modifier = modifier .fillMaxSize() .verticalScroll(rememberScrollState()) - .padding(16.dp) + .padding(top = 32.dp) + .padding(horizontal = 20.dp) ) { when { isLoading -> LoadingScreen() @@ -61,33 +61,43 @@ fun OrderDetailsContent( order: OrderItem, modifier: Modifier ) { - Column { - Text( - text = order.date, - color = Color.White - ) - Text( - text = order.number, - color = Color.White - ) - Text( - text = order.customerName ?: stringResource(id = R.string.orders_list_guest_customer), - textAlign = TextAlign.Center, - color = Color.White - ) - Text( /* Needs proper handling */ - text = "3 Products", - textAlign = TextAlign.Center, - color = Color.White - ) - Text( - text = order.total, - color = Color.White - ) - Text( - text = order.status, - color = Color.White - ) + Column(modifier = modifier.fillMaxSize()) { + Column( + modifier = modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = order.date, + color = Color.White + ) + Text( + text = order.number, + color = Color.White + ) + } + Column( + modifier = modifier.fillMaxSize(), + horizontalAlignment = Alignment.Start + ) { + Text( + text = order.customerName ?: stringResource(id = R.string.orders_list_guest_customer), + textAlign = TextAlign.Center, + color = Color.White + ) + Text( /* Needs proper handling */ + text = "3 Products", + textAlign = TextAlign.Center, + color = Color.White + ) + Text( + text = order.total, + color = Color.White + ) + Text( + text = order.status, + color = Color.White + ) + } } } From f15efc35199367994ab4194507f114cd943eeee7 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 14 May 2024 17:19:56 -0300 Subject: [PATCH 21/45] Centralize all format operations to the ParseOrderData --- .../woocommerce/android/ui/orders/ParseOrderData.kt | 11 ++++++++--- .../android/ui/orders/list/OrdersListScreen.kt | 6 ++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/ParseOrderData.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/ParseOrderData.kt index 6f47a20c3ea..2d04daa9bdb 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/ParseOrderData.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/ParseOrderData.kt @@ -1,6 +1,8 @@ package com.woocommerce.android.ui.orders +import android.content.Context import android.os.Parcelable +import com.woocommerce.android.R import com.woocommerce.android.util.DateUtils import kotlinx.parcelize.Parcelize import org.wordpress.android.fluxc.model.OrderEntity @@ -10,6 +12,7 @@ import java.util.Locale import javax.inject.Inject class ParseOrderData @Inject constructor( + private val context: Context, private val wooCommerceStore: WooCommerceStore, private val dateUtils: DateUtils, private val locale: Locale, @@ -40,16 +43,18 @@ class ParseOrderData @Inject constructor( val formattedBillingName = takeUnless { billingFirstName.isEmpty() && billingLastName.isEmpty() - }?.let { "$billingFirstName $billingLastName" } + }?.let { "$billingFirstName $billingLastName" } ?: context.getString(R.string.orders_list_guest_customer) val formattedStatus = status.replaceFirstChar { if (it.isLowerCase()) it.titlecase(locale) else it.toString() } + val formattedNumber = "#$number" + return OrderItem( id = orderId, date = formattedCreationDate, - number = number, + number = formattedNumber, customerName = formattedBillingName, total = formattedOrderTotals, status = formattedStatus @@ -61,7 +66,7 @@ class ParseOrderData @Inject constructor( val id: Long, val date: String, val number: String, - val customerName: String?, + val customerName: String, val total: String, val status: String ) : Parcelable diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListScreen.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListScreen.kt index ca2bb941855..8875def092f 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListScreen.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListScreen.kt @@ -127,14 +127,12 @@ fun OrderListItem( color = WooColors.woo_purple_20 ) Text( - text = "#${order.number}", + text = order.number, color = WooColors.woo_gray_alpha ) } Text( - text = order.customerName - ?.takeIf { it.isNotEmpty() } - ?: stringResource(id = R.string.orders_list_guest_customer), + text = order.customerName, style = WooTypography.body1, color = Color.White, textAlign = TextAlign.Start, From 67af8ca4dd1c379dd73417eabbd5785444735d27 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 14 May 2024 17:20:16 -0300 Subject: [PATCH 22/45] Add Text style to OrderDetailsScreen --- .../ui/orders/details/OrderDetailsScreen.kt | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt index 7c02444bb7f..9d07358151e 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt @@ -1,7 +1,9 @@ package com.woocommerce.android.ui.orders.details +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll @@ -11,15 +13,16 @@ import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.wear.compose.material.TimeText import androidx.wear.tooling.preview.devices.WearDevices -import com.woocommerce.android.R import com.woocommerce.android.presentation.component.LoadingScreen +import com.woocommerce.android.presentation.theme.WooColors import com.woocommerce.android.presentation.theme.WooTheme +import com.woocommerce.android.presentation.theme.WooTypography import com.woocommerce.android.ui.orders.ParseOrderData.OrderItem @Composable @@ -39,8 +42,8 @@ fun OrderDetailsScreen( ) { WooTheme { TimeText() - Column( - horizontalAlignment = Alignment.CenterHorizontally, + Box( + contentAlignment = Alignment.TopCenter, modifier = modifier .fillMaxSize() .verticalScroll(rememberScrollState()) @@ -80,9 +83,11 @@ fun OrderDetailsContent( horizontalAlignment = Alignment.Start ) { Text( - text = order.customerName ?: stringResource(id = R.string.orders_list_guest_customer), - textAlign = TextAlign.Center, - color = Color.White + text = order.customerName, + style = WooTypography.title3, + color = Color.White, + textAlign = TextAlign.Start, + modifier = Modifier.fillMaxWidth() ) Text( /* Needs proper handling */ text = "3 Products", @@ -91,11 +96,18 @@ fun OrderDetailsContent( ) Text( text = order.total, - color = Color.White + style = WooTypography.body1, + color = Color.White, + fontWeight = FontWeight.Bold, + textAlign = TextAlign.Start, + modifier = Modifier.fillMaxWidth() ) Text( text = order.status, - color = Color.White + style = WooTypography.caption1, + color = WooColors.woo_gray_alpha, + textAlign = TextAlign.Start, + modifier = Modifier.fillMaxWidth() ) } } From e894a296ca863867e6e96e189ccbf769e9298d04 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 14 May 2024 17:21:16 -0300 Subject: [PATCH 23/45] Rename ParseOrderData.kt to FormatOrderData --- .../ui/orders/{ParseOrderData.kt => FormatOrderData.kt} | 2 +- .../android/ui/orders/details/OrderDetailsScreen.kt | 2 +- .../android/ui/orders/details/OrderDetailsViewModel.kt | 8 ++++---- .../android/ui/orders/list/OrdersListScreen.kt | 2 +- .../android/ui/orders/list/OrdersListViewModel.kt | 8 ++++---- 5 files changed, 11 insertions(+), 11 deletions(-) rename WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/{ParseOrderData.kt => FormatOrderData.kt} (98%) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/ParseOrderData.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/FormatOrderData.kt similarity index 98% rename from WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/ParseOrderData.kt rename to WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/FormatOrderData.kt index 2d04daa9bdb..79ba76be92d 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/ParseOrderData.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/FormatOrderData.kt @@ -11,7 +11,7 @@ import org.wordpress.android.fluxc.store.WooCommerceStore import java.util.Locale import javax.inject.Inject -class ParseOrderData @Inject constructor( +class FormatOrderData @Inject constructor( private val context: Context, private val wooCommerceStore: WooCommerceStore, private val dateUtils: DateUtils, diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt index 9d07358151e..84be46115be 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt @@ -23,7 +23,7 @@ import com.woocommerce.android.presentation.component.LoadingScreen import com.woocommerce.android.presentation.theme.WooColors import com.woocommerce.android.presentation.theme.WooTheme import com.woocommerce.android.presentation.theme.WooTypography -import com.woocommerce.android.ui.orders.ParseOrderData.OrderItem +import com.woocommerce.android.ui.orders.FormatOrderData.OrderItem @Composable fun OrderDetailsScreen(viewModel: OrderDetailsViewModel) { diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt index b8ab4292438..83891d02f4b 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt @@ -6,8 +6,8 @@ import androidx.lifecycle.asLiveData import com.woocommerce.android.ui.NavArgs.ORDER_ID import com.woocommerce.android.ui.login.LoginRepository import com.woocommerce.android.ui.orders.OrdersRepository -import com.woocommerce.android.ui.orders.ParseOrderData -import com.woocommerce.android.ui.orders.ParseOrderData.OrderItem +import com.woocommerce.android.ui.orders.FormatOrderData +import com.woocommerce.android.ui.orders.FormatOrderData.OrderItem import com.woocommerce.commons.viewmodel.ScopedViewModel import com.woocommerce.commons.viewmodel.getStateFlow import dagger.hilt.android.lifecycle.HiltViewModel @@ -21,7 +21,7 @@ import javax.inject.Inject @HiltViewModel class OrderDetailsViewModel @Inject constructor( ordersRepository: OrdersRepository, - parseOrder: ParseOrderData, + formatOrder: FormatOrderData, loginRepository: LoginRepository, savedState: SavedStateHandle ) : ScopedViewModel(savedState) { @@ -38,7 +38,7 @@ class OrderDetailsViewModel @Inject constructor( .onEach { site -> savedState.get(ORDER_ID.key) ?.let { ordersRepository.getOrderFromId(site, it) } - ?.let { parseOrder(site, it) } + ?.let { formatOrder(site, it) } .let { presentOrderData(it) } }.launchIn(this) } diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListScreen.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListScreen.kt index 8875def092f..be75fb06231 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListScreen.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListScreen.kt @@ -33,7 +33,7 @@ import com.woocommerce.android.presentation.component.LoadingScreen import com.woocommerce.android.presentation.theme.WooColors import com.woocommerce.android.presentation.theme.WooTheme import com.woocommerce.android.presentation.theme.WooTypography -import com.woocommerce.android.ui.orders.ParseOrderData.OrderItem +import com.woocommerce.android.ui.orders.FormatOrderData.OrderItem @Composable fun OrdersListScreen(viewModel: OrdersListViewModel) { diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt index d0a24ea8031..a9d206e6dad 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt @@ -6,8 +6,8 @@ import androidx.lifecycle.asLiveData import androidx.navigation.NavHostController import com.woocommerce.android.ui.NavRoutes.ORDER_DETAILS import com.woocommerce.android.ui.login.LoginRepository -import com.woocommerce.android.ui.orders.ParseOrderData -import com.woocommerce.android.ui.orders.ParseOrderData.OrderItem +import com.woocommerce.android.ui.orders.FormatOrderData +import com.woocommerce.android.ui.orders.FormatOrderData.OrderItem import com.woocommerce.commons.viewmodel.ScopedViewModel import com.woocommerce.commons.viewmodel.getStateFlow import dagger.assisted.Assisted @@ -25,7 +25,7 @@ import org.wordpress.android.fluxc.model.SiteModel class OrdersListViewModel @AssistedInject constructor( @Assisted private val navController: NavHostController, private val fetchOrders: FetchOrders, - private val parseOrders: ParseOrderData, + private val formatOrders: FormatOrderData, loginRepository: LoginRepository, savedState: SavedStateHandle ) : ScopedViewModel(savedState) { @@ -52,7 +52,7 @@ class OrdersListViewModel @AssistedInject constructor( .onEach { orders -> _viewState.update { viewState -> viewState.copy( - orders = parseOrders(selectedSite, orders), + orders = formatOrders(selectedSite, orders), isLoading = false ) } From f37f78f518875f63bc6a676b09c91e7bb050df84 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 14 May 2024 17:29:45 -0300 Subject: [PATCH 24/45] Add Order Details string resources --- WooCommerce-Wear/src/main/res/values/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/WooCommerce-Wear/src/main/res/values/strings.xml b/WooCommerce-Wear/src/main/res/values/strings.xml index 066672f9ce4..6532d66ab48 100644 --- a/WooCommerce-Wear/src/main/res/values/strings.xml +++ b/WooCommerce-Wear/src/main/res/values/strings.xml @@ -15,6 +15,11 @@ Orders Guest + + 1 product + %1$d products + Failed to load order details + Example tile Example complication From 0499d55fe0724be8237c1e7cbf99c788a2b4b4df Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 14 May 2024 17:41:29 -0300 Subject: [PATCH 25/45] Fix lint issues --- .../android/ui/orders/details/OrderDetailsViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt index 83891d02f4b..78b6f15aa48 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsViewModel.kt @@ -5,9 +5,9 @@ import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.asLiveData import com.woocommerce.android.ui.NavArgs.ORDER_ID import com.woocommerce.android.ui.login.LoginRepository -import com.woocommerce.android.ui.orders.OrdersRepository import com.woocommerce.android.ui.orders.FormatOrderData import com.woocommerce.android.ui.orders.FormatOrderData.OrderItem +import com.woocommerce.android.ui.orders.OrdersRepository import com.woocommerce.commons.viewmodel.ScopedViewModel import com.woocommerce.commons.viewmodel.getStateFlow import dagger.hilt.android.lifecycle.HiltViewModel From 0bb1f30543519db2be590c5e5a666422c135ea5f Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 14 May 2024 18:02:48 -0300 Subject: [PATCH 26/45] Add Order Refunds fetching support --- .../android/ui/orders/OrdersRepository.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt index 0aa270fa2c6..5107d48941a 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt @@ -16,11 +16,13 @@ import org.wordpress.android.fluxc.model.OrderEntity import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.WCOrderStore import javax.inject.Inject +import org.wordpress.android.fluxc.store.WCRefundStore class OrdersRepository @Inject constructor( @DataStoreQualifier(DataStoreType.ORDERS) private val ordersDataStore: DataStore, private val loginRepository: LoginRepository, - private val orderStore: WCOrderStore + private val orderStore: WCOrderStore, + private val refundStore: WCRefundStore, ) { private val gson by lazy { Gson() } @@ -39,6 +41,14 @@ class OrdersRepository @Inject constructor( orderId = orderId ) + suspend fun fetchOrderRefunds( + selectedSite: SiteModel, + orderId: Long + ) = refundStore.fetchAllRefunds( + site = selectedSite, + orderId = orderId + ).takeIf { it.isError.not() }?.model + fun observeOrdersDataChanges() = ordersDataStore.data .mapNotNull { it[stringPreferencesKey(generateOrdersKey())] } .map { gson.fromJson(it, Array::class.java).toList() } From ae7834dd293eda2d9973b749063b9a5541b23055 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 15 May 2024 20:01:09 -0300 Subject: [PATCH 27/45] Fix lint issues --- .../java/com/woocommerce/android/ui/orders/OrdersRepository.kt | 2 +- .../woocommerce/android/ui/orders/details/OrderDetailsScreen.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt index 5107d48941a..7fcded1da5f 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt @@ -15,8 +15,8 @@ import kotlinx.coroutines.flow.mapNotNull import org.wordpress.android.fluxc.model.OrderEntity import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.WCOrderStore -import javax.inject.Inject import org.wordpress.android.fluxc.store.WCRefundStore +import javax.inject.Inject class OrdersRepository @Inject constructor( @DataStoreQualifier(DataStoreType.ORDERS) private val ordersDataStore: DataStore, diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt index 84be46115be..3aebe27ff7b 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/OrderDetailsScreen.kt @@ -89,7 +89,7 @@ fun OrderDetailsContent( textAlign = TextAlign.Start, modifier = Modifier.fillMaxWidth() ) - Text( /* Needs proper handling */ + Text( // Needs proper handling text = "3 Products", textAlign = TextAlign.Center, color = Color.White From fe280dfbb0587a030adaeb09a36ff4f304cbd1df Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 15 May 2024 22:59:40 -0300 Subject: [PATCH 28/45] Define WearOrderProduct type --- .../woocommerce/commons/wear/orders/WearOrderProduct.kt | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 libs/commons/src/main/java/com/woocommerce/commons/wear/orders/WearOrderProduct.kt diff --git a/libs/commons/src/main/java/com/woocommerce/commons/wear/orders/WearOrderProduct.kt b/libs/commons/src/main/java/com/woocommerce/commons/wear/orders/WearOrderProduct.kt new file mode 100644 index 00000000000..a19d34a560d --- /dev/null +++ b/libs/commons/src/main/java/com/woocommerce/commons/wear/orders/WearOrderProduct.kt @@ -0,0 +1,8 @@ +package com.woocommerce.commons.wear.orders + +data class WearOrderProduct( + val amount: String, + val imageUrl: String, + val total: String, + val name: String +) From 42a998931cc57b508f322d444a43718444281f49 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 15 May 2024 23:11:22 -0300 Subject: [PATCH 29/45] Introduce GetWearableOrderProducts operation --- .../android/wear/GetWearableOrderProducts.kt | 28 +++++++++++++++++++ .../commons/wear/orders/WearOrderProduct.kt | 1 - 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/wear/GetWearableOrderProducts.kt diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/GetWearableOrderProducts.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/GetWearableOrderProducts.kt new file mode 100644 index 00000000000..a074a5f95f1 --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/GetWearableOrderProducts.kt @@ -0,0 +1,28 @@ +package com.woocommerce.android.wear + +import com.woocommerce.android.model.getNonRefundedProducts +import com.woocommerce.android.ui.orders.details.OrderDetailRepository +import com.woocommerce.commons.wear.orders.WearOrderProduct +import javax.inject.Inject + +class GetWearableOrderProducts @Inject constructor( + private val orderDetailRepository: OrderDetailRepository +) { + suspend operator fun invoke( + orderId: Long + ): List { + val orderItems = orderDetailRepository + .fetchOrderById(orderId)?.items + ?: return emptyList() + + return orderDetailRepository.fetchOrderRefunds(orderId) + .getNonRefundedProducts(orderItems) + .map { + WearOrderProduct( + amount = it.quantity.toString(), + total = it.total.toString(), + name = it.name + ) + } + } +} diff --git a/libs/commons/src/main/java/com/woocommerce/commons/wear/orders/WearOrderProduct.kt b/libs/commons/src/main/java/com/woocommerce/commons/wear/orders/WearOrderProduct.kt index a19d34a560d..8b31423ff79 100644 --- a/libs/commons/src/main/java/com/woocommerce/commons/wear/orders/WearOrderProduct.kt +++ b/libs/commons/src/main/java/com/woocommerce/commons/wear/orders/WearOrderProduct.kt @@ -2,7 +2,6 @@ package com.woocommerce.commons.wear.orders data class WearOrderProduct( val amount: String, - val imageUrl: String, val total: String, val name: String ) From 5881da01ed06e16dd9ac76bd449ee8f9c11d1bd2 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 15 May 2024 23:12:26 -0300 Subject: [PATCH 30/45] Add Order Products support to Wearable Paths --- .../main/java/com/woocommerce/commons/wear/Paths.kt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/libs/commons/src/main/java/com/woocommerce/commons/wear/Paths.kt b/libs/commons/src/main/java/com/woocommerce/commons/wear/Paths.kt index 5eb26586076..7f29fa39a1f 100644 --- a/libs/commons/src/main/java/com/woocommerce/commons/wear/Paths.kt +++ b/libs/commons/src/main/java/com/woocommerce/commons/wear/Paths.kt @@ -3,13 +3,15 @@ package com.woocommerce.commons.wear enum class MessagePath(val value: String) { REQUEST_SITE("/request-site"), REQUEST_STATS("/request-stats"), - REQUEST_ORDERS("/request-orders") + REQUEST_ORDERS("/request-orders"), + REQUEST_ORDER_PRODUCTS("/request-order-products") } enum class DataPath(val value: String) { SITE_DATA("/site-data"), STATS_DATA("/stats-data"), - ORDERS_DATA("/orders-data") + ORDERS_DATA("/orders-data"), + ORDER_PRODUCTS_DATA("/order-products-data") } enum class DataParameters(val value: String) { @@ -26,5 +28,9 @@ enum class DataParameters(val value: String) { CONVERSION_RATE("conversion-rate"), // Orders data - ORDERS_JSON("orders-json") + ORDERS_JSON("orders-json"), + + // Order products data + ORDER_ID("order-id"), + ORDER_PRODUCTS_JSON("order-products-json") } From b1bd6784226401d643cf1d04849a0ed57d104f43 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 15 May 2024 23:21:10 -0300 Subject: [PATCH 31/45] Handle Order products request from WearOS --- .../wear/WearableConnectionRepository.kt | 23 ++++++++++++++++++- .../android/wear/WearableConnectionService.kt | 3 +++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionRepository.kt index d97b8bf9ded..38308557f43 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionRepository.kt @@ -2,19 +2,24 @@ package com.woocommerce.android.wear import com.google.android.gms.wearable.DataClient import com.google.android.gms.wearable.DataMap +import com.google.android.gms.wearable.MessageEvent import com.google.android.gms.wearable.PutDataMapRequest import com.google.gson.Gson import com.woocommerce.android.extensions.convertedFrom import com.woocommerce.android.tools.SelectedSite +import com.woocommerce.commons.wear.DataParameters import com.woocommerce.commons.wear.DataParameters.CONVERSION_RATE import com.woocommerce.commons.wear.DataParameters.ORDERS_COUNT import com.woocommerce.commons.wear.DataParameters.ORDERS_JSON +import com.woocommerce.commons.wear.DataParameters.ORDER_PRODUCTS_JSON import com.woocommerce.commons.wear.DataParameters.SITE_JSON import com.woocommerce.commons.wear.DataParameters.TIMESTAMP import com.woocommerce.commons.wear.DataParameters.TOKEN import com.woocommerce.commons.wear.DataParameters.TOTAL_REVENUE import com.woocommerce.commons.wear.DataParameters.VISITORS_TOTAL import com.woocommerce.commons.wear.DataPath +import com.woocommerce.commons.wear.DataPath.ORDERS_DATA +import com.woocommerce.commons.wear.DataPath.ORDER_PRODUCTS_DATA import com.woocommerce.commons.wear.DataPath.SITE_DATA import com.woocommerce.commons.wear.DataPath.STATS_DATA import kotlinx.coroutines.CoroutineScope @@ -34,6 +39,7 @@ class WearableConnectionRepository @Inject constructor( private val wooCommerceStore: WooCommerceStore, private val orderStore: WCOrderStore, private val getStats: GetWearableMyStoreStats, + private val getWearableOrderProducts: GetWearableOrderProducts, private val coroutineScope: CoroutineScope ) { private val gson by lazy { Gson() } @@ -83,13 +89,28 @@ class WearableConnectionRepository @Inject constructor( ).run { this as? Success }?.orders ?: emptyList() sendData( - DataPath.ORDERS_DATA, + ORDERS_DATA, DataMap().apply { putString(ORDERS_JSON.value, gson.toJson(orders)) } ) } + fun sendOrderProductsData(message: MessageEvent) = coroutineScope.launch { + val orderProductsJson = runCatching { message.data.toString().toLong() } + .getOrNull() + ?.let { getWearableOrderProducts(it) } + ?.let { gson.toJson(it) } + .orEmpty() + + sendData( + ORDER_PRODUCTS_DATA, + DataMap().apply { + putString(ORDER_PRODUCTS_JSON.value, orderProductsJson) + } + ) + } + private fun sendData( dataPath: DataPath, data: DataMap diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionService.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionService.kt index 4ede7f8f344..490bc969d8e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionService.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionService.kt @@ -2,7 +2,9 @@ package com.woocommerce.android.wear import com.google.android.gms.wearable.MessageEvent import com.google.android.gms.wearable.WearableListenerService +import com.woocommerce.commons.wear.MessagePath import com.woocommerce.commons.wear.MessagePath.REQUEST_ORDERS +import com.woocommerce.commons.wear.MessagePath.REQUEST_ORDER_PRODUCTS import com.woocommerce.commons.wear.MessagePath.REQUEST_SITE import com.woocommerce.commons.wear.MessagePath.REQUEST_STATS import dagger.hilt.android.AndroidEntryPoint @@ -20,6 +22,7 @@ class WearableConnectionService : WearableListenerService() { REQUEST_SITE.value -> wearableConnectionRepository.sendSiteData() REQUEST_STATS.value -> wearableConnectionRepository.sendStatsData() REQUEST_ORDERS.value -> wearableConnectionRepository.sendOrdersData() + REQUEST_ORDER_PRODUCTS.value -> wearableConnectionRepository.sendOrderProductsData(message) } } } From b281970d08792285d2a3e3e02e8c19cb6534c14a Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 15 May 2024 23:32:19 -0300 Subject: [PATCH 32/45] Add the Order ID looping back to the OrderProducts request --- .../android/wear/WearableConnectionRepository.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionRepository.kt index 38308557f43..7f94a355a42 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionRepository.kt @@ -11,6 +11,7 @@ import com.woocommerce.commons.wear.DataParameters import com.woocommerce.commons.wear.DataParameters.CONVERSION_RATE import com.woocommerce.commons.wear.DataParameters.ORDERS_COUNT import com.woocommerce.commons.wear.DataParameters.ORDERS_JSON +import com.woocommerce.commons.wear.DataParameters.ORDER_ID import com.woocommerce.commons.wear.DataParameters.ORDER_PRODUCTS_JSON import com.woocommerce.commons.wear.DataParameters.SITE_JSON import com.woocommerce.commons.wear.DataParameters.TIMESTAMP @@ -97,8 +98,9 @@ class WearableConnectionRepository @Inject constructor( } fun sendOrderProductsData(message: MessageEvent) = coroutineScope.launch { - val orderProductsJson = runCatching { message.data.toString().toLong() } - .getOrNull() + val orderId = runCatching { message.data.toString().toLong() }.getOrNull() + + val orderProductsJson = orderId ?.let { getWearableOrderProducts(it) } ?.let { gson.toJson(it) } .orEmpty() @@ -106,6 +108,7 @@ class WearableConnectionRepository @Inject constructor( sendData( ORDER_PRODUCTS_DATA, DataMap().apply { + putString(ORDER_ID.value, orderId?.toString().orEmpty()) putString(ORDER_PRODUCTS_JSON.value, orderProductsJson) } ) From 732f61430eee8ba7d53564903838d4dd31f41efe Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 15 May 2024 23:38:35 -0300 Subject: [PATCH 33/45] Receive and store Order Products data from phone --- .../android/phone/PhoneConnectionRepository.kt | 3 +++ .../android/ui/orders/OrdersRepository.kt | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/phone/PhoneConnectionRepository.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/phone/PhoneConnectionRepository.kt index 55a2a14c6c9..c0eb60c54da 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/phone/PhoneConnectionRepository.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/phone/PhoneConnectionRepository.kt @@ -8,7 +8,9 @@ import com.google.android.gms.wearable.MessageClient import com.woocommerce.android.ui.login.LoginRepository import com.woocommerce.android.ui.orders.OrdersRepository import com.woocommerce.android.ui.stats.datasource.StatsRepository +import com.woocommerce.commons.wear.DataPath import com.woocommerce.commons.wear.DataPath.ORDERS_DATA +import com.woocommerce.commons.wear.DataPath.ORDER_PRODUCTS_DATA import com.woocommerce.commons.wear.DataPath.SITE_DATA import com.woocommerce.commons.wear.DataPath.STATS_DATA import com.woocommerce.commons.wear.MessagePath @@ -38,6 +40,7 @@ class PhoneConnectionRepository @Inject constructor( SITE_DATA.value -> loginRepository.receiveStoreDataFromPhone(dataMap) STATS_DATA.value -> statsRepository.receiveStatsDataFromPhone(dataMap) ORDERS_DATA.value -> ordersRepository.receiveOrdersDataFromPhone(dataMap) + ORDER_PRODUCTS_DATA.value -> ordersRepository.receiveOrderProductsDataFromPhone(dataMap) else -> Log.d(TAG, "Unknown path data received") } } diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt index 7fcded1da5f..1bd86e7c9e2 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt @@ -10,6 +10,8 @@ import com.woocommerce.android.datastore.DataStoreQualifier import com.woocommerce.android.datastore.DataStoreType import com.woocommerce.android.ui.login.LoginRepository import com.woocommerce.commons.wear.DataParameters.ORDERS_JSON +import com.woocommerce.commons.wear.DataParameters.ORDER_ID +import com.woocommerce.commons.wear.DataParameters.ORDER_PRODUCTS_JSON import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapNotNull import org.wordpress.android.fluxc.model.OrderEntity @@ -61,11 +63,25 @@ class OrdersRepository @Inject constructor( } } + suspend fun receiveOrderProductsDataFromPhone(data: DataMap) { + val orderId = data.getLong(ORDER_ID.value, 0) + val productsJson = data.getString(ORDER_PRODUCTS_JSON.value, "") + + ordersDataStore.edit { prefs -> + prefs[stringPreferencesKey(generateProductsKey(orderId))] = productsJson + } + } + private fun generateOrdersKey(): String { val siteId = loginRepository.selectedSite?.siteId ?: 0 return "${ORDERS_KEY_PREFIX}:$siteId" } + private fun generateProductsKey(orderId: Long): String { + val siteId = loginRepository.selectedSite?.siteId ?: 0 + return "${ORDERS_KEY_PREFIX}:$siteId:$orderId" + } + companion object { private const val ORDERS_KEY_PREFIX = "store-orders" } From bf30bf81100ad2c00ac7ad6c14ebce53075c880e Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 15 May 2024 23:38:45 -0300 Subject: [PATCH 34/45] Refactor Order Products requests from WearableConnectionRepository --- .../android/wear/WearableConnectionRepository.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionRepository.kt index 7f94a355a42..06f9163600a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionRepository.kt @@ -7,7 +7,6 @@ import com.google.android.gms.wearable.PutDataMapRequest import com.google.gson.Gson import com.woocommerce.android.extensions.convertedFrom import com.woocommerce.android.tools.SelectedSite -import com.woocommerce.commons.wear.DataParameters import com.woocommerce.commons.wear.DataParameters.CONVERSION_RATE import com.woocommerce.commons.wear.DataParameters.ORDERS_COUNT import com.woocommerce.commons.wear.DataParameters.ORDERS_JSON @@ -40,7 +39,7 @@ class WearableConnectionRepository @Inject constructor( private val wooCommerceStore: WooCommerceStore, private val orderStore: WCOrderStore, private val getStats: GetWearableMyStoreStats, - private val getWearableOrderProducts: GetWearableOrderProducts, + private val getOrderProducts: GetWearableOrderProducts, private val coroutineScope: CoroutineScope ) { private val gson by lazy { Gson() } @@ -101,14 +100,14 @@ class WearableConnectionRepository @Inject constructor( val orderId = runCatching { message.data.toString().toLong() }.getOrNull() val orderProductsJson = orderId - ?.let { getWearableOrderProducts(it) } + ?.let { getOrderProducts(it) } ?.let { gson.toJson(it) } .orEmpty() sendData( ORDER_PRODUCTS_DATA, DataMap().apply { - putString(ORDER_ID.value, orderId?.toString().orEmpty()) + putLong(ORDER_ID.value, orderId ?: -1L) putString(ORDER_PRODUCTS_JSON.value, orderProductsJson) } ) From 86b3730606c2bcf68c40449f13042107f37d9ccb Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 15 May 2024 23:49:15 -0300 Subject: [PATCH 35/45] Introduce FlowUtils.kt --- .../com/woocommerce/android/util/FlowUtils.kt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 WooCommerce-Wear/src/main/java/com/woocommerce/android/util/FlowUtils.kt diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/util/FlowUtils.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/util/FlowUtils.kt new file mode 100644 index 00000000000..d3c11e96fb2 --- /dev/null +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/util/FlowUtils.kt @@ -0,0 +1,18 @@ +package com.woocommerce.android.util + +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flow + +const val TIMEOUT_MILLIS = 20000L +val timeoutFlow: Flow + get() = flow { + emit(false) + delay(TIMEOUT_MILLIS) + emit(true) + } + +fun Flow.combineWithTimeout( + transform: (data: T, isTimeout: Boolean) -> R +) = combine(this, timeoutFlow, transform) From 58e4a5bff59cefb187f6fe2dc2971a08524f47d5 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 15 May 2024 23:49:25 -0300 Subject: [PATCH 36/45] Refactor flow with timeout operations --- .../android/ui/login/ObserveLoginRequest.kt | 15 +--------- .../android/ui/orders/list/FetchOrders.kt | 29 ++++++------------- .../stats/datasource/FetchStatsFromPhone.kt | 14 ++------- 3 files changed, 12 insertions(+), 46 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/login/ObserveLoginRequest.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/login/ObserveLoginRequest.kt index 00a723d190f..19389a45786 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/login/ObserveLoginRequest.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/login/ObserveLoginRequest.kt @@ -3,10 +3,8 @@ package com.woocommerce.android.ui.login import com.woocommerce.android.ui.login.ObserveLoginRequest.LoginRequestState.Logged import com.woocommerce.android.ui.login.ObserveLoginRequest.LoginRequestState.Timeout import com.woocommerce.android.ui.login.ObserveLoginRequest.LoginRequestState.Waiting -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.Flow +import com.woocommerce.android.util.timeoutFlow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.flow import javax.inject.Inject class ObserveLoginRequest @Inject constructor( @@ -23,20 +21,9 @@ class ObserveLoginRequest @Inject constructor( } } - private val timeoutFlow: Flow - get() = flow { - emit(false) - delay(TIMEOUT_MILLIS) - emit(true) - } - enum class LoginRequestState { Logged, Waiting, Timeout } - - companion object { - const val TIMEOUT_MILLIS = 20000L - } } diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/FetchOrders.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/FetchOrders.kt index 98b20381891..35e637f501a 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/FetchOrders.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/FetchOrders.kt @@ -2,12 +2,10 @@ package com.woocommerce.android.ui.orders.list import com.woocommerce.android.phone.PhoneConnectionRepository import com.woocommerce.android.system.NetworkStatus -import com.woocommerce.android.ui.login.ObserveLoginRequest.Companion.TIMEOUT_MILLIS import com.woocommerce.android.ui.orders.OrdersRepository +import com.woocommerce.android.util.combineWithTimeout import com.woocommerce.commons.wear.MessagePath.REQUEST_ORDERS -import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.flow import org.wordpress.android.fluxc.model.OrderEntity @@ -22,16 +20,14 @@ class FetchOrders @Inject constructor( ) { suspend operator fun invoke( selectedSite: SiteModel - ): Flow> = combine( - selectOrdersDataSource(selectedSite), - timeoutFlow - ) { orders, isTimeout -> - when { - orders.isNotEmpty() -> orders - isTimeout -> emptyList() - else -> null - } - }.filterNotNull() + ): Flow> = selectOrdersDataSource(selectedSite) + .combineWithTimeout { orders, isTimeout -> + when { + orders.isNotEmpty() -> orders + isTimeout -> emptyList() + else -> null + } + }.filterNotNull() private suspend fun selectOrdersDataSource( selectedSite: SiteModel @@ -48,11 +44,4 @@ class FetchOrders @Inject constructor( return ordersRepository.observeOrdersDataChanges() } } - - private val timeoutFlow: Flow - get() = flow { - emit(false) - delay(TIMEOUT_MILLIS) - emit(true) - } } diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStatsFromPhone.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStatsFromPhone.kt index 827ab9adfb6..a5cfb392903 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStatsFromPhone.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStatsFromPhone.kt @@ -1,13 +1,10 @@ package com.woocommerce.android.ui.stats.datasource import com.woocommerce.android.phone.PhoneConnectionRepository -import com.woocommerce.android.ui.login.ObserveLoginRequest.Companion.TIMEOUT_MILLIS +import com.woocommerce.android.util.combineWithTimeout import com.woocommerce.commons.wear.MessagePath.REQUEST_STATS -import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.flow import javax.inject.Inject class FetchStatsFromPhone @Inject constructor( @@ -16,7 +13,7 @@ class FetchStatsFromPhone @Inject constructor( ) { suspend operator fun invoke(): Flow { phoneRepository.sendMessage(REQUEST_STATS) - return combine(statsRepository.observeStatsDataChanges(), timeoutFlow) { statsData, isTimeout -> + return statsRepository.observeStatsDataChanges().combineWithTimeout { statsData, isTimeout -> when { statsData?.isFinished == true -> statsData isTimeout -> StoreStatsRequest.Error @@ -24,11 +21,4 @@ class FetchStatsFromPhone @Inject constructor( } }.filterNotNull() } - - private val timeoutFlow: Flow - get() = flow { - emit(false) - delay(TIMEOUT_MILLIS) - emit(true) - } } From 5fd124778a909de6c506226ca151928083156f8b Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 15 May 2024 23:53:59 -0300 Subject: [PATCH 37/45] Rename FlowUtils to FlowExt.kt --- .../FlowUtils.kt => extensions/FlowExt.kt} | 2 +- .../android/ui/login/ObserveLoginRequest.kt | 19 ++++++++----------- .../android/ui/orders/OrdersRepository.kt | 8 -------- .../android/ui/orders/list/FetchOrders.kt | 2 +- .../stats/datasource/FetchStatsFromPhone.kt | 17 +++++++++-------- 5 files changed, 19 insertions(+), 29 deletions(-) rename WooCommerce-Wear/src/main/java/com/woocommerce/android/{util/FlowUtils.kt => extensions/FlowExt.kt} (91%) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/util/FlowUtils.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/extensions/FlowExt.kt similarity index 91% rename from WooCommerce-Wear/src/main/java/com/woocommerce/android/util/FlowUtils.kt rename to WooCommerce-Wear/src/main/java/com/woocommerce/android/extensions/FlowExt.kt index d3c11e96fb2..b2c3279b15f 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/util/FlowUtils.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/extensions/FlowExt.kt @@ -1,4 +1,4 @@ -package com.woocommerce.android.util +package com.woocommerce.android.extensions import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/login/ObserveLoginRequest.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/login/ObserveLoginRequest.kt index 19389a45786..d120a85a91e 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/login/ObserveLoginRequest.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/login/ObserveLoginRequest.kt @@ -1,25 +1,22 @@ package com.woocommerce.android.ui.login +import com.woocommerce.android.extensions.combineWithTimeout import com.woocommerce.android.ui.login.ObserveLoginRequest.LoginRequestState.Logged import com.woocommerce.android.ui.login.ObserveLoginRequest.LoginRequestState.Timeout import com.woocommerce.android.ui.login.ObserveLoginRequest.LoginRequestState.Waiting -import com.woocommerce.android.util.timeoutFlow -import kotlinx.coroutines.flow.combine import javax.inject.Inject class ObserveLoginRequest @Inject constructor( private val loginRepository: LoginRepository ) { - operator fun invoke() = combine( - loginRepository.isSiteAvailable, - timeoutFlow - ) { isSiteAvailable, isTimeout -> - when { - isSiteAvailable -> Logged - isTimeout.not() -> Waiting - else -> Timeout + operator fun invoke() = loginRepository.isSiteAvailable + .combineWithTimeout { isSiteAvailable, isTimeout -> + when { + isSiteAvailable -> Logged + isTimeout.not() -> Waiting + else -> Timeout + } } - } enum class LoginRequestState { Logged, diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt index 1bd86e7c9e2..6a3c07dce8c 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt @@ -43,14 +43,6 @@ class OrdersRepository @Inject constructor( orderId = orderId ) - suspend fun fetchOrderRefunds( - selectedSite: SiteModel, - orderId: Long - ) = refundStore.fetchAllRefunds( - site = selectedSite, - orderId = orderId - ).takeIf { it.isError.not() }?.model - fun observeOrdersDataChanges() = ordersDataStore.data .mapNotNull { it[stringPreferencesKey(generateOrdersKey())] } .map { gson.fromJson(it, Array::class.java).toList() } diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/FetchOrders.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/FetchOrders.kt index 35e637f501a..f22a5943f6e 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/FetchOrders.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/FetchOrders.kt @@ -1,9 +1,9 @@ package com.woocommerce.android.ui.orders.list +import com.woocommerce.android.extensions.combineWithTimeout import com.woocommerce.android.phone.PhoneConnectionRepository import com.woocommerce.android.system.NetworkStatus import com.woocommerce.android.ui.orders.OrdersRepository -import com.woocommerce.android.util.combineWithTimeout import com.woocommerce.commons.wear.MessagePath.REQUEST_ORDERS import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.filterNotNull diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStatsFromPhone.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStatsFromPhone.kt index a5cfb392903..7d97919a533 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStatsFromPhone.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStatsFromPhone.kt @@ -1,7 +1,7 @@ package com.woocommerce.android.ui.stats.datasource +import com.woocommerce.android.extensions.combineWithTimeout import com.woocommerce.android.phone.PhoneConnectionRepository -import com.woocommerce.android.util.combineWithTimeout import com.woocommerce.commons.wear.MessagePath.REQUEST_STATS import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.filterNotNull @@ -13,12 +13,13 @@ class FetchStatsFromPhone @Inject constructor( ) { suspend operator fun invoke(): Flow { phoneRepository.sendMessage(REQUEST_STATS) - return statsRepository.observeStatsDataChanges().combineWithTimeout { statsData, isTimeout -> - when { - statsData?.isFinished == true -> statsData - isTimeout -> StoreStatsRequest.Error - else -> null - } - }.filterNotNull() + return statsRepository.observeStatsDataChanges() + .combineWithTimeout { statsData, isTimeout -> + when { + statsData?.isFinished == true -> statsData + isTimeout -> StoreStatsRequest.Error + else -> null + } + }.filterNotNull() } } From cee29128e24acd7a83a86f0964003e51adf5623a Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 15 May 2024 23:54:06 -0300 Subject: [PATCH 38/45] Fix lint issues --- .../woocommerce/android/phone/PhoneConnectionRepository.kt | 1 - .../com/woocommerce/android/ui/orders/OrdersRepository.kt | 4 +--- .../com/woocommerce/android/wear/WearableConnectionService.kt | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/phone/PhoneConnectionRepository.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/phone/PhoneConnectionRepository.kt index c0eb60c54da..edaa6c1cfe3 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/phone/PhoneConnectionRepository.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/phone/PhoneConnectionRepository.kt @@ -8,7 +8,6 @@ import com.google.android.gms.wearable.MessageClient import com.woocommerce.android.ui.login.LoginRepository import com.woocommerce.android.ui.orders.OrdersRepository import com.woocommerce.android.ui.stats.datasource.StatsRepository -import com.woocommerce.commons.wear.DataPath import com.woocommerce.commons.wear.DataPath.ORDERS_DATA import com.woocommerce.commons.wear.DataPath.ORDER_PRODUCTS_DATA import com.woocommerce.commons.wear.DataPath.SITE_DATA diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt index 6a3c07dce8c..86e746ea9de 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt @@ -17,14 +17,12 @@ import kotlinx.coroutines.flow.mapNotNull import org.wordpress.android.fluxc.model.OrderEntity import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.WCOrderStore -import org.wordpress.android.fluxc.store.WCRefundStore import javax.inject.Inject class OrdersRepository @Inject constructor( @DataStoreQualifier(DataStoreType.ORDERS) private val ordersDataStore: DataStore, private val loginRepository: LoginRepository, - private val orderStore: WCOrderStore, - private val refundStore: WCRefundStore, + private val orderStore: WCOrderStore ) { private val gson by lazy { Gson() } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionService.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionService.kt index 490bc969d8e..ce4b5c49444 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionService.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionService.kt @@ -2,7 +2,6 @@ package com.woocommerce.android.wear import com.google.android.gms.wearable.MessageEvent import com.google.android.gms.wearable.WearableListenerService -import com.woocommerce.commons.wear.MessagePath import com.woocommerce.commons.wear.MessagePath.REQUEST_ORDERS import com.woocommerce.commons.wear.MessagePath.REQUEST_ORDER_PRODUCTS import com.woocommerce.commons.wear.MessagePath.REQUEST_SITE From 30e39f8dfaaa99e5204c9c2f8d9bfd719533d070 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 16 May 2024 00:10:22 -0300 Subject: [PATCH 39/45] Introduce FetchOrderProducts with data store observation from OrdersRepository --- .../android/ui/orders/OrdersRepository.kt | 15 ++++++--- .../ui/orders/details/FetchOrderProducts.kt | 31 +++++++++++++++++++ 2 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/FetchOrderProducts.kt diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt index 86e746ea9de..91371254f68 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/OrdersRepository.kt @@ -12,6 +12,7 @@ import com.woocommerce.android.ui.login.LoginRepository import com.woocommerce.commons.wear.DataParameters.ORDERS_JSON import com.woocommerce.commons.wear.DataParameters.ORDER_ID import com.woocommerce.commons.wear.DataParameters.ORDER_PRODUCTS_JSON +import com.woocommerce.commons.wear.orders.WearOrderProduct import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapNotNull import org.wordpress.android.fluxc.model.OrderEntity @@ -53,6 +54,15 @@ class OrdersRepository @Inject constructor( } } + private fun generateOrdersKey(): String { + val siteId = loginRepository.selectedSite?.siteId ?: 0 + return "${ORDERS_KEY_PREFIX}:$siteId" + } + + fun observeOrderProductsDataChanges(orderId: Long) = ordersDataStore.data + .mapNotNull { it[stringPreferencesKey(generateProductsKey(orderId))] } + .map { gson.fromJson(it, Array::class.java).toList() } + suspend fun receiveOrderProductsDataFromPhone(data: DataMap) { val orderId = data.getLong(ORDER_ID.value, 0) val productsJson = data.getString(ORDER_PRODUCTS_JSON.value, "") @@ -62,11 +72,6 @@ class OrdersRepository @Inject constructor( } } - private fun generateOrdersKey(): String { - val siteId = loginRepository.selectedSite?.siteId ?: 0 - return "${ORDERS_KEY_PREFIX}:$siteId" - } - private fun generateProductsKey(orderId: Long): String { val siteId = loginRepository.selectedSite?.siteId ?: 0 return "${ORDERS_KEY_PREFIX}:$siteId:$orderId" diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/FetchOrderProducts.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/FetchOrderProducts.kt new file mode 100644 index 00000000000..9843f42da39 --- /dev/null +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/FetchOrderProducts.kt @@ -0,0 +1,31 @@ +package com.woocommerce.android.ui.orders.details + +import com.woocommerce.android.extensions.combineWithTimeout +import com.woocommerce.android.phone.PhoneConnectionRepository +import com.woocommerce.android.ui.orders.OrdersRepository +import com.woocommerce.commons.wear.MessagePath.REQUEST_ORDER_PRODUCTS +import com.woocommerce.commons.wear.orders.WearOrderProduct +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.filterNotNull + +class FetchOrderProducts @Inject constructor( + private val phoneRepository: PhoneConnectionRepository, + private val ordersRepository: OrdersRepository +) { + suspend operator fun invoke(orderId: Long): Flow> { + phoneRepository.sendMessage( + REQUEST_ORDER_PRODUCTS, + orderId.toString().toByteArray() + ) + + return ordersRepository.observeOrderProductsDataChanges(orderId) + .combineWithTimeout { orderProducts, isTimeout -> + when { + orderProducts.isNotEmpty() -> orderProducts + isTimeout -> emptyList() + else -> null + } + }.filterNotNull() + } +} From f66a3e658725f36c6b989252450228371e981f8e Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 16 May 2024 00:13:44 -0300 Subject: [PATCH 40/45] Improve FetchOrderProducts with dedicated Request class --- .../ui/orders/details/FetchOrderProducts.kt | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/FetchOrderProducts.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/FetchOrderProducts.kt index 9843f42da39..4605f6326ed 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/FetchOrderProducts.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/details/FetchOrderProducts.kt @@ -3,17 +3,20 @@ package com.woocommerce.android.ui.orders.details import com.woocommerce.android.extensions.combineWithTimeout import com.woocommerce.android.phone.PhoneConnectionRepository import com.woocommerce.android.ui.orders.OrdersRepository +import com.woocommerce.android.ui.orders.details.FetchOrderProducts.OrderProductsRequest.Error +import com.woocommerce.android.ui.orders.details.FetchOrderProducts.OrderProductsRequest.Finished +import com.woocommerce.android.ui.orders.details.FetchOrderProducts.OrderProductsRequest.Waiting import com.woocommerce.commons.wear.MessagePath.REQUEST_ORDER_PRODUCTS import com.woocommerce.commons.wear.orders.WearOrderProduct -import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.filterNotNull +import javax.inject.Inject class FetchOrderProducts @Inject constructor( private val phoneRepository: PhoneConnectionRepository, private val ordersRepository: OrdersRepository ) { - suspend operator fun invoke(orderId: Long): Flow> { + suspend operator fun invoke(orderId: Long): Flow { phoneRepository.sendMessage( REQUEST_ORDER_PRODUCTS, orderId.toString().toByteArray() @@ -22,10 +25,16 @@ class FetchOrderProducts @Inject constructor( return ordersRepository.observeOrderProductsDataChanges(orderId) .combineWithTimeout { orderProducts, isTimeout -> when { - orderProducts.isNotEmpty() -> orderProducts - isTimeout -> emptyList() - else -> null + orderProducts.isNotEmpty() -> Finished(orderProducts) + isTimeout.not() -> Waiting + else -> Error } }.filterNotNull() } + + sealed class OrderProductsRequest { + data object Error : OrderProductsRequest() + data object Waiting : OrderProductsRequest() + data class Finished(val products: List) : OrderProductsRequest() + } } From 98fff0806b781e7c6609e3254856750fef6c8645 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 16 May 2024 00:16:21 -0300 Subject: [PATCH 41/45] Refactor FetchOrders to follow FetchOrderProducts strategy --- .../android/ui/orders/list/FetchOrders.kt | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/FetchOrders.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/FetchOrders.kt index f22a5943f6e..c58317de48f 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/FetchOrders.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/FetchOrders.kt @@ -4,6 +4,9 @@ import com.woocommerce.android.extensions.combineWithTimeout import com.woocommerce.android.phone.PhoneConnectionRepository import com.woocommerce.android.system.NetworkStatus import com.woocommerce.android.ui.orders.OrdersRepository +import com.woocommerce.android.ui.orders.list.FetchOrders.OrdersRequest.Error +import com.woocommerce.android.ui.orders.list.FetchOrders.OrdersRequest.Finished +import com.woocommerce.android.ui.orders.list.FetchOrders.OrdersRequest.Waiting import com.woocommerce.commons.wear.MessagePath.REQUEST_ORDERS import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.filterNotNull @@ -20,12 +23,12 @@ class FetchOrders @Inject constructor( ) { suspend operator fun invoke( selectedSite: SiteModel - ): Flow> = selectOrdersDataSource(selectedSite) + ): Flow = selectOrdersDataSource(selectedSite) .combineWithTimeout { orders, isTimeout -> when { - orders.isNotEmpty() -> orders - isTimeout -> emptyList() - else -> null + orders.isNotEmpty() -> Finished(orders) + isTimeout.not() -> Waiting + else -> Error } }.filterNotNull() @@ -44,4 +47,10 @@ class FetchOrders @Inject constructor( return ordersRepository.observeOrdersDataChanges() } } + + sealed class OrdersRequest { + data object Error : OrdersRequest() + data object Waiting : OrdersRequest() + data class Finished(val orders: List) : OrdersRequest() + } } From cb07d29779c52d76eb0411ba688aa6a84fe3a4c2 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 16 May 2024 00:43:34 -0300 Subject: [PATCH 42/45] Overhaul Store stats request structure --- .../ui/orders/list/OrdersListViewModel.kt | 19 +++++-- .../android/ui/stats/StoreStatsViewModel.kt | 34 +++++------- .../{FetchStatsFromStore.kt => FetchStats.kt} | 55 +++++++++++++++---- .../stats/datasource/FetchStatsFromPhone.kt | 25 --------- .../ui/stats/datasource/StatsRepository.kt | 6 +- .../ui/stats/datasource/StoreStatsData.kt | 27 +++++++++ .../ui/stats/datasource/StoreStatsRequest.kt | 31 ----------- .../ui/mystore/StoreStatsViewModelTest.kt | 20 ++----- 8 files changed, 104 insertions(+), 113 deletions(-) rename WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/{FetchStatsFromStore.kt => FetchStats.kt} (50%) delete mode 100644 WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStatsFromPhone.kt create mode 100644 WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/StoreStatsData.kt delete mode 100644 WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/StoreStatsRequest.kt diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt index a9d206e6dad..f4304b8ca1e 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt @@ -8,6 +8,8 @@ import com.woocommerce.android.ui.NavRoutes.ORDER_DETAILS import com.woocommerce.android.ui.login.LoginRepository import com.woocommerce.android.ui.orders.FormatOrderData import com.woocommerce.android.ui.orders.FormatOrderData.OrderItem +import com.woocommerce.android.ui.orders.list.FetchOrders.OrdersRequest.Finished +import com.woocommerce.android.ui.orders.list.FetchOrders.OrdersRequest.Waiting import com.woocommerce.commons.viewmodel.ScopedViewModel import com.woocommerce.commons.viewmodel.getStateFlow import dagger.assisted.Assisted @@ -49,13 +51,18 @@ class OrdersListViewModel @AssistedInject constructor( private suspend fun requestOrdersData(selectedSite: SiteModel) { _viewState.update { it.copy(isLoading = true) } fetchOrders(selectedSite) - .onEach { orders -> - _viewState.update { viewState -> - viewState.copy( - orders = formatOrders(selectedSite, orders), - isLoading = false - ) + .onEach { request -> + when (request) { + is Finished -> _viewState.update { viewState -> + viewState.copy( + orders = formatOrders(selectedSite, request.orders), + isLoading = false + ) + } + is Waiting -> _viewState.update { it.copy(isLoading = true) } + else -> _viewState.update { it.copy(isLoading = false) } } + }.launchIn(this) } diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/StoreStatsViewModel.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/StoreStatsViewModel.kt index 1a1dfbf5770..164007d263b 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/StoreStatsViewModel.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/StoreStatsViewModel.kt @@ -3,12 +3,11 @@ package com.woocommerce.android.ui.stats import android.os.Parcelable import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.asLiveData -import com.woocommerce.android.phone.PhoneConnectionRepository -import com.woocommerce.android.system.NetworkStatus import com.woocommerce.android.ui.login.LoginRepository -import com.woocommerce.android.ui.stats.datasource.FetchStatsFromPhone -import com.woocommerce.android.ui.stats.datasource.FetchStatsFromStore -import com.woocommerce.android.ui.stats.datasource.StoreStatsRequest +import com.woocommerce.android.ui.stats.datasource.FetchStats +import com.woocommerce.android.ui.stats.datasource.FetchStats.StoreStatsRequest +import com.woocommerce.android.ui.stats.datasource.FetchStats.StoreStatsRequest.Finished +import com.woocommerce.android.ui.stats.datasource.FetchStats.StoreStatsRequest.Waiting import com.woocommerce.commons.viewmodel.ScopedViewModel import com.woocommerce.commons.viewmodel.getStateFlow import dagger.hilt.android.lifecycle.HiltViewModel @@ -26,10 +25,8 @@ import javax.inject.Inject @HiltViewModel class StoreStatsViewModel @Inject constructor( - private val phoneRepository: PhoneConnectionRepository, - private val fetchStatsFromStore: FetchStatsFromStore, - private val fetchStatsFromPhone: FetchStatsFromPhone, - private val networkStatus: NetworkStatus, + private val fetchStats: FetchStats, + private val locale: Locale, loginRepository: LoginRepository, savedState: SavedStateHandle ) : ScopedViewModel(savedState) { @@ -40,7 +37,7 @@ class StoreStatsViewModel @Inject constructor( val viewState = _viewState.asLiveData() private val friendlyTimeFormat: SimpleDateFormat by lazy { - SimpleDateFormat("h:mm a", Locale.getDefault()) + SimpleDateFormat("h:mm a", locale) } init { @@ -52,24 +49,19 @@ class StoreStatsViewModel @Inject constructor( }.launchIn(this) } - private suspend fun evaluateStatsSource(selectedSite: SiteModel) = when { - networkStatus.isConnected() -> fetchStatsFromStore(selectedSite) - phoneRepository.isPhoneConnectionAvailable() -> fetchStatsFromPhone() - else -> error("No connection available") - } - private fun requestStoreStats(selectedSite: SiteModel) { _viewState.update { it.copy(isLoading = true) } launch { - evaluateStatsSource(selectedSite) + fetchStats(selectedSite) .onEach { handleStatsDataChange(it) } .launchIn(this) } } - private fun handleStatsDataChange(statsData: StoreStatsRequest?) { - when (statsData) { - is StoreStatsRequest.Data -> { + private fun handleStatsDataChange(request: StoreStatsRequest?) { + when (request) { + is Finished -> { + val statsData = request.data _viewState.update { it.copy( isLoading = false, @@ -81,7 +73,7 @@ class StoreStatsViewModel @Inject constructor( ) } } - + is Waiting -> _viewState.update { it.copy(isLoading = true) } else -> _viewState.update { it.copy(isLoading = false) } } } diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStatsFromStore.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStats.kt similarity index 50% rename from WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStatsFromStore.kt rename to WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStats.kt index 901a81f6f2e..f6ad3a50ec8 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStatsFromStore.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStats.kt @@ -1,6 +1,13 @@ package com.woocommerce.android.ui.stats.datasource -import com.woocommerce.android.ui.stats.datasource.StoreStatsRequest.Data.RevenueData +import com.woocommerce.android.extensions.combineWithTimeout +import com.woocommerce.android.phone.PhoneConnectionRepository +import com.woocommerce.android.system.NetworkStatus +import com.woocommerce.android.ui.stats.datasource.FetchStats.StoreStatsRequest.Error +import com.woocommerce.android.ui.stats.datasource.FetchStats.StoreStatsRequest.Finished +import com.woocommerce.android.ui.stats.datasource.FetchStats.StoreStatsRequest.Waiting +import com.woocommerce.android.ui.stats.datasource.StoreStatsData.RevenueData +import com.woocommerce.commons.wear.MessagePath import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine @@ -8,29 +15,47 @@ import kotlinx.coroutines.flow.filter import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.WooCommerceStore import javax.inject.Inject +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.map -class FetchStatsFromStore @Inject constructor( +class FetchStats @Inject constructor( private val statsRepository: StatsRepository, - private val wooCommerceStore: WooCommerceStore + private val phoneRepository: PhoneConnectionRepository, + private val wooCommerceStore: WooCommerceStore, + private val networkStatus: NetworkStatus ) { private val revenueStats = MutableStateFlow(null) private val visitorStats = MutableStateFlow(null) suspend operator fun invoke( selectedSite: SiteModel + ) = when { + networkStatus.isConnected() -> fetchStatsFromStore(selectedSite) + phoneRepository.isPhoneConnectionAvailable() -> fetchStatsFromPhone() + else -> error("No connection available") + } + + private suspend fun fetchStatsFromPhone(): Flow { + phoneRepository.sendMessage(MessagePath.REQUEST_STATS) + return statsRepository.observeStatsDataChanges() + .combineWithTimeout { statsData, isTimeout -> + when { + statsData?.isFinished == true -> Finished(statsData) + isTimeout.not() -> Waiting + else -> Error + } + }.filterNotNull() + } + + private suspend fun fetchStatsFromStore( + selectedSite: SiteModel ): Flow { fetchRevenueStats(selectedSite) fetchVisitorsStats(selectedSite) - return combine( - revenueStats, - visitorStats - ) { revenueStats, visitorStats -> - StoreStatsRequest.Data( - revenueData = revenueStats, - visitorData = visitorStats, - ) - }.filter { it.isFinished } + return combine(revenueStats, visitorStats) { revenue, visitors -> + StoreStatsData(revenue, visitors) + }.filter { it.isFinished }.map { Finished(it) } } private suspend fun fetchRevenueStats(selectedSite: SiteModel) { @@ -70,4 +95,10 @@ class FetchStatsFromStore @Inject constructor( } ) } + + sealed class StoreStatsRequest { + data object Error : StoreStatsRequest() + data object Waiting : StoreStatsRequest() + data class Finished(val data: StoreStatsData) : StoreStatsRequest() + } } diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStatsFromPhone.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStatsFromPhone.kt deleted file mode 100644 index 7d97919a533..00000000000 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStatsFromPhone.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.woocommerce.android.ui.stats.datasource - -import com.woocommerce.android.extensions.combineWithTimeout -import com.woocommerce.android.phone.PhoneConnectionRepository -import com.woocommerce.commons.wear.MessagePath.REQUEST_STATS -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.filterNotNull -import javax.inject.Inject - -class FetchStatsFromPhone @Inject constructor( - private val phoneRepository: PhoneConnectionRepository, - private val statsRepository: StatsRepository -) { - suspend operator fun invoke(): Flow { - phoneRepository.sendMessage(REQUEST_STATS) - return statsRepository.observeStatsDataChanges() - .combineWithTimeout { statsData, isTimeout -> - when { - statsData?.isFinished == true -> statsData - isTimeout -> StoreStatsRequest.Error - else -> null - } - }.filterNotNull() - } -} diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/StatsRepository.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/StatsRepository.kt index 66e2e02b8f8..4ed0f6d580f 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/StatsRepository.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/StatsRepository.kt @@ -9,7 +9,7 @@ import com.google.gson.Gson import com.woocommerce.android.datastore.DataStoreQualifier import com.woocommerce.android.datastore.DataStoreType import com.woocommerce.android.ui.login.LoginRepository -import com.woocommerce.android.ui.stats.datasource.StoreStatsRequest.Data.RevenueData +import com.woocommerce.android.ui.stats.datasource.StoreStatsData.RevenueData import com.woocommerce.android.ui.stats.range.TodayRangeData import com.woocommerce.android.util.DateUtils import com.woocommerce.commons.extensions.formatToYYYYmmDDhhmmss @@ -98,7 +98,7 @@ class StatsRepository @Inject constructor( } suspend fun receiveStatsDataFromPhone(data: DataMap) { - val statsJson = StoreStatsRequest.Data( + val statsJson = StoreStatsData( revenueData = RevenueData( totalRevenue = data.getString(TOTAL_REVENUE.value, ""), orderCount = data.getInt(ORDERS_COUNT.value, 0) @@ -113,7 +113,7 @@ class StatsRepository @Inject constructor( fun observeStatsDataChanges() = statsDataStore.data .mapNotNull { it[stringPreferencesKey(generateStatsKey())] } - .map { gson.fromJson(it, StoreStatsRequest.Data::class.java) } + .map { gson.fromJson(it, StoreStatsData::class.java) } private fun generateStatsKey(): String { val siteId = loginRepository.selectedSite?.siteId ?: 0 diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/StoreStatsData.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/StoreStatsData.kt new file mode 100644 index 00000000000..4b2a2266736 --- /dev/null +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/StoreStatsData.kt @@ -0,0 +1,27 @@ +package com.woocommerce.android.ui.stats.datasource + +import com.woocommerce.commons.extensions.convertedFrom + +data class StoreStatsData( + private val revenueData: RevenueData?, + private val visitorData: Int? +) { + val revenue get() = revenueData?.totalRevenue.orEmpty() + val ordersCount get() = revenueData?.orderCount ?: 0 + val visitorsCount get() = visitorData ?: 0 + val conversionRate: String + get() { + val ordersCount = revenueData?.orderCount ?: 0 + val visitorsCount = visitorData ?: 0 + return ordersCount convertedFrom visitorsCount + } + + val isFinished + get() = revenueData != null && + visitorData != null + + data class RevenueData( + val totalRevenue: String, + val orderCount: Int + ) +} diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/StoreStatsRequest.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/StoreStatsRequest.kt deleted file mode 100644 index 38f10b29b7c..00000000000 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/StoreStatsRequest.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.woocommerce.android.ui.stats.datasource - -import com.woocommerce.commons.extensions.convertedFrom - -sealed class StoreStatsRequest { - data class Data( - private val revenueData: RevenueData?, - private val visitorData: Int? - ) : StoreStatsRequest() { - val revenue get() = revenueData?.totalRevenue.orEmpty() - val ordersCount get() = revenueData?.orderCount ?: 0 - val visitorsCount get() = visitorData ?: 0 - val conversionRate: String - get() { - val ordersCount = revenueData?.orderCount ?: 0 - val visitorsCount = visitorData ?: 0 - return ordersCount convertedFrom visitorsCount - } - - val isFinished - get() = revenueData != null && - visitorData != null - - data class RevenueData( - val totalRevenue: String, - val orderCount: Int - ) - } - - data object Error : StoreStatsRequest() -} diff --git a/WooCommerce-Wear/src/test/java/com/woocommerce/android/ui/mystore/StoreStatsViewModelTest.kt b/WooCommerce-Wear/src/test/java/com/woocommerce/android/ui/mystore/StoreStatsViewModelTest.kt index 3f14a7cd5b2..465d15eb64e 100644 --- a/WooCommerce-Wear/src/test/java/com/woocommerce/android/ui/mystore/StoreStatsViewModelTest.kt +++ b/WooCommerce-Wear/src/test/java/com/woocommerce/android/ui/mystore/StoreStatsViewModelTest.kt @@ -1,14 +1,11 @@ package com.woocommerce.android.ui.mystore import androidx.lifecycle.SavedStateHandle -import androidx.navigation.NavHostController import com.woocommerce.android.BaseUnitTest -import com.woocommerce.android.phone.PhoneConnectionRepository -import com.woocommerce.android.system.NetworkStatus import com.woocommerce.android.ui.login.LoginRepository import com.woocommerce.android.ui.stats.StoreStatsViewModel -import com.woocommerce.android.ui.stats.datasource.FetchStatsFromPhone -import com.woocommerce.android.ui.stats.datasource.FetchStatsFromStore +import com.woocommerce.android.ui.stats.datasource.FetchStats +import java.util.Locale import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import org.assertj.core.api.Assertions.assertThat @@ -22,11 +19,7 @@ class StoreStatsViewModelTest : BaseUnitTest() { private lateinit var sut: StoreStatsViewModel private val loginRepository: LoginRepository = mock() - private val phoneRepository: PhoneConnectionRepository = mock() - private val fetchStatsFromStore: FetchStatsFromStore = mock() - private val fetchStatsFromPhone: FetchStatsFromPhone = mock() - private val networkStatus: NetworkStatus = mock() - private val navController: NavHostController = mock() + private val fetchStats: FetchStats = mock() @Test fun `when login changes, site data is updated`() = testBlocking { @@ -60,11 +53,8 @@ class StoreStatsViewModelTest : BaseUnitTest() { private fun createSut() { sut = StoreStatsViewModel( - navController, - phoneRepository, - fetchStatsFromStore, - fetchStatsFromPhone, - networkStatus, + fetchStats, + Locale.getDefault(), loginRepository, SavedStateHandle() ) From 8b4414c8937c0fb2d95902fa864710a4ffb6d626 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 16 May 2024 00:47:01 -0300 Subject: [PATCH 43/45] Improve Stats fetching even further --- .../android/ui/stats/datasource/FetchStats.kt | 15 ++++++++++----- .../android/ui/stats/datasource/StoreStatsData.kt | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStats.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStats.kt index f6ad3a50ec8..9898c5df6c9 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStats.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStats.kt @@ -11,12 +11,11 @@ import com.woocommerce.commons.wear.MessagePath import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.filter import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.WooCommerceStore import javax.inject.Inject import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.flowOf class FetchStats @Inject constructor( private val statsRepository: StatsRepository, @@ -32,7 +31,7 @@ class FetchStats @Inject constructor( ) = when { networkStatus.isConnected() -> fetchStatsFromStore(selectedSite) phoneRepository.isPhoneConnectionAvailable() -> fetchStatsFromPhone() - else -> error("No connection available") + else -> flowOf(Error) } private suspend fun fetchStatsFromPhone(): Flow { @@ -40,7 +39,7 @@ class FetchStats @Inject constructor( return statsRepository.observeStatsDataChanges() .combineWithTimeout { statsData, isTimeout -> when { - statsData?.isFinished == true -> Finished(statsData) + statsData?.isComplete == true -> Finished(statsData) isTimeout.not() -> Waiting else -> Error } @@ -55,7 +54,13 @@ class FetchStats @Inject constructor( return combine(revenueStats, visitorStats) { revenue, visitors -> StoreStatsData(revenue, visitors) - }.filter { it.isFinished }.map { Finished(it) } + }.combineWithTimeout { data, isTimeout -> + when { + data.isComplete -> Finished(data) + isTimeout.not() -> Waiting + else -> Error + } + }.filterNotNull() } private suspend fun fetchRevenueStats(selectedSite: SiteModel) { diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/StoreStatsData.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/StoreStatsData.kt index 4b2a2266736..c21935f4971 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/StoreStatsData.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/StoreStatsData.kt @@ -16,7 +16,7 @@ data class StoreStatsData( return ordersCount convertedFrom visitorsCount } - val isFinished + val isComplete get() = revenueData != null && visitorData != null From d80c0c5cb6470ec3243f40d3f13d46366ac36a2f Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 16 May 2024 00:50:50 -0300 Subject: [PATCH 44/45] Enforce site cohesion inside StatsRepository --- .../android/ui/orders/list/OrdersListViewModel.kt | 1 - .../android/ui/stats/datasource/FetchStats.kt | 12 +++++++----- .../android/ui/stats/datasource/StatsRepository.kt | 12 +++++++----- .../android/ui/mystore/StoreStatsViewModelTest.kt | 2 +- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt index f4304b8ca1e..9b3b5a8baeb 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/orders/list/OrdersListViewModel.kt @@ -62,7 +62,6 @@ class OrdersListViewModel @AssistedInject constructor( is Waiting -> _viewState.update { it.copy(isLoading = true) } else -> _viewState.update { it.copy(isLoading = false) } } - }.launchIn(this) } diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStats.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStats.kt index 9898c5df6c9..65933bd9a09 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStats.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/FetchStats.kt @@ -11,11 +11,11 @@ import com.woocommerce.commons.wear.MessagePath import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.flowOf import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.WooCommerceStore import javax.inject.Inject -import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.flowOf class FetchStats @Inject constructor( private val statsRepository: StatsRepository, @@ -30,13 +30,15 @@ class FetchStats @Inject constructor( selectedSite: SiteModel ) = when { networkStatus.isConnected() -> fetchStatsFromStore(selectedSite) - phoneRepository.isPhoneConnectionAvailable() -> fetchStatsFromPhone() + phoneRepository.isPhoneConnectionAvailable() -> fetchStatsFromPhone(selectedSite) else -> flowOf(Error) } - private suspend fun fetchStatsFromPhone(): Flow { + private suspend fun fetchStatsFromPhone( + selectedSite: SiteModel + ): Flow { phoneRepository.sendMessage(MessagePath.REQUEST_STATS) - return statsRepository.observeStatsDataChanges() + return statsRepository.observeStatsDataChanges(selectedSite) .combineWithTimeout { statsData, isTimeout -> when { statsData?.isComplete == true -> Finished(statsData) diff --git a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/StatsRepository.kt b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/StatsRepository.kt index 4ed0f6d580f..953851311c3 100644 --- a/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/StatsRepository.kt +++ b/WooCommerce-Wear/src/main/java/com/woocommerce/android/ui/stats/datasource/StatsRepository.kt @@ -107,16 +107,18 @@ class StatsRepository @Inject constructor( ).let { gson.toJson(it) } statsDataStore.edit { prefs -> - prefs[stringPreferencesKey(generateStatsKey())] = statsJson + val siteId = loginRepository.selectedSite?.siteId ?: 0 + prefs[stringPreferencesKey(generateStatsKey(siteId))] = statsJson } } - fun observeStatsDataChanges() = statsDataStore.data - .mapNotNull { it[stringPreferencesKey(generateStatsKey())] } + fun observeStatsDataChanges( + selectedSite: SiteModel + ) = statsDataStore.data + .mapNotNull { it[stringPreferencesKey(generateStatsKey(selectedSite.siteId))] } .map { gson.fromJson(it, StoreStatsData::class.java) } - private fun generateStatsKey(): String { - val siteId = loginRepository.selectedSite?.siteId ?: 0 + private fun generateStatsKey(siteId: Long): String { return "$STATS_KEY_PREFIX:$siteId" } diff --git a/WooCommerce-Wear/src/test/java/com/woocommerce/android/ui/mystore/StoreStatsViewModelTest.kt b/WooCommerce-Wear/src/test/java/com/woocommerce/android/ui/mystore/StoreStatsViewModelTest.kt index 465d15eb64e..f117452ff06 100644 --- a/WooCommerce-Wear/src/test/java/com/woocommerce/android/ui/mystore/StoreStatsViewModelTest.kt +++ b/WooCommerce-Wear/src/test/java/com/woocommerce/android/ui/mystore/StoreStatsViewModelTest.kt @@ -5,7 +5,6 @@ import com.woocommerce.android.BaseUnitTest import com.woocommerce.android.ui.login.LoginRepository import com.woocommerce.android.ui.stats.StoreStatsViewModel import com.woocommerce.android.ui.stats.datasource.FetchStats -import java.util.Locale import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import org.assertj.core.api.Assertions.assertThat @@ -13,6 +12,7 @@ import org.junit.Test import org.mockito.kotlin.mock import org.mockito.kotlin.whenever import org.wordpress.android.fluxc.model.SiteModel +import java.util.Locale @ExperimentalCoroutinesApi class StoreStatsViewModelTest : BaseUnitTest() { From 1345b1a338746f0eb7f5d37a862b84532171fdbf Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 16 May 2024 01:51:10 -0300 Subject: [PATCH 45/45] Add missing fixes for the Order Products request --- WooCommerce-Wear/src/main/AndroidManifest.xml | 8 ++++++++ WooCommerce/src/main/AndroidManifest.xml | 8 ++++++++ .../android/wear/WearableConnectionRepository.kt | 4 +++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/WooCommerce-Wear/src/main/AndroidManifest.xml b/WooCommerce-Wear/src/main/AndroidManifest.xml index 31b0cfd5552..69931c330a8 100644 --- a/WooCommerce-Wear/src/main/AndroidManifest.xml +++ b/WooCommerce-Wear/src/main/AndroidManifest.xml @@ -55,6 +55,14 @@ android:pathPrefix="/orders-data" android:scheme="wear" /> + + + + + + + + + + diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionRepository.kt index 06f9163600a..691d2d7957a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/wear/WearableConnectionRepository.kt @@ -97,7 +97,9 @@ class WearableConnectionRepository @Inject constructor( } fun sendOrderProductsData(message: MessageEvent) = coroutineScope.launch { - val orderId = runCatching { message.data.toString().toLong() }.getOrNull() + val orderId = runCatching { + message.data.toString(Charsets.UTF_8).toLong() + }.getOrNull() val orderProductsJson = orderId ?.let { getOrderProducts(it) }