Bug 1845260 - Create top level structure for Review Quality Check
parent
b7ff198e44
commit
609895be91
@ -0,0 +1,164 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.fenix.shopping.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.compose.SwitchWithLabel
|
||||
import org.mozilla.fenix.compose.annotation.LightDarkPreview
|
||||
import org.mozilla.fenix.compose.button.SecondaryButton
|
||||
import org.mozilla.fenix.shopping.state.ReviewQualityCheckState
|
||||
import org.mozilla.fenix.shopping.state.ReviewQualityCheckState.OptedIn.ProductReviewState.AnalysisPresent
|
||||
import org.mozilla.fenix.theme.FirefoxTheme
|
||||
|
||||
/**
|
||||
* UI for review quality check content displaying product analysis.
|
||||
*
|
||||
* @param productRecommendationsEnabled The current state of the product recommendations toggle.
|
||||
* @param productAnalysis The product analysis to display.
|
||||
* @param onOptOutClick Invoked when the user opts out of the review quality check feature.
|
||||
* @param onProductRecommendationsEnabledStateChange Invoked when the user changes the product
|
||||
* recommendations toggle state.
|
||||
* @param modifier The modifier to be applied to the Composable.
|
||||
*/
|
||||
@Composable
|
||||
fun ProductAnalysis(
|
||||
productRecommendationsEnabled: Boolean,
|
||||
productAnalysis: AnalysisPresent,
|
||||
onOptOutClick: () -> Unit,
|
||||
onProductRecommendationsEnabledStateChange: (Boolean) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
) {
|
||||
ReviewGradeCard(
|
||||
reviewGrade = productAnalysis.reviewGrade,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
|
||||
SettingsCard(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
productRecommendationsEnabled = productRecommendationsEnabled,
|
||||
onProductRecommendationsEnabledStateChange = onProductRecommendationsEnabledStateChange,
|
||||
onTurnOffReviewQualityCheckClick = onOptOutClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ReviewGradeCard(
|
||||
reviewGrade: ReviewQualityCheckState.Grade,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
ReviewQualityCheckCard(modifier = modifier.semantics(mergeDescendants = true) {}) {
|
||||
Text(
|
||||
text = stringResource(R.string.review_quality_check_grade_title),
|
||||
color = FirefoxTheme.colors.textPrimary,
|
||||
style = FirefoxTheme.typography.headline8,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
ReviewGradeExpanded(grade = reviewGrade)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SettingsCard(
|
||||
productRecommendationsEnabled: Boolean,
|
||||
onProductRecommendationsEnabledStateChange: (Boolean) -> Unit,
|
||||
onTurnOffReviewQualityCheckClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
ReviewQualityCheckExpandableCard(
|
||||
modifier = modifier,
|
||||
title = stringResource(R.string.review_quality_check_settings_title),
|
||||
) {
|
||||
Column {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
SwitchWithLabel(
|
||||
checked = productRecommendationsEnabled,
|
||||
onCheckedChange = onProductRecommendationsEnabledStateChange,
|
||||
label = stringResource(R.string.review_quality_check_settings_recommended_products),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
SecondaryButton(
|
||||
text = stringResource(R.string.review_quality_check_settings_turn_off),
|
||||
onClick = onTurnOffReviewQualityCheckClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@LightDarkPreview
|
||||
private fun ProductAnalysisPreview() {
|
||||
FirefoxTheme {
|
||||
ReviewQualityCheckScaffold(
|
||||
onRequestDismiss = {},
|
||||
) {
|
||||
val productRecommendationsEnabled = remember { mutableStateOf(false) }
|
||||
|
||||
ProductAnalysis(
|
||||
productRecommendationsEnabled = productRecommendationsEnabled.value,
|
||||
productAnalysis = AnalysisPresent(
|
||||
productId = "123",
|
||||
reviewGrade = ReviewQualityCheckState.Grade.B,
|
||||
needsAnalysis = false,
|
||||
adjustedRating = 3.6f,
|
||||
productUrl = "123",
|
||||
highlights = mapOf(
|
||||
ReviewQualityCheckState.HighlightType.QUALITY to listOf(
|
||||
"High quality",
|
||||
"Excellent craftsmanship",
|
||||
"Superior materials",
|
||||
),
|
||||
ReviewQualityCheckState.HighlightType.PRICE to listOf(
|
||||
"Affordable prices",
|
||||
"Great value for money",
|
||||
"Discounted offers",
|
||||
),
|
||||
ReviewQualityCheckState.HighlightType.SHIPPING to listOf(
|
||||
"Fast and reliable shipping",
|
||||
"Free shipping options",
|
||||
"Express delivery",
|
||||
),
|
||||
ReviewQualityCheckState.HighlightType.PACKAGING_AND_APPEARANCE to listOf(
|
||||
"Elegant packaging",
|
||||
"Attractive appearance",
|
||||
"Beautiful design",
|
||||
),
|
||||
ReviewQualityCheckState.HighlightType.COMPETITIVENESS to listOf(
|
||||
"Competitive pricing",
|
||||
"Strong market presence",
|
||||
"Unbeatable deals",
|
||||
),
|
||||
),
|
||||
),
|
||||
onOptOutClick = {},
|
||||
onProductRecommendationsEnabledStateChange = {
|
||||
productRecommendationsEnabled.value = it
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.fenix.shopping.ui
|
||||
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import mozilla.components.lib.state.ext.observeAsState
|
||||
import org.mozilla.fenix.shopping.state.ReviewQualityCheckAction
|
||||
import org.mozilla.fenix.shopping.state.ReviewQualityCheckState
|
||||
import org.mozilla.fenix.shopping.state.ReviewQualityCheckState.OptedIn.ProductReviewState.AnalysisPresent
|
||||
import org.mozilla.fenix.shopping.state.ReviewQualityCheckStore
|
||||
|
||||
/**
|
||||
* Top-level UI for the Review Quality Check feature.
|
||||
*
|
||||
* @param store [ReviewQualityCheckStore] that holds the state.
|
||||
* @param onRequestDismiss Invoked when a user action requests dismissal of the bottom sheet.
|
||||
* @param modifier The modifier to be applied to the Composable.
|
||||
*/
|
||||
@Composable
|
||||
fun ReviewQualityCheckBottomSheet(
|
||||
store: ReviewQualityCheckStore,
|
||||
onRequestDismiss: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val reviewQualityCheckState by store.observeAsState(ReviewQualityCheckState.Initial) { it }
|
||||
|
||||
ReviewQualityCheckScaffold(
|
||||
onRequestDismiss = onRequestDismiss,
|
||||
modifier = modifier.animateContentSize(),
|
||||
) {
|
||||
when (val state = reviewQualityCheckState) {
|
||||
is ReviewQualityCheckState.NotOptedIn -> {
|
||||
ReviewQualityCheckContextualOnboarding(
|
||||
onPrimaryButtonClick = {
|
||||
store.dispatch(ReviewQualityCheckAction.OptIn)
|
||||
},
|
||||
onSecondaryButtonClick = onRequestDismiss,
|
||||
)
|
||||
}
|
||||
|
||||
is ReviewQualityCheckState.OptedIn -> {
|
||||
ProductReview(
|
||||
state = state,
|
||||
onOptOutClick = {
|
||||
onRequestDismiss()
|
||||
store.dispatch(ReviewQualityCheckAction.OptOut)
|
||||
},
|
||||
onProductRecommendationsEnabledStateChange = {
|
||||
store.dispatch(ReviewQualityCheckAction.ToggleProductRecommendation)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
is ReviewQualityCheckState.Initial -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ProductReview(
|
||||
state: ReviewQualityCheckState.OptedIn,
|
||||
onOptOutClick: () -> Unit,
|
||||
onProductRecommendationsEnabledStateChange: (Boolean) -> Unit,
|
||||
) {
|
||||
when (val productReviewState = state.productReviewState) {
|
||||
is AnalysisPresent -> {
|
||||
ProductAnalysis(
|
||||
productRecommendationsEnabled = state.productRecommendationsPreference,
|
||||
productAnalysis = productReviewState,
|
||||
onOptOutClick = onOptOutClick,
|
||||
onProductRecommendationsEnabledStateChange = onProductRecommendationsEnabledStateChange,
|
||||
)
|
||||
}
|
||||
|
||||
is ReviewQualityCheckState.OptedIn.ProductReviewState.Error -> {
|
||||
// Bug 1840113
|
||||
}
|
||||
|
||||
is ReviewQualityCheckState.OptedIn.ProductReviewState.Loading -> {
|
||||
// Bug 1845255
|
||||
}
|
||||
|
||||
is ReviewQualityCheckState.OptedIn.ProductReviewState.NoAnalysisPresent -> {
|
||||
// Bug 1840333
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.fenix.shopping.ui
|
||||
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.compose.button.PrimaryButton
|
||||
import org.mozilla.fenix.compose.button.TextButton
|
||||
import org.mozilla.fenix.theme.FirefoxTheme
|
||||
|
||||
/**
|
||||
* A placeholder UI for review quality check contextual onboarding. The actual UI will be
|
||||
* implemented as part of Bug 1840103 with the illustration.
|
||||
*
|
||||
* @param onPrimaryButtonClick Invoked when a user clicks on the primary button.
|
||||
* @param onSecondaryButtonClick Invoked when a user clicks on the secondary button.
|
||||
*/
|
||||
@Composable
|
||||
fun ColumnScope.ReviewQualityCheckContextualOnboarding(
|
||||
onPrimaryButtonClick: () -> Unit,
|
||||
onSecondaryButtonClick: () -> Unit,
|
||||
) {
|
||||
ReviewQualityCheckCard(modifier = Modifier.fillMaxWidth()) {
|
||||
Text(
|
||||
text = stringResource(R.string.review_quality_check_contextual_onboarding_title),
|
||||
color = FirefoxTheme.colors.textPrimary,
|
||||
style = FirefoxTheme.typography.headline5,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.review_quality_check_contextual_onboarding_description),
|
||||
color = FirefoxTheme.colors.textPrimary,
|
||||
style = FirefoxTheme.typography.body2,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
PrimaryButton(
|
||||
text = stringResource(R.string.review_quality_check_contextual_onboarding_primary_button_text),
|
||||
onClick = onPrimaryButtonClick,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
TextButton(
|
||||
text = stringResource(R.string.review_quality_check_contextual_onboarding_secondary_button_text),
|
||||
onClick = onSecondaryButtonClick,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.review_quality_check_contextual_onboarding_caption),
|
||||
color = FirefoxTheme.colors.textPrimary,
|
||||
style = FirefoxTheme.typography.caption,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally),
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue