commit 4494dbcf540bfe146e07d21d4d21179c892115d8
parent 78bb0dc552f20c0e49ef74c98c172a9107b966fe
Author: John Oberhauser <j.git-global@obez.io>
Date: Tue, 9 Dec 2025 06:25:19 +0000
Bug 2003325 - Part 2: Refactoring MessageCard to use the new Banner base compose component r=android-reviewers,devota,mavduevskiy
Differential Revision: https://phabricator.services.mozilla.com/D274816
Diffstat:
2 files changed, 84 insertions(+), 211 deletions(-)
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/compose/MessageCard.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/compose/MessageCard.kt
@@ -6,39 +6,23 @@ package org.mozilla.fenix.compose
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-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.shape.RoundedCornerShape
-import androidx.compose.material3.ButtonDefaults
-import androidx.compose.material3.Card
-import androidx.compose.material3.CardDefaults
-import androidx.compose.material3.Icon
-import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
-import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
-import mozilla.components.compose.base.button.FilledButton
+import mozilla.components.compose.base.Banner
+import mozilla.components.compose.base.BannerColors
import mozilla.components.service.nimbus.messaging.Message
import org.mozilla.fenix.R
import org.mozilla.fenix.home.fake.FakeHomepagePreview
import org.mozilla.fenix.theme.FirefoxTheme
-import org.mozilla.fenix.wallpapers.Wallpaper
+import org.mozilla.fenix.theme.Theme
import org.mozilla.fenix.wallpapers.WallpaperState
-import mozilla.components.ui.icons.R as iconsR
/**
* State-based Message Card.
@@ -56,183 +40,53 @@ fun MessageCard(
onCloseButtonClick: () -> Unit = {},
) {
with(messageCardState) {
- MessageCard(
+ Banner(
messageText = messageText,
- modifier = modifier,
- titleText = titleText,
- buttonText = buttonText,
- messageColors = messageColors,
- onClick = onClick,
- onCloseButtonClick = onCloseButtonClick,
- )
- }
-}
-
-/**
- * Message Card.
- *
- * @param messageText The message card's body text to be displayed.
- * @param modifier Modifier to be applied to the card.
- * @param titleText An optional title of message card. If the provided title text is blank or null,
- * the title will not be shown.
- * @param buttonText An optional button text of the message card. If the provided button text is blank or null,
- * the button won't be shown.
- * @param messageColors The color set defined by [MessageCardColors] used to style the message card.
- * @param onClick Invoked when user clicks on the message card.
- * @param onCloseButtonClick Invoked when user clicks on close button to remove message.
- */
-@Suppress("LongMethod")
-@Composable
-fun MessageCard(
- messageText: String,
- modifier: Modifier = Modifier,
- titleText: String? = null,
- buttonText: String? = null,
- messageColors: MessageCardColors = MessageCardColors.buildMessageCardColors(),
- onClick: () -> Unit,
- onCloseButtonClick: () -> Unit,
-) {
- Card(
- modifier = modifier
- .padding(vertical = 16.dp)
- .then(
+ modifier = modifier
+ .then(
if (buttonText.isNullOrBlank()) {
Modifier.clickable(onClick = onClick)
} else {
Modifier
},
),
- shape = RoundedCornerShape(16.dp),
- border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant),
- colors = CardDefaults.cardColors(containerColor = messageColors.backgroundColor),
- ) {
- Column(
- Modifier
- .padding(all = 16.dp)
- .fillMaxWidth(),
- ) {
- if (!titleText.isNullOrBlank()) {
- Row(
- modifier = Modifier.fillMaxWidth(),
- ) {
- Text(
- text = titleText,
- modifier = Modifier.weight(1f),
- color = messageColors.titleTextColor,
- overflow = TextOverflow.Ellipsis,
- maxLines = 2,
- style = FirefoxTheme.typography.headline7,
- )
-
- MessageCardIconButton(
- iconTint = messageColors.iconColor,
- onCloseButtonClick = onCloseButtonClick,
- )
- }
-
- Text(
- text = messageText,
- modifier = Modifier.fillMaxWidth(),
- fontSize = 14.sp,
- color = messageColors.messageTextColor,
- )
- } else {
- Row(
- modifier = Modifier.fillMaxWidth(),
- ) {
- Text(
- text = messageText,
- modifier = Modifier.weight(1f),
- fontSize = 14.sp,
- color = messageColors.titleTextColor,
- )
-
- MessageCardIconButton(
- iconTint = messageColors.iconColor,
- onCloseButtonClick = onCloseButtonClick,
- )
- }
- }
-
- if (!buttonText.isNullOrBlank()) {
- Spacer(modifier = Modifier.height(16.dp))
-
- FilledButton(
- text = buttonText,
- modifier = Modifier.fillMaxWidth(),
- contentColor = messageColors.buttonTextColor,
- containerColor = messageColors.buttonColor,
- onClick = onClick,
- )
- }
- }
+ titleText = titleText,
+ positiveButtonText = buttonText,
+ positiveOnClick = onClick,
+ colors = bannerColors,
+ border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant),
+ onCloseButtonClick = onCloseButtonClick,
+ )
}
}
-/**
- * IconButton within a MessageCard.
- *
- * @param iconTint The [Color] used to tint the button's icon.
- * @param onCloseButtonClick Invoked when user clicks on close button to remove message.
- */
@Composable
-private fun MessageCardIconButton(
- iconTint: Color,
- onCloseButtonClick: () -> Unit,
-) {
- IconButton(
- modifier = Modifier.size(20.dp),
- onClick = onCloseButtonClick,
- ) {
- Icon(
- painter = painterResource(iconsR.drawable.mozac_ic_cross_20),
- contentDescription = stringResource(
- R.string.content_description_close_button,
- ),
- tint = iconTint,
- )
+@PreviewLightDark
+private fun MessageCardPreview() {
+ FirefoxTheme {
+ Surface {
+ MessageCard(
+ messageCardState = FakeHomepagePreview.messageCardState(),
+ modifier = Modifier.padding(all = 16.dp),
+ onClick = {},
+ onCloseButtonClick = {},
+ )
+ }
}
}
-/**
- * Wrapper for the color parameters of [MessageCard].
- *
- * @property backgroundColor The background [Color] of the message.
- * @property titleTextColor [Color] to apply to the message's title, or the body text when there is no title.
- * @property messageTextColor [Color] to apply to the message's body text.
- * @property iconColor [Color] to apply to the message's icon.
- * @property buttonColor The background [Color] of the message's button.
- * @property buttonTextColor [Color] to apply to the button text.
- */
-data class MessageCardColors(
- val backgroundColor: Color,
- val titleTextColor: Color,
- val messageTextColor: Color,
- val iconColor: Color,
- val buttonColor: Color,
- val buttonTextColor: Color,
-) {
- companion object {
-
- /**
- * Builder function used to construct an instance of [MessageCardColors].
- */
- @Composable
- fun buildMessageCardColors(
- backgroundColor: Color = MaterialTheme.colorScheme.surfaceContainerLowest,
- titleTextColor: Color = MaterialTheme.colorScheme.onSurface,
- messageTextColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
- iconColor: Color = MaterialTheme.colorScheme.onSurface,
- buttonColor: Color = ButtonDefaults.buttonColors().containerColor,
- buttonTextColor: Color = ButtonDefaults.buttonColors().contentColor,
- ): MessageCardColors {
- return MessageCardColors(
- backgroundColor = backgroundColor,
- titleTextColor = titleTextColor,
- messageTextColor = messageTextColor,
- iconColor = iconColor,
- buttonColor = buttonColor,
- buttonTextColor = buttonTextColor,
+@Composable
+@Preview
+private fun MessageCardPrivatePreview() {
+ FirefoxTheme(
+ theme = Theme.Private,
+ ) {
+ Surface {
+ MessageCard(
+ messageCardState = FakeHomepagePreview.messageCardState(),
+ modifier = Modifier.padding(all = 16.dp),
+ onClick = {},
+ onCloseButtonClick = {},
)
}
}
@@ -240,11 +94,14 @@ data class MessageCardColors(
@Composable
@PreviewLightDark
-private fun MessageCardPreview() {
+private fun MessageCardWithoutTitlePreview() {
FirefoxTheme {
Surface {
MessageCard(
- messageCardState = FakeHomepagePreview.messageCardState(),
+ messageCardState = MessageCardState(
+ messageText = stringResource(id = R.string.default_browser_experiment_card_text),
+ bannerColors = BannerColors.bannerColors(),
+ ),
modifier = Modifier.padding(all = 16.dp),
onClick = {},
onCloseButtonClick = {},
@@ -254,12 +111,17 @@ private fun MessageCardPreview() {
}
@Composable
-@PreviewLightDark
-private fun MessageCardWithoutTitlePreview() {
- FirefoxTheme {
+@Preview
+private fun MessageCardWithoutTitlePrivatePreview() {
+ FirefoxTheme(
+ theme = Theme.Private,
+ ) {
Surface {
MessageCard(
- messageText = stringResource(id = R.string.default_browser_experiment_card_text),
+ messageCardState = MessageCardState(
+ messageText = stringResource(id = R.string.default_browser_experiment_card_text),
+ bannerColors = BannerColors.bannerColors(),
+ ),
modifier = Modifier.padding(all = 16.dp),
onClick = {},
onCloseButtonClick = {},
@@ -274,10 +136,33 @@ private fun MessageCardWithButtonLabelPreview() {
FirefoxTheme {
Surface {
MessageCard(
- messageText = stringResource(id = R.string.default_browser_experiment_card_text),
- modifier = Modifier.padding(all = 16.dp),
- titleText = stringResource(id = R.string.default_browser_experiment_card_title),
- buttonText = stringResource(id = R.string.preferences_set_as_default_browser),
+ messageCardState = MessageCardState(
+ messageText = stringResource(id = R.string.default_browser_experiment_card_text),
+ titleText = stringResource(id = R.string.default_browser_experiment_card_title),
+ buttonText = stringResource(id = R.string.preferences_set_as_default_browser),
+ bannerColors = BannerColors.bannerColors(),
+ ),
+ onClick = {},
+ onCloseButtonClick = {},
+ )
+ }
+ }
+}
+
+@Composable
+@Preview
+private fun MessageCardWithButtonLabelPrivatePreview() {
+ FirefoxTheme(
+ theme = Theme.Private,
+ ) {
+ Surface {
+ MessageCard(
+ messageCardState = MessageCardState(
+ messageText = stringResource(id = R.string.default_browser_experiment_card_text),
+ titleText = stringResource(id = R.string.default_browser_experiment_card_title),
+ buttonText = stringResource(id = R.string.preferences_set_as_default_browser),
+ bannerColors = BannerColors.bannerColors(),
+ ),
onClick = {},
onCloseButtonClick = {},
)
@@ -293,13 +178,13 @@ private fun MessageCardWithButtonLabelPreview() {
* the title will not be shown.
* @property buttonText An optional button text of the message card. If the provided button text is blank or null,
* the button won't be shown.
- * @property messageColors The color set defined by [MessageCardColors] used to style the message card.
+ * @property bannerColors The color set defined by [BannerColors] used to style the message card.
*/
data class MessageCardState(
val messageText: String,
val titleText: String? = null,
val buttonText: String? = null,
- val messageColors: MessageCardColors,
+ val bannerColors: BannerColors,
) {
/**
@@ -315,27 +200,15 @@ data class MessageCardState(
*/
@Composable
fun build(message: Message, wallpaperState: WallpaperState): MessageCardState {
- val isWallpaperNotDefault =
- !Wallpaper.nameIsDefault(wallpaperState.currentWallpaper.name)
-
- var (_, _, _, _, buttonColor, buttonTextColor) = MessageCardColors.buildMessageCardColors()
-
- if (isWallpaperNotDefault) {
- buttonColor = MaterialTheme.colorScheme.surface
- buttonTextColor = MaterialTheme.colorScheme.onSurface
- }
-
- val messageCardColors = MessageCardColors.buildMessageCardColors(
+ val bannerColors = BannerColors.bannerColors(
backgroundColor = wallpaperState.cardBackgroundColor,
- buttonColor = buttonColor,
- buttonTextColor = buttonTextColor,
)
return MessageCardState(
messageText = message.text,
titleText = message.title,
buttonText = message.buttonLabel,
- messageColors = messageCardColors,
+ bannerColors = bannerColors,
)
}
}
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/home/fake/FakeHomepagePreview.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/home/fake/FakeHomepagePreview.kt
@@ -12,6 +12,7 @@ import androidx.compose.ui.res.stringResource
import mozilla.components.browser.state.state.ContentState
import mozilla.components.browser.state.state.TabSessionState
import mozilla.components.browser.state.state.recover.RecoverableTab
+import mozilla.components.compose.base.BannerColors
import mozilla.components.concept.engine.Engine
import mozilla.components.concept.sync.DeviceType
import mozilla.components.feature.tab.collections.Tab
@@ -27,7 +28,6 @@ import org.mozilla.fenix.R
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.components.appstate.AppState
import org.mozilla.fenix.components.appstate.setup.checklist.ChecklistItem
-import org.mozilla.fenix.compose.MessageCardColors
import org.mozilla.fenix.compose.MessageCardState
import org.mozilla.fenix.ext.CONTENT_RECOMMENDATIONS_TO_SHOW_COUNT
import org.mozilla.fenix.home.bookmarks.Bookmark
@@ -232,7 +232,7 @@ internal object FakeHomepagePreview {
messageText = stringResource(id = R.string.default_browser_experiment_card_text),
titleText = stringResource(id = R.string.default_browser_experiment_card_title),
buttonText = "",
- messageColors = MessageCardColors.buildMessageCardColors(),
+ bannerColors = BannerColors.bannerColors(),
)
internal fun message() = Message(