Bug 1854631 - Refactor review checker info card

fenix/119.0
rahulsainani 8 months ago committed by mergify[bot]
parent 0cdbfdc829
commit 18ef60af4e

@ -18,7 +18,6 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.material.Icon import androidx.compose.material.Icon
import androidx.compose.material.Text import androidx.compose.material.Text
@ -95,13 +94,6 @@ fun ProductAnalysis(
description = stringResource(id = R.string.review_quality_check_no_reviews_warning_body), description = stringResource(id = R.string.review_quality_check_no_reviews_warning_body),
type = ReviewQualityCheckInfoType.Info, type = ReviewQualityCheckInfoType.Info,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
icon = {
Icon(
painter = painterResource(id = R.drawable.mozac_ic_information_fill_24),
contentDescription = null,
tint = FirefoxTheme.colors.iconPrimary,
)
},
) )
} }
@ -154,16 +146,10 @@ private fun ReanalyzeCard(
title = stringResource(R.string.review_quality_check_outdated_analysis_warning_title), title = stringResource(R.string.review_quality_check_outdated_analysis_warning_title),
type = ReviewQualityCheckInfoType.AnalysisUpdate, type = ReviewQualityCheckInfoType.AnalysisUpdate,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
buttonText = stringResource(R.string.review_quality_check_outdated_analysis_warning_action), buttonText = InfoCardButtonText(
onButtonClick = onReanalyzeClick, text = stringResource(R.string.review_quality_check_outdated_analysis_warning_action),
icon = { onClick = onReanalyzeClick,
Icon( ),
painter = painterResource(id = R.drawable.mozac_ic_information_fill_24),
contentDescription = null,
modifier = Modifier.size(24.dp),
tint = FirefoxTheme.colors.iconPrimary,
)
},
) )
} }
@ -171,13 +157,8 @@ private fun ReanalyzeCard(
private fun ReanalysisInProgressCard() { private fun ReanalysisInProgressCard() {
ReviewQualityCheckInfoCard( ReviewQualityCheckInfoCard(
title = stringResource(R.string.review_quality_check_reanalysis_in_progress_warning_title), title = stringResource(R.string.review_quality_check_reanalysis_in_progress_warning_title),
type = ReviewQualityCheckInfoType.AnalysisUpdate, type = ReviewQualityCheckInfoType.Loading,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
icon = {
IndeterminateProgressIndicator(
modifier = Modifier.size(24.dp),
)
},
) )
} }

@ -4,16 +4,15 @@
package org.mozilla.fenix.shopping.ui package org.mozilla.fenix.shopping.ui
import androidx.annotation.StringRes
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material.Icon
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import org.mozilla.fenix.R import org.mozilla.fenix.R
@ -48,53 +47,43 @@ fun ProductAnalysisError(
modifier = modifier, modifier = modifier,
verticalArrangement = Arrangement.spacedBy(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp),
) { ) {
when (error) { val (
ProductReviewState.Error.GenericError -> @StringRes titleResourceId: Int,
ReviewQualityCheckInfoCard( @StringRes descriptionResourceId: Int,
title = stringResource(id = R.string.review_quality_check_generic_error_title), type: ReviewQualityCheckInfoType,
description = stringResource(id = R.string.review_quality_check_generic_error_body), ) = when (error) {
type = ReviewQualityCheckInfoType.Warning, ProductReviewState.Error.GenericError -> {
modifier = Modifier.fillMaxWidth(), Triple(
icon = { R.string.review_quality_check_generic_error_title,
Icon( R.string.review_quality_check_generic_error_body,
painter = painterResource(id = R.drawable.mozac_ic_warning_fill_24), ReviewQualityCheckInfoType.Info,
contentDescription = null,
tint = FirefoxTheme.colors.iconPrimary,
)
},
) )
}
ProductReviewState.Error.NetworkError -> ProductReviewState.Error.NetworkError -> {
ReviewQualityCheckInfoCard( Triple(
title = stringResource(id = R.string.review_quality_check_no_connection_title), R.string.review_quality_check_no_connection_title,
description = stringResource(id = R.string.review_quality_check_no_connection_body), R.string.review_quality_check_no_connection_body,
type = ReviewQualityCheckInfoType.Warning, ReviewQualityCheckInfoType.Warning,
modifier = Modifier.fillMaxWidth(),
icon = {
Icon(
painter = painterResource(id = R.drawable.mozac_ic_warning_fill_24),
contentDescription = null,
tint = FirefoxTheme.colors.iconPrimary,
)
},
) )
}
ProductReviewState.Error.UnsupportedProductTypeError -> ProductReviewState.Error.UnsupportedProductTypeError -> {
ReviewQualityCheckInfoCard( Triple(
title = stringResource(id = R.string.review_quality_check_not_analyzable_info_title), R.string.review_quality_check_not_analyzable_info_title,
description = stringResource(id = R.string.review_quality_check_not_analyzable_info_body), R.string.review_quality_check_not_analyzable_info_body,
type = ReviewQualityCheckInfoType.Info, ReviewQualityCheckInfoType.Info,
modifier = Modifier.fillMaxWidth(),
icon = {
Icon(
painter = painterResource(id = R.drawable.mozac_ic_information_fill_24),
contentDescription = null,
tint = FirefoxTheme.colors.iconPrimary,
)
},
) )
}
} }
ReviewQualityCheckInfoCard(
title = stringResource(id = titleResourceId),
description = stringResource(id = descriptionResourceId),
type = type,
modifier = Modifier.fillMaxWidth(),
)
ReviewQualityInfoCard( ReviewQualityInfoCard(
onLearnMoreClick = onReviewGradeLearnMoreClick, onLearnMoreClick = onReviewGradeLearnMoreClick,
) )

@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
@ -53,7 +54,7 @@ fun ReviewQualityCheckExpandableCard(
) { ) {
ReviewQualityCheckCard( ReviewQualityCheckCard(
modifier = modifier, modifier = modifier,
contentPadding = 0.dp, contentPadding = PaddingValues(0.dp),
) { ) {
var isExpanded by remember { mutableStateOf(false) } var isExpanded by remember { mutableStateOf(false) }
@ -113,7 +114,7 @@ fun ReviewQualityCheckCard(
modifier: Modifier, modifier: Modifier,
backgroundColor: Color = FirefoxTheme.colors.layer2, backgroundColor: Color = FirefoxTheme.colors.layer2,
elevation: Dp = defaultCardElevation, elevation: Dp = defaultCardElevation,
contentPadding: Dp = defaultCardContentPadding, contentPadding: PaddingValues = PaddingValues(defaultCardContentPadding),
content: @Composable ColumnScope.() -> Unit, content: @Composable ColumnScope.() -> Unit,
) { ) {
Card( Card(

@ -8,6 +8,7 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
@ -15,8 +16,6 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Card
import androidx.compose.material.Icon import androidx.compose.material.Icon
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -34,22 +33,15 @@ import org.mozilla.fenix.compose.annotation.LightDarkPreview
import org.mozilla.fenix.compose.button.PrimaryButton import org.mozilla.fenix.compose.button.PrimaryButton
import org.mozilla.fenix.theme.FirefoxTheme import org.mozilla.fenix.theme.FirefoxTheme
private val cardShape = RoundedCornerShape(8.dp)
/** /**
* Review Quality Check info UI. * Review Quality Check Info Card UI.
* *
* @param title The primary text of the info message. * @param title The primary text of the info message.
* @param type The [ReviewQualityCheckInfoType] of message to display. * @param type The [ReviewQualityCheckInfoType] of message to display.
* @param modifier Modifier to be applied to the card. * @param modifier Modifier to be applied to the card.
* @param description The optional secondary piece of text. * @param description The optional secondary piece of text.
* @param linkText An optional piece of text with a clickable substring. * @param footer An optional piece of text with a clickable link.
* @param hyperlinkText The text within [linkText] that is clickable.
* @param linkURL The optional URL to return when the link is clicked.
* @param buttonText The text to show in the optional button. * @param buttonText The text to show in the optional button.
* @param onLinkClick Invoked when the link is clicked. When not-null, the link will be visible.
* @param onButtonClick Invoked when the button is clicked. When not-null, the button will be visible.
* @param icon The UI to display before the text, typically an image or loading spinner.
*/ */
@Composable @Composable
fun ReviewQualityCheckInfoCard( fun ReviewQualityCheckInfoCard(
@ -57,77 +49,104 @@ fun ReviewQualityCheckInfoCard(
type: ReviewQualityCheckInfoType, type: ReviewQualityCheckInfoType,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
description: String? = null, description: String? = null,
linkText: String = "", footer: Pair<String, LinkTextState>? = null,
hyperlinkText: String = "", buttonText: InfoCardButtonText? = null,
linkURL: String = "",
buttonText: String = "",
onLinkClick: (() -> Unit)? = null,
onButtonClick: (() -> Unit)? = null,
icon: @Composable () -> Unit,
) { ) {
Card( ReviewQualityCheckCard(
modifier = modifier, modifier = modifier,
shape = cardShape,
backgroundColor = type.cardBackgroundColor, backgroundColor = type.cardBackgroundColor,
contentPadding = PaddingValues(
horizontal = 12.dp,
vertical = 8.dp,
),
elevation = 0.dp, elevation = 0.dp,
) { ) {
Column(modifier = Modifier.padding(horizontal = 12.dp, vertical = 8.dp)) { Row {
Row { when (type) {
icon() ReviewQualityCheckInfoType.Warning -> {
InfoCardIcon(iconId = R.drawable.mozac_ic_warning_fill_24)
}
ReviewQualityCheckInfoType.Confirmation -> {
InfoCardIcon(iconId = R.drawable.mozac_ic_checkmark_24)
}
ReviewQualityCheckInfoType.Error,
ReviewQualityCheckInfoType.Info,
ReviewQualityCheckInfoType.AnalysisUpdate,
-> {
InfoCardIcon(
iconId = R.drawable.mozac_ic_information_fill_24,
modifier = Modifier.size(24.dp),
)
}
Spacer(modifier = Modifier.width(12.dp)) ReviewQualityCheckInfoType.Loading -> {
IndeterminateProgressIndicator(modifier = Modifier.size(24.dp))
}
}
Spacer(modifier = Modifier.width(12.dp))
Column {
Text(
text = title,
color = FirefoxTheme.colors.textPrimary,
style = FirefoxTheme.typography.headline8,
)
description?.let {
Spacer(modifier = Modifier.height(4.dp))
Column {
Text( Text(
text = title, text = description,
color = FirefoxTheme.colors.textPrimary, color = FirefoxTheme.colors.textPrimary,
style = FirefoxTheme.typography.headline8, style = FirefoxTheme.typography.body2,
) )
}
description?.let { footer?.let {
Spacer(modifier = Modifier.height(4.dp)) Spacer(modifier = Modifier.height(4.dp))
Text( LinkText(
text = description, text = it.first,
linkTextState = it.second,
style = FirefoxTheme.typography.body2.copy(
color = FirefoxTheme.colors.textPrimary, color = FirefoxTheme.colors.textPrimary,
style = FirefoxTheme.typography.body2, ),
) linkTextColor = FirefoxTheme.colors.textPrimary,
} linkTextDecoration = TextDecoration.Underline,
)
onLinkClick?.let {
Spacer(modifier = Modifier.height(4.dp))
LinkText(
text = linkText,
linkTextState = LinkTextState(
text = hyperlinkText,
url = linkURL,
onClick = { onLinkClick() },
),
style = FirefoxTheme.typography.body2.copy(
color = FirefoxTheme.colors.textPrimary,
),
linkTextColor = FirefoxTheme.colors.textPrimary,
linkTextDecoration = TextDecoration.Underline,
)
}
} }
} }
}
onButtonClick?.let { buttonText?.let {
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
PrimaryButton( PrimaryButton(
text = buttonText, text = it.text,
textColor = type.buttonTextColor, textColor = type.buttonTextColor,
backgroundColor = type.buttonBackgroundColor, backgroundColor = type.buttonBackgroundColor,
onClick = onButtonClick, onClick = it.onClick,
) )
}
} }
} }
} }
@Composable
private fun InfoCardIcon(
iconId: Int,
modifier: Modifier = Modifier,
) {
Icon(
painter = painterResource(id = iconId),
contentDescription = null,
tint = FirefoxTheme.colors.iconPrimary,
modifier = modifier,
)
}
/** /**
* The possible types of a [ReviewQualityCheckInfoCard]. * The possible types of a [ReviewQualityCheckInfoCard].
*/ */
@ -138,6 +157,7 @@ enum class ReviewQualityCheckInfoType {
Error, Error,
Info, Info,
AnalysisUpdate, AnalysisUpdate,
Loading,
; ;
val cardBackgroundColor: Color val cardBackgroundColor: Color
@ -148,6 +168,7 @@ enum class ReviewQualityCheckInfoType {
Error -> FirefoxTheme.colors.layerError Error -> FirefoxTheme.colors.layerError
Info -> FirefoxTheme.colors.layerInfo Info -> FirefoxTheme.colors.layerInfo
AnalysisUpdate -> Color.Transparent AnalysisUpdate -> Color.Transparent
Loading -> Color.Transparent
} }
val buttonBackgroundColor: Color val buttonBackgroundColor: Color
@ -158,37 +179,38 @@ enum class ReviewQualityCheckInfoType {
Error -> FirefoxTheme.colors.actionError Error -> FirefoxTheme.colors.actionError
Info -> FirefoxTheme.colors.actionInfo Info -> FirefoxTheme.colors.actionInfo
AnalysisUpdate -> FirefoxTheme.colors.actionSecondary AnalysisUpdate -> FirefoxTheme.colors.actionSecondary
Loading -> FirefoxTheme.colors.actionSecondary
} }
val buttonTextColor: Color val buttonTextColor: Color
@Composable @Composable
get() = when { get() = when {
this == Info && !isSystemInDarkTheme() -> FirefoxTheme.colors.textOnColorPrimary this == Info && !isSystemInDarkTheme() -> FirefoxTheme.colors.textOnColorPrimary
this == AnalysisUpdate -> FirefoxTheme.colors.textActionSecondary this == AnalysisUpdate || this == Loading -> FirefoxTheme.colors.textActionSecondary
else -> FirefoxTheme.colors.textPrimary else -> FirefoxTheme.colors.textPrimary
} }
} }
private class PreviewModel( /**
val messageType: ReviewQualityCheckInfoType, * Model for the optional button in a [ReviewQualityCheckInfoCard].
val iconId: Int, *
* @param text The text to show in the button.
* @param onClick The callback to invoke when the button is clicked.
*/
data class InfoCardButtonText(
val text: String,
val onClick: () -> Unit,
) )
private class PreviewModelParameterProvider : PreviewParameterProvider<PreviewModel> { private class PreviewModelParameterProvider : PreviewParameterProvider<ReviewQualityCheckInfoType> {
override val values: Sequence<PreviewModel>
get() = sequenceOf( override val values = enumValues<ReviewQualityCheckInfoType>().asSequence()
PreviewModel(ReviewQualityCheckInfoType.Warning, R.drawable.mozac_ic_warning_fill_24),
PreviewModel(ReviewQualityCheckInfoType.Confirmation, R.drawable.mozac_ic_checkmark_24),
PreviewModel(ReviewQualityCheckInfoType.Error, R.drawable.mozac_ic_information_fill_24),
PreviewModel(ReviewQualityCheckInfoType.Info, R.drawable.mozac_ic_information_fill_24),
PreviewModel(ReviewQualityCheckInfoType.AnalysisUpdate, R.drawable.mozac_ic_information_fill_24),
)
} }
@LightDarkPreview @LightDarkPreview
@Composable @Composable
private fun InfoCardPreview( private fun InfoCardPreview(
@PreviewParameter(PreviewModelParameterProvider::class) model: PreviewModel, @PreviewParameter(PreviewModelParameterProvider::class) type: ReviewQualityCheckInfoType,
) { ) {
FirefoxTheme { FirefoxTheme {
Box( Box(
@ -198,22 +220,18 @@ private fun InfoCardPreview(
) { ) {
ReviewQualityCheckInfoCard( ReviewQualityCheckInfoCard(
title = "Title text", title = "Title text",
type = model.messageType, type = type,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
description = "Description text", description = "Description text",
linkText = "Primary link text with an underlined hyperlink.", footer = "Primary link text with an underlined hyperlink." to LinkTextState(
hyperlinkText = "underlined hyperlink", text = "underlined hyperlink",
buttonText = "Button text", url = "https://www.mozilla.org",
onLinkClick = {}, onClick = {},
onButtonClick = {}, ),
icon = { buttonText = InfoCardButtonText(
Icon( text = "Button text",
painter = painterResource(id = model.iconId), onClick = {},
contentDescription = null, ),
modifier = Modifier.size(24.dp),
tint = FirefoxTheme.colors.iconPrimary,
)
},
) )
} }
} }

Loading…
Cancel
Save