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] Refactor shipping label notices #13817

Open
wants to merge 8 commits into
base: trunk
Choose a base branch
from
Open
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@ package com.woocommerce.android.ui.orders.wooshippinglabels
import android.content.res.Configuration
import android.os.Parcelable
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
Expand All @@ -24,9 +19,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.sizeIn
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.BottomSheetScaffoldState
import androidx.compose.material.Divider
Expand All @@ -36,13 +29,8 @@ import androidx.compose.material.ModalBottomSheetState
import androidx.compose.material.ModalBottomSheetValue
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.CheckCircleOutline
import androidx.compose.material.icons.outlined.Close
import androidx.compose.material.icons.outlined.Info
import androidx.compose.material.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
Expand All @@ -60,16 +48,16 @@ import com.woocommerce.android.R
import com.woocommerce.android.extensions.appendWithIfNotEmpty
import com.woocommerce.android.ui.compose.animations.SkeletonView
import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground
import com.woocommerce.android.ui.orders.wooshippinglabels.address.AddressNotification
import com.woocommerce.android.ui.orders.wooshippinglabels.address.AddressSectionLandscape
import com.woocommerce.android.ui.orders.wooshippinglabels.address.AddressSectionPortrait
import com.woocommerce.android.ui.orders.wooshippinglabels.address.AddressStatus
import com.woocommerce.android.ui.orders.wooshippinglabels.address.getShipFrom
import com.woocommerce.android.ui.orders.wooshippinglabels.address.getShipTo
import com.woocommerce.android.ui.orders.wooshippinglabels.components.NoticeBanner
import com.woocommerce.android.ui.orders.wooshippinglabels.components.NoticeBannerUiState
import com.woocommerce.android.ui.orders.wooshippinglabels.models.DestinationShippingAddress
import com.woocommerce.android.ui.orders.wooshippinglabels.models.OriginShippingAddress
import com.woocommerce.android.util.StringUtils
import kotlinx.coroutines.delay
import kotlinx.parcelize.Parcelize

@Composable
Expand All @@ -80,17 +68,14 @@ fun ShipmentDetails(
shippingLines: List<ShippingLineSummaryUI>,
shippingAddresses: WooShippingAddresses,
shippingRateSummary: ShippingRateSummaryUI?,
addressNotification: AddressNotification?,
itnNotification: ItnMissingNotification? = null,
modifier: Modifier = Modifier,
noticeBannerUiState: NoticeBannerUiState? = null,
isShipmentDetailsExpanded: Boolean = false,
onShipmentDetailsExpandedChange: (Boolean) -> Boolean,
onEditDestinationAddress: (DestinationShippingAddress) -> Unit,
onEditOriginAddress: (OriginShippingAddress) -> Unit,
destinationStatus: AddressStatus,
markOrderComplete: Boolean = false,
onMarkOrderCompleteChange: (Boolean) -> Unit = {},
onDismissAddressNotification: () -> Unit = {},
handlerModifier: Modifier = Modifier,
isReadOnly: Boolean = false
) {
Expand Down Expand Up @@ -128,23 +113,7 @@ fun ShipmentDetails(
.padding(top = dimensionResource(R.dimen.minor_100) * LocalConfiguration.current.fontScale)
)

ShippingAddressNotification(
addressNotification = addressNotification,
onDismiss = onDismissAddressNotification,
onAction = {
addressNotification?.let {
when {
it.isSuccess.not() && it.isDestinationNotification -> {
onEditDestinationAddress(shippingAddresses.shipTo)
}
it.isSuccess.not() && it.isDestinationNotification.not() -> {
onEditOriginAddress(shippingAddresses.shipFrom)
}
Comment on lines -137 to -142
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This onAction logic has been moved into the view model.

}
}
}
)
ItnMissingNotification(itnNotification)
NoticeBanner(noticeBannerUiState)
Comment on lines -131 to +116
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We'll use NoticeBanner for all notice types.


Spacer(
modifier = Modifier.size(
Expand Down Expand Up @@ -559,178 +528,6 @@ private fun ShipmentCostRow(
}
}

@Composable
private fun ItnMissingNotification(
itnNotification: ItnMissingNotification?,
modifier: Modifier = Modifier
) {
AnimatedVisibility(
visible = itnNotification != null,
enter = fadeIn(
animationSpec = tween(
durationMillis = 180
)
) + scaleIn(
animationSpec = tween(
durationMillis = 180
)
),
exit = fadeOut(
animationSpec = tween(
durationMillis = 90
)
) + scaleOut(
animationSpec = tween(
durationMillis = 90
)

)
) {
if (itnNotification == null) return@AnimatedVisibility

val rowModifier = when (LocalConfiguration.current.orientation) {
Configuration.ORIENTATION_LANDSCAPE -> {
modifier.widthIn(max = 600.dp).fillMaxWidth()
}
else -> {
modifier.fillMaxWidth()
}
}

Row(
verticalAlignment = Alignment.CenterVertically,
modifier = rowModifier
.padding(dimensionResource(R.dimen.major_100))
.background(
color = colorResource(R.color.woo_red_5),
shape = RoundedCornerShape(dimensionResource(R.dimen.corner_radius_large))
)
.padding(vertical = 8.dp, horizontal = 16.dp),
) {
Icon(
imageVector = Icons.Outlined.Info,
tint = MaterialTheme.colors.error,
contentDescription = null
)
Spacer(Modifier.size(dimensionResource(R.dimen.minor_50)))
Text(
text = itnNotification.errorMessage,
style = MaterialTheme.typography.body2,
color = MaterialTheme.colors.error,
modifier = Modifier.weight(1f)
)
Icon(
imageVector = Icons.Outlined.Close,
tint = MaterialTheme.colors.error,
contentDescription = null,
modifier = Modifier.clickable {
itnNotification.onErrorDismissed()
}
)
}
}
}

@Composable
private fun ShippingAddressNotification(
addressNotification: AddressNotification?,
modifier: Modifier = Modifier,
onAction: () -> Unit = {},
onDismiss: () -> Unit = {}
) {
AnimatedVisibility(
visible = addressNotification != null && addressNotification.isExpired().not(),
enter = fadeIn(
animationSpec = tween(
durationMillis = 180
)
) + scaleIn(
animationSpec = tween(
durationMillis = 180
)
),
exit = fadeOut(
animationSpec = tween(
durationMillis = 90
)
) + scaleOut(
animationSpec = tween(
durationMillis = 90
)

)
) {
if (addressNotification != null && addressNotification.isExpired().not()) {
if (addressNotification.expireAfter != null) {
LaunchedEffect(addressNotification) {
delay(addressNotification.expireAfter)
onDismiss()
}
}

val color = if (addressNotification.isSuccess) {
colorResource(id = R.color.woo_shipping_label_success)
} else {
colorResource(id = R.color.woo_shipping_label_error)
}

val backgroundColor = if (addressNotification.isSuccess) {
colorResource(id = R.color.woo_shipping_label_success_surface)
} else {
colorResource(id = R.color.woo_shipping_label_error_surface)
}

val icon = if (addressNotification.isSuccess) {
Icons.Outlined.CheckCircleOutline
} else {
Icons.Outlined.Info
}

val configuration = LocalConfiguration.current
val rowModifier = when (configuration.orientation) {
Configuration.ORIENTATION_LANDSCAPE -> {
modifier.widthIn(max = 600.dp).fillMaxWidth()
}
else -> {
modifier.fillMaxWidth()
}
}

Row(
rowModifier
.padding(dimensionResource(R.dimen.major_100))
.background(
color = backgroundColor,
shape = RoundedCornerShape(dimensionResource(R.dimen.corner_radius_large))
)
.clickable { onAction() }
.padding(vertical = 8.dp, horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
imageVector = icon,
contentDescription = null,
tint = color,
modifier = Modifier.padding(end = 8.dp)
)
Text(
text = stringResource(addressNotification.message),
color = color,
modifier = Modifier.weight(1f)
)
if (addressNotification.isSuccess.not()) {
Icon(
imageVector = Icons.Outlined.Close,
contentDescription = null,
tint = color,
modifier = Modifier.clickable { onDismiss() }
)
}
}
}
}
}

@Preview
@Composable
private fun ShipmentCostSectionPreview() {
Expand Down Expand Up @@ -771,11 +568,6 @@ data class ShippingRateSummaryUI(
val optionFee: String? = null
) : Parcelable

data class ItnMissingNotification(
val errorMessage: String,
val onErrorDismissed: () -> Unit
)

@Composable
fun VerticalDivider(
modifier: Modifier = Modifier,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,7 @@ fun WooShippingLabelCreationScreen(viewModel: WooShippingLabelCreationViewModel)
onEditDestinationAddress = viewModel::onEditDestinationAddress,
destinationStatus = viewState.destinationStatus,
actionSnackbar = viewModel.actionSnackbar,
onDismissAddressNotification = viewModel::onDismissAddressNotification,
onSplitShipment = viewModel::onSplitShipment,
onDismissItnNotice = viewModel::onDismissItnNotice
)
}

Expand Down Expand Up @@ -165,11 +163,9 @@ fun WooShippingLabelCreationScreen(
onEditCustomsClick: () -> Unit,
onNavigateBack: () -> Unit,
onEditDestinationAddress: (DestinationShippingAddress) -> Unit,
onDismissItnNotice: () -> Unit,
destinationStatus: AddressStatus,
modifier: Modifier = Modifier,
actionSnackbar: ActionSnackbar? = null,
onDismissAddressNotification: () -> Unit = {},
onSplitShipment: () -> Unit = {}
) {
val shipmentDetailsValue = if (uiState.isShipmentDetailsExpanded) {
Expand Down Expand Up @@ -232,8 +228,6 @@ fun WooShippingLabelCreationScreen(
onShipmentDetailsExpandedChange = onShipmentDetailsExpandedChange,
onEditCustomsClick = onEditCustomsClick,
onEditDestinationAddress = onEditDestinationAddress,
onDismissItnNotice = onDismissItnNotice,
onDismissAddressNotification = onDismissAddressNotification,
destinationStatus = destinationStatus,
actionSnackbar = actionSnackbar,
onSplitShipment = onSplitShipment
Expand Down Expand Up @@ -312,18 +306,15 @@ private fun LabelCreationScreenWithBottomSheet(
onShipmentDetailsExpandedChange: (Boolean) -> Boolean,
onEditCustomsClick: () -> Unit,
onEditDestinationAddress: (DestinationShippingAddress) -> Unit,
onDismissItnNotice: () -> Unit,
destinationStatus: AddressStatus,
modifier: Modifier = Modifier,
onDismissAddressNotification: () -> Unit = {},
actionSnackbar: ActionSnackbar? = null,
onSplitShipment: () -> Unit = {}
) {
val snackbarHostState = remember { SnackbarHostState() }

val isItnMissing = customsState is ItnMissing
val isPurchaseButtonDisplayed = shippingRatesState is WooShippingLabelCreationViewModel.ShippingRatesState.DataState
val requiresLargePeekHeight = isPurchaseButtonDisplayed || uiState.addressNotification != null || isItnMissing
val requiresLargePeekHeight = isPurchaseButtonDisplayed || uiState.noticeBannerUiState != null

val bottomSheetPeekHeight = when {
requiresLargePeekHeight -> 128.dp
Expand Down Expand Up @@ -371,15 +362,7 @@ private fun LabelCreationScreenWithBottomSheet(
onShipmentDetailsExpandedChange = onShipmentDetailsExpandedChange,
onEditDestinationAddress = onEditDestinationAddress,
destinationStatus = destinationStatus,
addressNotification = uiState.addressNotification,
onDismissAddressNotification = onDismissAddressNotification,
onEditOriginAddress = onEditOriginAddress,
itnNotification = takeIf { isItnMissing }?.let {
ItnMissingNotification(
errorMessage = stringResource(R.string.woo_shipping_labels_customs_itn_required_error),
onErrorDismissed = onDismissItnNotice
)
}
Comment on lines -377 to -382
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This logic has been moved into the ObserveShippingLabelNotice class.

noticeBannerUiState = uiState.noticeBannerUiState
)
}
},
Expand Down Expand Up @@ -894,7 +877,6 @@ private fun WooShippingLabelCreationScreenPreview() {
onSelectAddressExpandedChange = { true },
onEditCustomsClick = {},
onEditDestinationAddress = {},
onDismissItnNotice = {},
destinationStatus = AddressStatus.VERIFIED
)
}
Expand Down
Loading