tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit f5de84c293fd05b61d9d26eac45bdab8fbe05be8
parent 9d5ec4665d21c6cee93f48db44d1a397affbc07c
Author: Gabriel Luong <gabriel.luong@gmail.com>
Date:   Tue,  2 Dec 2025 08:19:08 +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:
Mmobile/android/android-components/components/compose/base/src/main/java/mozilla/components/compose/base/button/Button.kt | 90++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/startupCrash/StartupCrashScreen.kt | 103+++++++++++++++++++++++++++++--------------------------------------------------
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) } }