Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[Shipping Labels Revamp] Update Carrier and Saved packages data for better state control #13104

Merged
merged 17 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@ import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingL
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.PageType.CARRIER
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.PageType.CUSTOM
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.PageType.SAVED
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.Carrier
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.CarrierPackageGroup
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.PackageData
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.WooShippingCarrierPackageContent
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.WooShippingCarrierPackageScreen
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.WooShippingCustomPackageCreationScreen
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.WooShippingSavedPackageContent
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.WooShippingSavedPackageScreen

@Composable
Expand Down Expand Up @@ -128,7 +132,7 @@ fun WooShippingLabelsPackageCreationScreenPreview() {
)
},
createSavedPackageScreen = {
WooShippingSavedPackageScreen(
WooShippingSavedPackageContent(
savedPackages = listOf(
PackageData(
name = "Small Flat Rate Box",
Expand Down Expand Up @@ -157,7 +161,74 @@ fun WooShippingLabelsPackageCreationScreenPreview() {
onSavedPackageSelected = { _, _ -> }
)
},
createCarrierPackageScreen = { }
createCarrierPackageScreen = {
WooShippingCarrierPackageContent(
carrierPackages = mapOf(
Carrier.DHL to listOf(
CarrierPackageGroup(
groupName = "Group 1",
packages = listOf(
PackageData(
name = "Package 1 - Carrier 1",
dimensions = "10 x 10 x 10",
weight = "10",
isSelected = false,
isLetter = false
),
PackageData(
name = "Package 2 - Carrier 1",
dimensions = "20 x 20 x 20",
weight = "20",
isSelected = false,
isLetter = false
)
)
),
CarrierPackageGroup(
groupName = "Group 2",
packages = listOf(
PackageData(
name = "Package 3 - Carrier 1",
dimensions = "30 x 30 x 30",
weight = "30",
isSelected = false,
isLetter = false
),
PackageData(
name = "Package 4 - Carrier 1",
dimensions = "40 x 40 x 40",
weight = "40",
isSelected = false,
isLetter = false
)
)
)
),
Carrier.USPS to listOf(
CarrierPackageGroup(
groupName = "Group 2",
packages = listOf(
PackageData(
name = "Package 1 - Carrier 2",
dimensions = "10 x 10 x 10",
weight = "10",
isSelected = false,
isLetter = false
),
PackageData(
name = "Package 2 Carrier - 2",
dimensions = "20 x 20 x 20",
weight = "20",
isSelected = false,
isLetter = false
)
)
)
)
),
onPackageSelected = { _, _ -> }
)
}
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,8 @@ import com.woocommerce.android.ui.orders.wooshippinglabels.packages.datasource.W
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.networking.CustomPackageCreationRequestData
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.Carrier
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.CarrierPackageGroup
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.CarrierPackageSelection
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.CustomPackageCreationData
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.PackageData
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.SavedPackageSelection
import com.woocommerce.android.viewmodel.MultiLiveEvent
import com.woocommerce.android.viewmodel.ResourceProvider
import com.woocommerce.android.viewmodel.ScopedViewModel
Expand Down Expand Up @@ -59,47 +57,50 @@ class WooShippingLabelPackageCreationViewModel @Inject constructor(

init {
launch {
fetchPredefinedPackages()?.let {
fetchPredefinedPackages().let { response ->
_viewState.update { viewState ->
viewState.copy(
savedPackageSelection = it.savedPackageSelection,
carrierPackageSection = it.carrierPackageSelection
)
viewState.copy(predefinedPackagesState = response)
}
}
}
}

fun onCarrierPackageSelected(selectedPackage: PackageData, isSelected: Boolean) {
_viewState.update { viewState ->
viewState.carrierPackageSection.carrierPackages
.map { updateCarrierPackagesSelection(it, selectedPackage, isSelected) }
.let { viewState.copy(carrierPackageSection = CarrierPackageSelection(it.toMap())) }
val predefinedPackages = viewState.predefinedPackagesData
predefinedPackages?.carrierPackages
?.map { updateCarrierPackagesSelection(it, selectedPackage, isSelected) }
?.let {
viewState.copy(predefinedPackagesState = predefinedPackages.copy(carrierPackages = it.toMap()))
} ?: _viewState.value
}
}

fun onSavedPackageSelected(selectedPackage: PackageData, isSelected: Boolean) {
_viewState.update { viewState ->
viewState.savedPackageSelection.packages
.map { it.copy(isSelected = false) }
.toMutableList()
.safelyUpdate(selectedPackage, selectedPackage.copy(isSelected = isSelected))
.let { SavedPackageSelection(it) }
.let { viewState.copy(savedPackageSelection = it) }
val predefinedPackages = viewState.predefinedPackagesData
predefinedPackages?.savedPackages
?.map { it.copy(isSelected = false) }
?.toMutableList()
?.safelyUpdate(selectedPackage, selectedPackage.copy(isSelected = isSelected))
?.let { viewState.copy(predefinedPackagesState = predefinedPackages.copy(savedPackages = it)) }
?: _viewState.value
}
}

fun onAddCarrierPackageClick() {
_viewState.value.carrierPackageSection.carrierPackages
.asSequence()
.flatMap { it.value }
.flatMap { it.packages }
.find { it.isSelected }
_viewState.value.predefinedPackagesData?.carrierPackages
?.asSequence()
?.flatMap { it.value }
?.flatMap { it.packages }
?.find { it.isSelected }
?.let { triggerEvent(PackageSelected(it)) }
}

fun onAddSavedPackageClick() {
_viewState.value.savedPackageSelection.packages.find { it.isSelected }
_viewState.value.predefinedPackagesData
?.savedPackages
?.find { it.isSelected }
?.let { triggerEvent(PackageSelected(it)) }
}

Expand Down Expand Up @@ -209,9 +210,29 @@ class WooShippingLabelPackageCreationViewModel @Inject constructor(
data class ViewState(
val pageTabs: List<PageTab> = emptyList(),
val customPackageCreationData: CustomPackageCreationData = CustomPackageCreationData.EMPTY,
val savedPackageSelection: SavedPackageSelection = SavedPackageSelection(emptyList()),
val carrierPackageSection: CarrierPackageSelection = CarrierPackageSelection(emptyMap())
) : Parcelable
val predefinedPackagesState: PredefinedPackagesState = PredefinedPackagesState.Waiting,
) : Parcelable {
val predefinedPackagesData
get() = (predefinedPackagesState as? PredefinedPackagesState.Data)
}

@Parcelize
sealed class PredefinedPackagesState : Parcelable {
data object Error : PredefinedPackagesState()
data object Waiting : PredefinedPackagesState()
data class Data(
val savedPackages: List<PackageData> = emptyList(),
val carrierPackages: Map<Carrier, List<CarrierPackageGroup>> = emptyMap()
) : PredefinedPackagesState() {
val hasCarrierSelection: Boolean
get() = carrierPackages.values.flatten().find { group ->
group.packages.find { it.isSelected } != null
} != null

val hasSavedSelection: Boolean
get() = savedPackages.find { it.isSelected } != null
}
}

@Parcelize
data class PageTab(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.Divider
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
Expand All @@ -13,13 +16,16 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.woocommerce.android.R
import com.woocommerce.android.ui.compose.animations.SkeletonView
import com.woocommerce.android.ui.compose.component.SelectionCheck
import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.PackageData

@Composable
fun WooSavedPackageListItem(
fun WooShippingPackageListItem(
modifier: Modifier,
packageData: PackageData,
onPackageSelected: (PackageData, Boolean) -> Unit
Expand Down Expand Up @@ -60,3 +66,68 @@ fun WooSavedPackageListItem(
Divider()
}
}

@Composable
fun WooShippingPackageListItemSkeleton(
modifier: Modifier = Modifier
) {
Column(
modifier = modifier
.padding(top = 8.dp)
.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalAlignment = Alignment.CenterVertically
) {
SkeletonView(
modifier = Modifier.size(24.dp)
)
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
SkeletonView(
modifier = Modifier
.height(16.dp)
.fillMaxWidth(0.5f)
)
SkeletonView(
modifier = Modifier
.height(20.dp)
.fillMaxWidth(0.7f)
)
SkeletonView(
modifier = Modifier
.height(16.dp)
.fillMaxWidth(0.6f)
)
}
}
Divider()
}
}

@Preview
@Composable
fun WooSavedPackageListItemPreview() {
WooThemeWithBackground {
WooShippingPackageListItem(
modifier = Modifier,
packageData = PackageData(
name = "Small Flat Rate Box",
dimensions = "5 x 5 x 5",
weight = "1.5",
isLetter = false,
isSelected = false
),
onPackageSelected = { _, _ -> }
)
}
}

@Preview
@Composable
fun WooSavedPackageListItemSkeletonPreview() {
WooThemeWithBackground {
WooShippingPackageListItemSkeleton()
}
}
Original file line number Diff line number Diff line change
@@ -1,32 +1,26 @@
package com.woocommerce.android.ui.orders.wooshippinglabels.packages.datasource

import com.woocommerce.android.tools.SelectedSite
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.PredefinedPackagesState
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.Carrier
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.CarrierPackageGroup
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.CarrierPackageSelection
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.PackageData
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.SavedPackageSelection
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.StorePredefinedPackages
import javax.inject.Inject

class FetchPredefinedPackagesFromStore @Inject constructor(
private val selectedSite: SelectedSite,
private val packageRepository: WooShippingLabelPackageRepository
) {
suspend operator fun invoke(): StorePredefinedPackages? {
suspend operator fun invoke(): PredefinedPackagesState {
val storePackages = selectedSite.getOrNull()
?.let { packageRepository.fetchAllStorePackages(it) }
?.takeIf { it.isError.not() }
?.model
?: return null
?: return PredefinedPackagesState.Error

return StorePredefinedPackages(
savedPackageSelection = storePackages
.filterSavedData()
.let { SavedPackageSelection(it) },
carrierPackageSelection = storePackages
.filterCarrierData()
.let { CarrierPackageSelection(it) }
return PredefinedPackagesState.Data(
savedPackages = storePackages.filterSavedData(),
carrierPackages = storePackages.filterCarrierData()
)
}

Expand Down
Loading
Loading