commit cdd682ab2802c92056b33708ef17aa01c0f087f4
parent d1ae802dbccaa038131e46502ece12ce222002c1
Author: Gabriel Luong <gabriel.luong@gmail.com>
Date: Sat, 6 Dec 2025 00:11:44 +0000
Bug 1997968 - Part 5: Migrate Filters and SelectableChip to use M3 Acorn color tokens r=android-reviewers,007
Chips: https://www.figma.com/design/MjufE1X5fvkxZ0YneX4kRd/Android-Library--2025-?node-id=63942-32895&m=dev
Differential Revision: https://phabricator.services.mozilla.com/D271136
Diffstat:
5 files changed, 90 insertions(+), 133 deletions(-)
diff --git a/mobile/android/android-components/components/compose/base/src/main/java/mozilla/components/compose/base/SelectableChip.kt b/mobile/android/android-components/components/compose/base/src/main/java/mozilla/components/compose/base/SelectableChip.kt
@@ -4,32 +4,33 @@
package mozilla.components.compose.base
-import androidx.compose.foundation.BorderStroke
-import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.FilterChip
-import androidx.compose.material3.FilterChipDefaults.filterChipColors
+import androidx.compose.material3.FilterChipDefaults
import androidx.compose.material3.Icon
-import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.SelectableChipColors
+import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
+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 mozilla.components.ui.icons.R as iconsR
/**
* Default layout of a selectable chip.
*
* @param text [String] displayed in this chip.
- * @param isSelected Whether this should be shown as selected.
+ * @param selected Whether this should be shown as selected.
* @param modifier [Modifier] used to be applied to the layout of the chip.
* @param selectableChipColors The color set defined by [SelectableChipColors] used to style the chip.
* @param onClick Callback for when the user taps this chip.
@@ -37,109 +38,67 @@ import mozilla.components.ui.icons.R as iconsR
@Composable
fun SelectableChip(
text: String,
- isSelected: Boolean,
+ selected: Boolean,
modifier: Modifier = Modifier,
- selectableChipColors: SelectableChipColors = SelectableChipColors.buildColors(),
+ colors: SelectableChipColors = FilterChipDefaults.filterChipColors(),
onClick: () -> Unit,
) {
FilterChip(
- selected = isSelected,
- modifier = modifier,
+ selected = selected,
onClick = onClick,
+ modifier = modifier,
label = {
Text(
text = text,
- color = AcornTheme.colors.textPrimary,
- style = if (isSelected) AcornTheme.typography.headline8 else AcornTheme.typography.body2,
+ style = if (selected) AcornTheme.typography.headline8 else AcornTheme.typography.body2,
)
},
- leadingIcon = if (isSelected) {
+ leadingIcon = if (selected) {
{
Icon(
painter = painterResource(id = iconsR.drawable.mozac_ic_checkmark_16),
contentDescription = null,
- tint = AcornTheme.colors.iconPrimary,
)
}
} else {
null
},
- colors = selectableChipColors.toMaterialChipColors(),
+ colors = colors,
shape = RoundedCornerShape(16.dp),
- border = if (isSelected) {
- null
- } else {
- BorderStroke(width = 1.dp, color = selectableChipColors.borderColor)
- },
)
}
-/**
- * Wrapper for the color parameters of [SelectableChip].
- *
- * @property selectedContainerColor Background [Color] when the chip is selected.
- * @property containerColor Background [Color] when the chip is not selected.
- * @property selectedLabelColor Text [Color] when the chip is selected.
- * @property labelColor Text [Color] when the chip is not selected.
- * @property borderColor Border [Color] for the chip.
- */
-data class SelectableChipColors(
- val selectedContainerColor: Color,
- val containerColor: Color,
- val selectedLabelColor: Color,
- val labelColor: Color,
- val borderColor: Color,
-) {
-
- /**
- * @see [SelectableChipColors]
- */
- companion object {
-
- /**
- * Builder function used to construct an instance of [SelectableChipColors].
- */
- @Composable
- @ReadOnlyComposable
- fun buildColors(
- selectedContainerColor: Color = AcornTheme.colors.actionChipSelected,
- containerColor: Color = AcornTheme.colors.layer1,
- selectedLabelColor: Color = AcornTheme.colors.textPrimary,
- labelColor: Color = AcornTheme.colors.textPrimary,
- borderColor: Color = AcornTheme.colors.borderPrimary,
- ) = SelectableChipColors(
- selectedContainerColor = selectedContainerColor,
- containerColor = containerColor,
- selectedLabelColor = selectedLabelColor,
- labelColor = labelColor,
- borderColor = borderColor,
- )
- }
-}
-
-/**
- * Map applications' colors for selectable chips to the platform type.
- */
-@Composable
-private fun SelectableChipColors.toMaterialChipColors() = filterChipColors(
- selectedContainerColor = selectedContainerColor,
- containerColor = containerColor,
- selectedLabelColor = selectedLabelColor,
- labelColor = labelColor,
-)
-
@Composable
@PreviewLightDark
private fun SelectableChipPreview() {
AcornTheme {
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .background(MaterialTheme.colorScheme.surface),
- horizontalArrangement = Arrangement.SpaceEvenly,
- ) {
- SelectableChip(text = "ChirpOne", isSelected = false) {}
- SelectableChip(text = "ChirpTwo", isSelected = true) {}
+ Surface {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceEvenly,
+ ) {
+ SelectableChip(text = "ChirpOne", selected = false) {}
+ SelectableChip(text = "ChirpTwo", selected = true) {}
+ }
+ }
+ }
+}
+
+@Composable
+@Preview
+private fun SelectableChipPrivatePreview() {
+ AcornTheme(
+ colors = privateColorPalette,
+ colorScheme = acornPrivateColorScheme(),
+ ) {
+ Surface {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceEvenly,
+ ) {
+ SelectableChip(text = "ChirpOne", selected = false) {}
+ SelectableChip(text = "ChirpTwo", selected = true) {}
+ }
}
}
}
@@ -148,37 +107,36 @@ private fun SelectableChipPreview() {
@PreviewLightDark
private fun SelectableChipWithCustomColorsPreview() {
AcornTheme {
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .background(MaterialTheme.colorScheme.surface),
- horizontalArrangement = Arrangement.SpaceEvenly,
- ) {
- SelectableChip(
- text = "Yellow",
- isSelected = false,
- selectableChipColors = SelectableChipColors(
- selectedContainerColor = Color.Yellow,
- containerColor = Color.DarkGray,
- selectedLabelColor = Color.Black,
- labelColor = Color.Gray,
- borderColor = Color.Red,
- ),
- onClick = {},
- )
+ Surface {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceEvenly,
+ ) {
+ SelectableChip(
+ text = "Yellow",
+ selected = false,
+ colors = FilterChipDefaults.filterChipColors(
+ selectedContainerColor = Color.Yellow,
+ containerColor = Color.DarkGray,
+ selectedLabelColor = Color.Black,
+ labelColor = Color.Gray,
+ ),
+ onClick = {},
+ )
- SelectableChip(
- text = "Cyan",
- isSelected = true,
- selectableChipColors = SelectableChipColors(
- selectedContainerColor = Color.Cyan,
- containerColor = Color.DarkGray,
- selectedLabelColor = Color.Red,
- labelColor = Color.Gray,
- borderColor = Color.Red,
- ),
- onClick = {},
- )
+ SelectableChip(
+ text = "Cyan",
+ selected = true,
+ colors = FilterChipDefaults.filterChipColors(
+ selectedContainerColor = Color.Cyan,
+ containerColor = Color.DarkGray,
+ selectedLabelColor = Color.Red,
+ selectedLeadingIconColor = Color.Red,
+ labelColor = Color.Gray,
+ ),
+ onClick = {},
+ )
+ }
}
}
}
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/downloads/listscreen/ui/Filters.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/downloads/listscreen/ui/Filters.kt
@@ -4,14 +4,13 @@
package org.mozilla.fenix.downloads.listscreen.ui
-import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
+import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@@ -55,7 +54,7 @@ internal fun Filters(
) { contentTypeParam ->
SelectableChip(
text = stringResource(id = contentTypeParam.stringRes),
- isSelected = selectedContentTypeFilter == contentTypeParam,
+ selected = selectedContentTypeFilter == contentTypeParam,
modifier = Modifier.height(36.dp),
onClick = { onContentTypeSelected(contentTypeParam) },
)
@@ -78,9 +77,7 @@ private fun FiltersPreview() {
FirefoxTheme {
var selectedContentTypeFilter by remember { mutableStateOf(FileItem.ContentTypeFilter.All) }
- Box(
- modifier = Modifier.background(FirefoxTheme.colors.layer1),
- ) {
+ Surface {
Filters(
selectedContentTypeFilter = selectedContentTypeFilter,
contentTypeFilters = FileItem.ContentTypeFilter.entries,
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
@@ -5,13 +5,13 @@
package org.mozilla.fenix.home.fake
import android.content.Context
+import androidx.compose.material3.FilterChipDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
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.SelectableChipColors
import mozilla.components.concept.engine.Engine
import mozilla.components.concept.sync.DeviceType
import mozilla.components.feature.tab.collections.Tab
@@ -52,7 +52,6 @@ import org.mozilla.fenix.home.sessioncontrol.CollectionInteractor
import org.mozilla.fenix.home.store.NimbusMessageState
import org.mozilla.fenix.home.topsites.interactor.TopSiteInteractor
import org.mozilla.fenix.search.toolbar.SearchSelectorMenu
-import org.mozilla.fenix.theme.FirefoxTheme
import org.mozilla.fenix.wallpapers.WallpaperState
import java.io.File
import java.util.UUID
@@ -411,8 +410,8 @@ internal object FakeHomepagePreview {
.split(" ")
.map { PocketRecommendedStoriesCategory(it) },
categoriesSelections = emptyList(),
- categoryColors = SelectableChipColors.buildColors(),
- textColor = FirefoxTheme.colors.textPrimary,
+ categoryColors = FilterChipDefaults.filterChipColors(),
+ textColor = MaterialTheme.colorScheme.onSurface,
linkTextColor = MaterialTheme.colorScheme.tertiary,
showDiscoverMoreButton = false,
)
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/home/pocket/PocketState.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/home/pocket/PocketState.kt
@@ -5,10 +5,11 @@
package org.mozilla.fenix.home.pocket
import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material3.FilterChipDefaults
import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.SelectableChipColors
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
-import mozilla.components.compose.base.SelectableChipColors
import mozilla.components.service.pocket.PocketStory
import org.mozilla.fenix.components.appstate.AppState
import org.mozilla.fenix.theme.FirefoxTheme
@@ -74,12 +75,14 @@ data class PocketState(
@Composable
private fun AppState.getSelectableChipColors(): SelectableChipColors {
- var (selectedContainerColor, containerColor, selectedLabelColor, labelColor, borderColor) =
- SelectableChipColors.buildColors()
+ var selectedLabelColor = Color.Unspecified
+ var labelColor = Color.Unspecified
+ var selectedContainerColor = Color.Unspecified
+ var containerColor = Color.Unspecified
wallpaperState.ComposeRunIfWallpaperCardColorsAreAvailable { cardColorLight, cardColorDark ->
- selectedLabelColor = FirefoxTheme.colors.textPrimary
- labelColor = FirefoxTheme.colors.textInverted
+ selectedLabelColor = MaterialTheme.colorScheme.onSurface
+ labelColor = MaterialTheme.colorScheme.inverseOnSurface
if (isSystemInDarkTheme()) {
selectedContainerColor = cardColorDark
@@ -90,11 +93,10 @@ private fun AppState.getSelectableChipColors(): SelectableChipColors {
}
}
- return SelectableChipColors(
+ return FilterChipDefaults.filterChipColors(
selectedLabelColor = selectedLabelColor,
labelColor = labelColor,
selectedContainerColor = selectedContainerColor,
containerColor = containerColor,
- borderColor = borderColor,
)
}
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/home/pocket/ui/StoriesCategories.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/home/pocket/ui/StoriesCategories.kt
@@ -7,6 +7,8 @@ package org.mozilla.fenix.home.pocket.ui
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.FlowRow
+import androidx.compose.material3.FilterChipDefaults
+import androidx.compose.material3.SelectableChipColors
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.semantics
@@ -14,7 +16,6 @@ import androidx.compose.ui.semantics.testTag
import androidx.compose.ui.semantics.testTagsAsResourceId
import androidx.compose.ui.unit.dp
import mozilla.components.compose.base.SelectableChip
-import mozilla.components.compose.base.SelectableChipColors
import org.mozilla.fenix.home.pocket.POCKET_STORIES_DEFAULT_CATEGORY_NAME
import org.mozilla.fenix.home.pocket.PocketRecommendedStoriesCategory
import org.mozilla.fenix.home.pocket.PocketRecommendedStoriesSelectedCategory
@@ -33,7 +34,7 @@ fun StoriesCategories(
categories: List<PocketRecommendedStoriesCategory>,
selections: List<PocketRecommendedStoriesSelectedCategory>,
modifier: Modifier = Modifier,
- categoryColors: SelectableChipColors = SelectableChipColors.buildColors(),
+ categoryColors: SelectableChipColors = FilterChipDefaults.filterChipColors(),
onCategoryClick: (PocketRecommendedStoriesCategory) -> Unit,
) {
Box(
@@ -50,8 +51,8 @@ fun StoriesCategories(
.forEach { category ->
SelectableChip(
text = category.name,
- isSelected = selections.map { it.name }.contains(category.name),
- selectableChipColors = categoryColors,
+ selected = selections.map { it.name }.contains(category.name),
+ colors = categoryColors,
) {
onCategoryClick(category)
}