commit fe68a75831292b6e4aa1d7db4c5b22b62d2d9a3b
parent aedb1c618ad62613dd09ac3eb672c0fe62815840
Author: Gabriel Luong <gabriel.luong@gmail.com>
Date: Tue, 2 Dec 2025 16:41:28 +0000
Bug 2003337 - Migrate StartupCrashScreen to M3 specs r=android-reviewers,007
- Figma: https://www.figma.com/design/CaopY3iqHHpyLYjhhR78wI/In-app-Crash-Reporter?node-id=891-9466&m=dev
Differential Revision: https://phabricator.services.mozilla.com/D274623
Diffstat:
2 files changed, 120 insertions(+), 73 deletions(-)
diff --git a/mobile/android/android-components/components/compose/base/src/main/java/mozilla/components/compose/base/button/Button.kt b/mobile/android/android-components/components/compose/base/src/main/java/mozilla/components/compose/base/button/Button.kt
@@ -5,7 +5,6 @@
package mozilla.components.compose.base.button
import androidx.compose.foundation.BorderStroke
-import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
@@ -14,8 +13,10 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ButtonDefaults.outlinedButtonBorder
+import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
@@ -25,9 +26,12 @@ import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import mozilla.components.compose.base.theme.AcornTheme
+import mozilla.components.compose.base.theme.acornPrivateColorScheme
+import mozilla.components.compose.base.theme.privateColorPalette
import androidx.compose.material3.Button as M3Button
import androidx.compose.material3.OutlinedButton as M3OutlinedButton
import mozilla.components.ui.icons.R as iconsR
@@ -59,6 +63,7 @@ private fun ButtonContent(
)
Spacer(modifier = Modifier.width(AcornTheme.layout.space.static100))
}
+
Text(
text = text,
textAlign = TextAlign.Center,
@@ -106,6 +111,40 @@ fun FilledButton(
}
/**
+ * Filled button.
+ *
+ * @param onClick Invoked when the user clicks on the button.
+ * @param modifier [Modifier] to be applied to the layout.
+ * @param enabled Controls the enabled state of the button.
+ * When false, this button will not be clickable.
+ * @param contentColor The color to be used for the button's text and icon when enabled.
+ * @param containerColor The background color of the button when enabled.
+ * @param content [Composable] content to be displayed in the button.
+ */
+@Composable
+fun FilledButton(
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true,
+ contentColor: Color = ButtonDefaults.buttonColors().contentColor,
+ containerColor: Color = ButtonDefaults.buttonColors().containerColor,
+ content: @Composable () -> Unit,
+) {
+ M3Button(
+ onClick = onClick,
+ modifier = modifier,
+ enabled = enabled,
+ contentPadding = AcornTheme.buttonContentPadding(),
+ colors = ButtonDefaults.buttonColors(
+ containerColor = containerColor,
+ contentColor = contentColor,
+ ),
+ ) {
+ content()
+ }
+}
+
+/**
* Outlined button.
*
* @param text The button text to be displayed.
@@ -191,17 +230,19 @@ fun DestructiveButton(
}
@Composable
-@PreviewLightDark
-private fun ButtonPreview() {
- AcornTheme {
+private fun ButtonPreviewContent() {
+ Surface {
Column(
- modifier = Modifier
- .background(MaterialTheme.colorScheme.surface)
- .padding(16.dp),
+ modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
FilledButton(
text = "Label",
+ onClick = {},
+ )
+
+ FilledButton(
+ text = "Label",
icon = painterResource(iconsR.drawable.mozac_ic_collection_24),
onClick = {},
)
@@ -213,6 +254,17 @@ private fun ButtonPreview() {
onClick = {},
)
+ FilledButton(
+ onClick = {},
+ ) {
+ CircularProgressIndicator(color = MaterialTheme.colorScheme.onPrimary)
+ }
+
+ OutlinedButton(
+ text = "Label",
+ onClick = {},
+ )
+
OutlinedButton(
text = "Label",
icon = painterResource(iconsR.drawable.mozac_ic_collection_24),
@@ -228,6 +280,11 @@ private fun ButtonPreview() {
DestructiveButton(
text = "Label",
+ onClick = {},
+ )
+
+ DestructiveButton(
+ text = "Label",
icon = painterResource(iconsR.drawable.mozac_ic_collection_24),
onClick = {},
)
@@ -241,3 +298,22 @@ private fun ButtonPreview() {
}
}
}
+
+@Composable
+@PreviewLightDark
+private fun ButtonPreview() {
+ AcornTheme {
+ ButtonPreviewContent()
+ }
+}
+
+@Composable
+@Preview
+private fun ButtonPrivatePreview() {
+ AcornTheme(
+ colors = privateColorPalette,
+ colorScheme = acornPrivateColorScheme(),
+ ) {
+ ButtonPreviewContent()
+ }
+}
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/startupCrash/StartupCrashScreen.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/startupCrash/StartupCrashScreen.kt
@@ -5,24 +5,20 @@
package org.mozilla.fenix.startupCrash
import androidx.compose.foundation.Image
-import androidx.compose.foundation.background
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
-import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
-import androidx.compose.material3.Button
-import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.CircularProgressIndicator
-import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@@ -36,6 +32,8 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import mozilla.components.compose.base.annotation.FlexibleWindowLightDarkPreview
+import mozilla.components.compose.base.button.FilledButton
+import mozilla.components.compose.base.button.OutlinedButton
import mozilla.components.lib.state.ext.observeAsComposableState
import org.mozilla.fenix.R
import org.mozilla.fenix.theme.FirefoxTheme
@@ -47,16 +45,21 @@ internal fun StartupCrashScreen(store: StartupCrashStore) {
val scrollState = rememberScrollState()
Column(
- horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxSize()
.verticalScroll(scrollState)
- .padding(top = 74.dp, bottom = 97.dp, start = 16.dp, end = 16.dp),
+ .padding(horizontal = 16.dp),
+ verticalArrangement = Arrangement.Center,
+ horizontalAlignment = Alignment.CenterHorizontally,
) {
ScreenImg()
+ Spacer(modifier = Modifier.height(16.dp))
+
ScreenText()
+ Spacer(modifier = Modifier.height(24.dp))
+
when (state.uiState) {
UiState.Idle -> {
ReportButtons(store)
@@ -73,78 +76,49 @@ internal fun StartupCrashScreen(store: StartupCrashStore) {
@Composable
private fun ReportButtons(store: StartupCrashStore) {
- Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
- Button(
- onClick = { store.dispatch(ReportTapped) },
- shape = RoundedCornerShape(4.dp),
- colors = ButtonDefaults.buttonColors(
- containerColor = FirefoxTheme.colors.actionPrimary,
- contentColor = FirefoxTheme.colors.textActionPrimary,
- ),
+ Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
+ FilledButton(
+ text = stringResource(R.string.startup_crash_positive),
modifier = Modifier.fillMaxWidth(),
) {
- Text(stringResource(R.string.startup_crash_positive))
+ store.dispatch(ReportTapped)
}
- Button(
- onClick = { store.dispatch(NoTapped) },
- shape = RoundedCornerShape(4.dp),
- colors = ButtonDefaults.buttonColors(
- containerColor = FirefoxTheme.colors.actionSecondary,
- contentColor = FirefoxTheme.colors.textActionSecondary,
- ),
+
+ OutlinedButton(
+ text = stringResource(R.string.startup_crash_negative),
modifier = Modifier.fillMaxWidth(),
) {
- Text(stringResource(R.string.startup_crash_negative))
+ store.dispatch(NoTapped)
}
}
}
@Composable
private fun ReopenButton(store: StartupCrashStore) {
- Button(
- onClick = { store.dispatch(ReopenTapped) },
- shape = RoundedCornerShape(4.dp),
- colors = ButtonDefaults.buttonColors(
- containerColor = FirefoxTheme.colors.actionPrimary,
- contentColor = FirefoxTheme.colors.textActionPrimary,
+ FilledButton(
+ text = stringResource(
+ R.string.startup_crash_restart,
+ stringResource(R.string.firefox),
),
- modifier = Modifier
- .padding(bottom = 8.dp)
- .fillMaxWidth(),
+ modifier = Modifier.fillMaxWidth(),
+ icon = painterResource(iconsR.drawable.mozac_ic_checkmark_24),
) {
- Icon(
- painter = painterResource(iconsR.drawable.mozac_ic_checkmark_24),
- contentDescription = null,
- tint = FirefoxTheme.colors.textActionPrimary,
- )
- Spacer(Modifier.width(8.dp))
- Text(
- stringResource(
- R.string.startup_crash_restart,
- stringResource(R.string.firefox),
- ),
- )
+ store.dispatch(ReopenTapped)
}
}
@Composable
private fun CircularLoadButton() {
- Button(
- onClick = { },
+ FilledButton(
+ onClick = {},
+ modifier = Modifier.fillMaxWidth(),
enabled = false,
- modifier = Modifier
- .fillMaxWidth(),
- shape = RoundedCornerShape(4.dp),
- colors = ButtonDefaults.buttonColors(
- disabledContainerColor = FirefoxTheme.colors.actionPrimaryDisabled,
- disabledContentColor = FirefoxTheme.colors.textActionPrimaryDisabled,
- ),
) {
CircularProgressIndicator(
+ modifier = Modifier.size(18.dp),
+ color = MaterialTheme.colorScheme.inverseOnSurface,
strokeWidth = 2.dp,
- modifier = Modifier
- .size(24.dp),
- color = FirefoxTheme.colors.actionPrimaryDisabled,
+ trackColor = MaterialTheme.colorScheme.primary,
)
}
}
@@ -158,7 +132,6 @@ private fun ScreenImg() {
painterResource(id = R.drawable.fox_alert_crash_dark)
},
contentDescription = null,
- modifier = Modifier.padding(bottom = 24.dp),
)
}
@@ -167,24 +140,22 @@ private fun ScreenText() {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
- modifier = Modifier
- .padding(bottom = 32.dp)
- .fillMaxWidth(),
+ modifier = Modifier.fillMaxWidth(),
) {
Text(
text = stringResource(
R.string.startup_crash_title,
stringResource(R.string.firefox),
),
- color = FirefoxTheme.colors.textPrimary,
style = FirefoxTheme.typography.headline5,
)
+
Text(
text = stringResource(
R.string.startup_crash_body,
stringResource(R.string.firefox),
),
- color = FirefoxTheme.colors.textSecondary,
+ color = MaterialTheme.colorScheme.onSurfaceVariant,
style = FirefoxTheme.typography.body2,
textAlign = TextAlign.Center,
)
@@ -211,7 +182,7 @@ internal fun StartupCrashScreenPreview(
)
}
FirefoxTheme {
- Box(modifier = Modifier.background(FirefoxTheme.colors.layer2)) {
+ Surface {
StartupCrashScreen(store)
}
}