commit ddcf5ec0787055978e20178a6ad4a92f4903cea5
parent fc351100eafea724a49c0877100e07bd8de2fd31
Author: Gabriel Luong <gabriel.luong@gmail.com>
Date: Tue, 2 Dec 2025 08:19:07 +0000
Bug 1993368 - Part 36: Migrate UnsubmittedCrashDialog to M3 color tokens r=android-reviewers,007
- Simplified CrashCard composable method to have 2 separate composable functions to render the dialog content.
- Migrated the acorn color tokens to use M3 color tokens.
- Used PreviewParameterProvider to simplify the Composable Previews.
- Figma: https://www.figma.com/design/CaopY3iqHHpyLYjhhR78wI/In-app-Crash-Reporter?node-id=600-2098&m=dev
- M3 update of the dialog will be filed as a followup.
Differential Revision: https://phabricator.services.mozilla.com/D274539
Diffstat:
1 file changed, 180 insertions(+), 168 deletions(-)
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/crashes/UnsubmittedCrashDialog.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/crashes/UnsubmittedCrashDialog.kt
@@ -8,10 +8,8 @@ import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.view.ViewGroup
-import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@@ -22,10 +20,9 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Checkbox
-import androidx.compose.material3.CheckboxDefaults
import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
import androidx.compose.material3.Text
-import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -33,7 +30,6 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.ViewCompositionStrategy
@@ -42,8 +38,11 @@ import androidx.compose.ui.semantics.heading
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.tooling.preview.PreviewLightDark
+import androidx.compose.ui.tooling.preview.PreviewParameter
+import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import androidx.fragment.app.DialogFragment
+import mozilla.components.compose.base.button.TextButton
import mozilla.components.lib.crash.store.CrashAction
import org.mozilla.fenix.R
import org.mozilla.fenix.compose.LinkText
@@ -71,18 +70,12 @@ class UnsubmittedCrashDialog(
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
FirefoxTheme {
- Box(
- modifier = Modifier
- .clip(RoundedCornerShape(8.dp))
- .background(FirefoxTheme.colors.layer1),
- ) {
- CrashCard(
- dismiss = ::dismiss,
- dispatcher = dispatcher,
- crashIDs = crashIDs,
- cardContext = localContext,
- )
- }
+ CrashCard(
+ dismiss = ::dismiss,
+ dispatcher = dispatcher,
+ crashIDs = crashIDs,
+ cardContext = localContext,
+ )
}
}
},
@@ -101,7 +94,6 @@ class UnsubmittedCrashDialog(
}
}
-@Suppress("LongMethod")
@Composable
private fun CrashCard(
dismiss: () -> Unit,
@@ -109,11 +101,9 @@ private fun CrashCard(
crashIDs: List<String>?,
cardContext: Context?,
) {
- val requestedByDevs = !crashIDs.isNullOrEmpty()
- val context = LocalContext.current
-
dispatcher(CrashAction.PromptShown)
+ val requestedByDevs = !crashIDs.isNullOrEmpty()
val msg = if (requestedByDevs) {
if (crashIDs.size == 1) {
stringResource(
@@ -134,150 +124,93 @@ private fun CrashCard(
)
}
+ Surface(
+ shape = RoundedCornerShape(8.dp),
+ ) {
+ if (!requestedByDevs) {
+ CrashDialog(
+ msg = msg,
+ dismiss = dismiss,
+ dispatcher = dispatcher,
+ )
+ } else {
+ CrashPullDialog(
+ msg = msg,
+ dismiss = dismiss,
+ dispatcher = dispatcher,
+ crashIDs = crashIDs,
+ cardContext = cardContext,
+ )
+ }
+ }
+}
+
+@Composable
+private fun CrashDialog(
+ msg: String,
+ dismiss: () -> Unit,
+ dispatcher: (action: CrashAction) -> Unit,
+) {
var checkboxChecked by remember { mutableStateOf(false) }
- if (!requestedByDevs) {
- Column(
+ Column(
+ modifier = Modifier
+ .width(280.dp)
+ .padding(top = 16.dp, start = 16.dp, end = 16.dp, bottom = 0.dp),
+ verticalArrangement = Arrangement.spacedBy(16.dp),
+ ) {
+ Text(
+ text = msg,
+ style = FirefoxTheme.typography.headline7,
modifier = Modifier
- .width(280.dp)
- .padding(top = 16.dp, start = 16.dp, end = 16.dp, bottom = 0.dp),
- verticalArrangement = Arrangement.spacedBy(16.dp),
+ .semantics { heading() },
+ )
+
+ AnnotatedStringBody()
+
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier.widthIn(max = 248.dp),
) {
- Text(
- text = msg,
- color = FirefoxTheme.colors.textPrimary,
- style = FirefoxTheme.typography.headline7,
- modifier = Modifier
- .semantics { heading() },
+ Checkbox(
+ checked = checkboxChecked,
+ onCheckedChange = { checkboxChecked = it },
+ modifier = Modifier.padding(start = 0.dp, end = 0.dp),
)
- AnnotatedStringBody()
-
- Row(
- verticalAlignment = Alignment.CenterVertically,
- modifier = Modifier.widthIn(max = 248.dp),
- ) {
- Checkbox(
- checked = checkboxChecked,
- colors = CheckboxDefaults.colors(
- checkedColor = FirefoxTheme.colors.formSelected,
- uncheckedColor = FirefoxTheme.colors.formDefault,
- ),
- onCheckedChange = { checkboxChecked = it },
- modifier = Modifier.padding(start = 0.dp, end = 0.dp),
- )
- Text(
- text = stringResource(R.string.unsubmitted_crash_dialog_checkbox_label),
- color = FirefoxTheme.colors.textPrimary,
- style = FirefoxTheme.typography.subtitle1,
- )
- }
- Row(
- horizontalArrangement = Arrangement.spacedBy(
- space = 8.dp,
- alignment = Alignment.End,
- ),
- modifier = Modifier.fillMaxWidth(),
- ) {
- TextButton(
- onClick = {
- dispatcher(CrashAction.CancelTapped)
- dismiss()
- },
- ) {
- Text(
- text = stringResource(R.string.unsubmitted_crash_dialog_negative_button_2),
- color = MaterialTheme.colorScheme.tertiary,
- style = FirefoxTheme.typography.button,
- )
- }
- TextButton(
- onClick = {
- dispatcher(
- CrashAction.ReportTapped(
- checkboxChecked,
- listOf(),
- ),
- )
- dismiss()
- },
- ) {
- Text(
- text = stringResource(R.string.unsubmitted_crash_dialog_positive_button_2),
- color = MaterialTheme.colorScheme.tertiary,
- style = FirefoxTheme.typography.button,
- )
- }
- }
- }
- } else {
- Column(modifier = Modifier.padding(16.dp)) {
Text(
- text = msg,
- modifier = Modifier
- .semantics { heading() },
- color = FirefoxTheme.colors.textPrimary,
- style = FirefoxTheme.typography.headline5,
+ text = stringResource(R.string.unsubmitted_crash_dialog_checkbox_label),
+ style = FirefoxTheme.typography.subtitle1,
)
+ }
- Spacer(modifier = Modifier.height(16.dp))
-
- Row(
- horizontalArrangement = Arrangement.SpaceBetween,
- modifier = Modifier.fillMaxWidth(),
- ) {
- Text(
- text = stringResource(R.string.unsubmitted_crash_requested_by_devs_learn_more).uppercase(),
- color = FirefoxTheme.colors.actionPrimary,
- modifier = Modifier.clickable {
- if (cardContext != null) {
- SupportUtils.launchSandboxCustomTab(
- context = cardContext,
- url = SupportUtils.getSumoURLForTopic(
- context = cardContext,
- topic = SupportUtils.SumoTopic.REQUESTED_CRASH_MINIDUMP,
- ),
- )
- }
- },
- )
- Text(
- text = stringResource(R.string.unsubmitted_crash_requested_by_devs_dialog_never_button).uppercase(),
- color = FirefoxTheme.colors.textSecondary,
- modifier = Modifier.clickable {
- dispatcher(CrashAction.CancelForEverTapped)
- dismiss()
- },
- )
- }
- Spacer(modifier = Modifier.height(16.dp))
+ Row(
+ horizontalArrangement = Arrangement.spacedBy(
+ space = 8.dp,
+ alignment = Alignment.End,
+ ),
+ modifier = Modifier.fillMaxWidth(),
+ ) {
+ TextButton(
+ text = stringResource(R.string.unsubmitted_crash_dialog_negative_button_2),
+ onClick = {
+ dispatcher(CrashAction.CancelTapped)
+ dismiss()
+ },
+ )
- Row(
- horizontalArrangement = Arrangement.SpaceBetween,
- modifier = Modifier.fillMaxWidth(),
- ) {
- Text(
- text = stringResource(R.string.unsubmitted_crash_dialog_negative_button).uppercase(),
- color = FirefoxTheme.colors.textSecondary,
- modifier = Modifier.clickable {
- dispatcher(CrashAction.CancelTapped)
- dismiss()
- },
- )
- Text(
- text = stringResource(R.string.unsubmitted_crash_dialog_positive_button).uppercase(),
- color = FirefoxTheme.colors.textSecondary,
- modifier = Modifier.clickable {
- dispatcher(
- CrashAction.ReportTapped(
- automaticallySendChecked = false,
- crashIDs = crashIDs,
- ),
- )
- dismiss()
- },
- )
- }
+ TextButton(
+ text = stringResource(R.string.unsubmitted_crash_dialog_positive_button_2),
+ onClick = {
+ dispatcher(
+ CrashAction.ReportTapped(
+ checkboxChecked,
+ listOf(),
+ ),
+ )
+ dismiss()
+ },
+ )
}
}
}
@@ -306,7 +239,7 @@ private fun AnnotatedStringBody() {
stringResource(R.string.unsubmitted_crash_dialog_learn_more),
),
linkTextStates = listOf(linkStateLearnMore),
- style = FirefoxTheme.typography.body2.copy(FirefoxTheme.colors.textPrimary),
+ style = FirefoxTheme.typography.body2,
linkTextColor = MaterialTheme.colorScheme.tertiary,
linkTextDecoration = TextDecoration.Underline,
textAlign = null,
@@ -314,30 +247,109 @@ private fun AnnotatedStringBody() {
)
}
-@PreviewLightDark
@Composable
-private fun CrashDialogPreview() {
- FirefoxTheme {
- Box(Modifier.background(FirefoxTheme.colors.layer1)) {
- CrashCard(
- dismiss = {},
- dispatcher = {},
- crashIDs = null,
- cardContext = null,
+private fun CrashPullDialog(
+ msg: String,
+ dismiss: () -> Unit,
+ dispatcher: (action: CrashAction) -> Unit,
+ crashIDs: List<String>,
+ cardContext: Context?,
+) {
+ Column(modifier = Modifier.padding(16.dp)) {
+ Text(
+ text = msg,
+ modifier = Modifier
+ .semantics { heading() },
+ style = FirefoxTheme.typography.headline5,
+ )
+
+ Spacer(modifier = Modifier.height(16.dp))
+
+ Row(
+ horizontalArrangement = Arrangement.SpaceBetween,
+ modifier = Modifier.fillMaxWidth(),
+ ) {
+ Text(
+ text = stringResource(R.string.unsubmitted_crash_requested_by_devs_learn_more).uppercase(),
+ color = MaterialTheme.colorScheme.tertiary,
+ modifier = Modifier.clickable {
+ if (cardContext != null) {
+ SupportUtils.launchSandboxCustomTab(
+ context = cardContext,
+ url = SupportUtils.getSumoURLForTopic(
+ context = cardContext,
+ topic = SupportUtils.SumoTopic.REQUESTED_CRASH_MINIDUMP,
+ ),
+ )
+ }
+ },
+ )
+
+ Text(
+ text = stringResource(R.string.unsubmitted_crash_requested_by_devs_dialog_never_button).uppercase(),
+ color = MaterialTheme.colorScheme.onSurfaceVariant,
+ modifier = Modifier.clickable {
+ dispatcher(CrashAction.CancelForEverTapped)
+ dismiss()
+ },
+ )
+ }
+
+ Spacer(modifier = Modifier.height(16.dp))
+
+ Row(
+ horizontalArrangement = Arrangement.SpaceBetween,
+ modifier = Modifier.fillMaxWidth(),
+ ) {
+ Text(
+ text = stringResource(R.string.unsubmitted_crash_dialog_negative_button).uppercase(),
+ color = MaterialTheme.colorScheme.onSurfaceVariant,
+ modifier = Modifier.clickable {
+ dispatcher(CrashAction.CancelTapped)
+ dismiss()
+ },
+ )
+
+ Text(
+ text = stringResource(R.string.unsubmitted_crash_dialog_positive_button).uppercase(),
+ color = MaterialTheme.colorScheme.onSurfaceVariant,
+ modifier = Modifier.clickable {
+ dispatcher(
+ CrashAction.ReportTapped(
+ automaticallySendChecked = false,
+ crashIDs = crashIDs,
+ ),
+ )
+ dismiss()
+ },
)
}
}
}
+private data class CrashDialogState(
+ val crashIDs: List<String>?,
+)
+
+private class CrashDialogPreviewProvider : PreviewParameterProvider<CrashDialogState> {
+ override val values = sequenceOf(
+ CrashDialogState(crashIDs = null),
+ CrashDialogState(crashIDs = listOf("12345")),
+ CrashDialogState(crashIDs = listOf("12345", "67890")),
+ )
+}
+
@PreviewLightDark
@Composable
-private fun CrashPullDialogPreview() {
+private fun UnsubmittedCrashDialogPreview(
+ @PreviewParameter(CrashDialogPreviewProvider::class) state: CrashDialogState,
+) {
FirefoxTheme {
- Box(Modifier.background(FirefoxTheme.colors.layer1)) {
+ Column(modifier = Modifier.padding(all = 16.dp)) {
CrashCard(
dismiss = {},
dispatcher = {},
- crashIDs = listOf("12345", "67890"),
+ crashIDs = state.crashIDs,
cardContext = null,
)
}