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

Split shipment instructions #13828

Open
wants to merge 9 commits into
base: issue/13699-split-shipment-products-ui
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 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 @@ -16,7 +16,6 @@ import androidx.compose.foundation.shape.CornerSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Card
import androidx.compose.material.Colors
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
Expand All @@ -29,6 +28,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
Expand All @@ -37,12 +37,6 @@ import androidx.compose.ui.unit.sp
import com.woocommerce.android.R
import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground

@Suppress("MagicNumber")
val Colors.feedbackSurface: Color get() = if (isLight) Color(0xFF1C1C1E) else Color(0xFFB999FF)

@Suppress("MagicNumber")
val Colors.onFeedbackSurface: Color get() = if (isLight) Color(0xFFB999FF) else Color(0xFF1C1C1E)

@Composable
fun FeedbackDialog(
title: String,
Expand All @@ -55,7 +49,7 @@ fun FeedbackDialog(
) {
val colorStops = arrayOf(
.6f to Color.Transparent,
1f to MaterialTheme.colors.feedbackSurface.copy(alpha = .4f),
1f to colorResource(R.color.woo_message_surface).copy(alpha = .4f),
)

Box(modifier = modifier) {
Expand All @@ -80,7 +74,7 @@ fun FeedbackDialog(
modifier = Modifier.align(Alignment.BottomCenter)
) {
Card(
backgroundColor = MaterialTheme.colors.feedbackSurface,
backgroundColor = colorResource(R.color.woo_message_surface),
modifier = Modifier.padding(16.dp),
shape = RoundedCornerShape(corner = CornerSize(8.dp))
) {
Expand Down Expand Up @@ -109,7 +103,7 @@ fun FeedbackDialog(
icon = Icons.Outlined.Reviews,
text = action,
colors = ButtonDefaults
.textButtonColors(contentColor = MaterialTheme.colors.onFeedbackSurface),
.textButtonColors(contentColor = colorResource(R.color.woo_message_on_surface)),
modifier = Modifier.padding(start = 4.dp)

)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
package com.woocommerce.android.ui.orders.wooshippinglabels.split

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CornerSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Card

Check warning

Code scanning / Android Lint

material and material3 are separate, incompatible design system libraries Warning

Using a material import while also using the material3 library
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme

Check warning

Code scanning / Android Lint

material and material3 are separate, incompatible design system libraries Warning

Using a material import while also using the material3 library
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
Expand All @@ -19,9 +29,15 @@
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
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.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import com.woocommerce.android.R
import com.woocommerce.android.ui.compose.component.WCTextButton
Expand All @@ -39,6 +55,7 @@
WooShippingSplitShipmentScreen(
viewState = it,
onBack = viewModel::onNavigateBack,
onDismissInstructions = viewModel::onDismissInstructions,
modifier = modifier
)
}
Expand All @@ -48,6 +65,7 @@
fun WooShippingSplitShipmentScreen(
viewState: SplitShipmentViewState,
onBack: () -> Unit,
onDismissInstructions: () -> Unit,
modifier: Modifier = Modifier
) {
Scaffold(
Expand All @@ -74,64 +92,135 @@
) { padding ->
val shipment = viewState.selectableItems.values.first()
Surface(
modifier = modifier.fillMaxSize()
modifier = modifier
.padding(padding)
.fillMaxSize()
) {
Column(
modifier = Modifier
.padding(padding)
Box(
modifier
.fillMaxSize()
.padding(16.dp)
) {
ProductsSummary(
totalItems = shipment.shippableItems.size,
totalWeight = shipment.formattedTotalWeight,
totalPrice = shipment.formattedTotalPrice,
modifier = modifier.padding(top = 8.dp, bottom = 8.dp)
)
Column {
ProductsSummary(
totalItems = shipment.shippableItems.size,
totalWeight = shipment.formattedTotalWeight,
totalPrice = shipment.formattedTotalPrice,
modifier = modifier.padding(top = 8.dp, bottom = 8.dp)
)

LazyColumn {
items(
items = shipment.shippableItems,
) { shippableItem ->
var selection by remember { mutableStateOf(false) }
when (shippableItem) {
is SelectableShippableItemUI.SingleSelectableShippableItemUI -> {
SelectableShippingProduct(
title = shippableItem.shippableItem.title,
description = shippableItem.shippableItem.formattedSize,
weight = shippableItem.shippableItem.formattedWeight,
price = shippableItem.shippableItem.formattedPrice,
quantity = shippableItem.shippableItem.quantity,
imageUrl = shippableItem.shippableItem.imageUrl,
isSelected = selection,
onSelectionChange = { selection = !selection },
modifier = Modifier.padding(vertical = 8.dp)
)
}

LazyColumn {
items(
items = shipment.shippableItems,
) { shippableItem ->
var selection by remember { mutableStateOf(false) }
when (shippableItem) {
is SelectableShippableItemUI.SingleSelectableShippableItemUI -> {
SelectableShippingProduct(
title = shippableItem.shippableItem.title,
description = shippableItem.shippableItem.formattedSize,
weight = shippableItem.shippableItem.formattedWeight,
price = shippableItem.shippableItem.formattedPrice,
quantity = shippableItem.shippableItem.quantity,
imageUrl = shippableItem.shippableItem.imageUrl,
isSelected = selection,
onSelectionChange = { selection = !selection },
modifier = Modifier.padding(vertical = 8.dp)
)
is SelectableShippableItemUI.ExpandableSelectableShippableItemUI -> {
var expanded by remember { mutableStateOf(false) }
ExpandableSelectableShippingProduct(
title = shippableItem.shippableItem.title,
description = shippableItem.shippableItem.formattedSize,
weight = shippableItem.shippableItem.formattedWeight,
price = shippableItem.shippableItem.formattedPrice,
quantity = shippableItem.shippableItem.quantity,
imageUrl = shippableItem.shippableItem.imageUrl,
isSelected = selection,
onSelectionChange = {
selection = !selection
},
isExpanded = expanded,
onExpand = { expanded = !expanded },
singleWeight = shippableItem.innerShippableItem.formattedWeight,
singlePrice = shippableItem.innerShippableItem.formattedPrice,
modifier = Modifier.padding(vertical = 8.dp)
)
}
}
}
if (viewState.splitMessage != null) {
item {
Spacer(modifier = Modifier.padding(bottom = 120.dp))
}
}
}
}

is SelectableShippableItemUI.ExpandableSelectableShippableItemUI -> {
var expanded by remember { mutableStateOf(false) }
ExpandableSelectableShippingProduct(
title = shippableItem.shippableItem.title,
description = shippableItem.shippableItem.formattedSize,
weight = shippableItem.shippableItem.formattedWeight,
price = shippableItem.shippableItem.formattedPrice,
quantity = shippableItem.shippableItem.quantity,
imageUrl = shippableItem.shippableItem.imageUrl,
isSelected = selection,
onSelectionChange = {
selection = !selection
},
isExpanded = expanded,
onExpand = { expanded = !expanded },
singleWeight = shippableItem.innerShippableItem.formattedWeight,
singlePrice = shippableItem.innerShippableItem.formattedPrice,
modifier = Modifier.padding(vertical = 8.dp)
)
AnimatedVisibility(
visible = viewState.splitMessage != null,
label = "message_transition",
enter = slideInVertically(initialOffsetY = { it }),
exit = slideOutVertically(targetOffsetY = { it }),
modifier = Modifier.align(Alignment.BottomCenter)
) {
when (viewState.splitMessage) {
is SplitShipmentMessage.Instructions -> {
val annotatedString = buildAnnotatedString {
append(stringResource(R.string.woo_shipping_split_shipment_instructions_1))
append(" ")
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
append(stringResource(R.string.woo_shipping_split_shipment_instructions_2))
}
append(" ")
append(stringResource(R.string.woo_shipping_split_shipment_instructions_3))
}

InstructionsMessage(
message = annotatedString,
onClose = onDismissInstructions,
modifier = Modifier.align(Alignment.BottomCenter)
)
}

is SplitShipmentMessage.Success -> TODO()
null -> {}
}
}
}
}
}
}

@Composable
private fun InstructionsMessage(
message: AnnotatedString,
onClose: () -> Unit,
modifier: Modifier = Modifier
) {
Card(
backgroundColor = colorResource(id = R.color.woo_message_surface),
modifier = modifier,
shape = RoundedCornerShape(corner = CornerSize(8.dp))
) {
Row {
Text(
text = message,
color = MaterialTheme.colors.onPrimary.copy(alpha = .9f),
modifier = Modifier
.weight(1f, true)
.padding(start = 16.dp, top = 16.dp, bottom = 16.dp)
)
IconButton(onClick = { onClose() }) {
Icon(
imageVector = Icons.Filled.Close,
tint = MaterialTheme.colors.onPrimary.copy(alpha = .60f),
contentDescription = stringResource(id = R.string.close),
modifier = Modifier.padding(14.dp)
)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ import com.woocommerce.android.viewmodel.MultiLiveEvent
import com.woocommerce.android.viewmodel.ScopedViewModel
import com.woocommerce.android.viewmodel.navArgs
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import javax.inject.Inject
import kotlin.getValue

Expand All @@ -25,6 +27,7 @@ class WooShippingSplitShipmentViewModel @Inject constructor(

private val shipments = MutableStateFlow(navArgs.shipmentArgs.shipments)
private val currentShipments = MutableStateFlow(navArgs.shipmentArgs.shipments)
private val splitMessage: MutableStateFlow<SplitShipmentMessage?> = MutableStateFlow(null)

val selectableItems = shipments.map { shipment ->
shipment.mapValues {
Expand All @@ -36,25 +39,43 @@ class WooShippingSplitShipmentViewModel @Inject constructor(
}
}

init {
launch {
delay(NOTIFICATIONS_DELAY)
splitMessage.value = SplitShipmentMessage.Instructions
}
}

val viewState = combine(
shipments,
currentShipments,
selectableItems
) { shipments, currentShipments, selectableItems ->
selectableItems,
splitMessage
) { shipments, currentShipments, selectableItems, message ->
SplitShipmentViewState(
selectableItems = selectableItems,
hasChanges = shipments != currentShipments
hasChanges = shipments != currentShipments,
splitMessage = message
)
}.asLiveData()

fun onNavigateBack() {
triggerEvent(MultiLiveEvent.Event.Exit)
}

fun onDismissInstructions() {
splitMessage.value = null
}

data class SplitShipmentViewState(
val selectableItems: Map<Int, SelectableShippableItemsUI>,
val hasChanges: Boolean = false
val hasChanges: Boolean = false,
val splitMessage: SplitShipmentMessage? = null
)

companion object {
const val NOTIFICATIONS_DELAY = 500L
}
}

data class SelectableShippableItemsUI(
Expand All @@ -79,3 +100,11 @@ sealed class SelectableShippableItemUI {
get() = selectedIndexes.size == shippableItem.quantity.toInt()
}
}

sealed class SplitShipmentMessage {
data object Instructions : SplitShipmentMessage()
data class Success(
val message: String,
val action: () -> Unit
) : SplitShipmentMessage()
}
6 changes: 6 additions & 0 deletions WooCommerce/src/main/res/values-night/colors_base.xml
Original file line number Diff line number Diff line change
Expand Up @@ -241,4 +241,10 @@
<color name="blaze_campaign_preview_header_background">@color/woo_white_alpha_012</color>
<color name="blaze_campaign_objective_item_background">@color/woo_purple_90</color>

<!--
Custom Message Color
-->
<color name="woo_message_surface">@color/woo_purple_20</color>
<color name="woo_message_on_surface">@color/woo_black</color>

</resources>
Loading