From 3ba1aab119848242eca94492c1236a6ce0c9021c Mon Sep 17 00:00:00 2001 From: Gabriel Luong Date: Fri, 19 Apr 2024 04:40:30 +0000 Subject: [PATCH] Bug 1891342 - Part 4: Implement enabled, disabled, active and warning states for MenuItem r=android-reviewers,007 Differential Revision: https://phabricator.services.mozilla.com/D207394 --- .../components/menu/compose/MenuDialog.kt | 8 +- .../fenix/components/menu/compose/MenuItem.kt | 168 +++++++++++++++++- 2 files changed, 165 insertions(+), 11 deletions(-) diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/menu/compose/MenuDialog.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/menu/compose/MenuDialog.kt index bac79c0dc4a2..e8978539442b 100644 --- a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/menu/compose/MenuDialog.kt +++ b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/menu/compose/MenuDialog.kt @@ -125,32 +125,32 @@ private fun LibraryMenuGroup( MenuGroup { MenuItem( label = stringResource(id = R.string.library_bookmarks), - onClick = onBookmarksMenuClick, beforeIconPainter = painterResource(id = R.drawable.mozac_ic_bookmark_tray_fill_24), + onClick = onBookmarksMenuClick, ) Divider(color = FirefoxTheme.colors.borderSecondary) MenuItem( label = stringResource(id = R.string.library_history), - onClick = onHistoryMenuClick, beforeIconPainter = painterResource(id = R.drawable.mozac_ic_history_24), + onClick = onHistoryMenuClick, ) Divider(color = FirefoxTheme.colors.borderSecondary) MenuItem( label = stringResource(id = R.string.library_downloads), - onClick = onDownloadsMenuClick, beforeIconPainter = painterResource(id = R.drawable.mozac_ic_download_24), + onClick = onDownloadsMenuClick, ) Divider(color = FirefoxTheme.colors.borderSecondary) MenuItem( label = stringResource(id = R.string.browser_menu_passwords), - onClick = onPasswordsMenuClick, beforeIconPainter = painterResource(id = R.drawable.mozac_ic_login_24), + onClick = onPasswordsMenuClick, ) } } diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/menu/compose/MenuItem.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/menu/compose/MenuItem.kt index a8c39c206ccb..179a92cab188 100644 --- a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/menu/compose/MenuItem.kt +++ b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/menu/compose/MenuItem.kt @@ -4,39 +4,56 @@ package org.mozilla.fenix.components.menu.compose +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding import androidx.compose.material.Icon import androidx.compose.material.IconButton import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import org.mozilla.fenix.R +import org.mozilla.fenix.compose.Divider +import org.mozilla.fenix.compose.annotation.LightDarkPreview import org.mozilla.fenix.compose.list.IconListItem import org.mozilla.fenix.theme.FirefoxTheme /** - * Wrapper around [IconListItem] for menu items that appear in a [MenuGroup]. + * An [IconListItem] wrapper for menu items in a [MenuGroup] with an optional icon at the end. * - * @param label The label in the list item. - * @param description An optional description text below the label. - * @param onClick Invoked when the user clicks on the item. + * @param label The label in the menu item. * @param beforeIconPainter [Painter] used to display an [Icon] before the list item. * @param beforeIconDescription Content description of the icon. + * @param description An optional description text below the label. + * @param state The state of the menu item to display. + * @param onClick Invoked when the user clicks on the item. * @param afterIconPainter [Painter] used to display an [IconButton] after the list item. * @param afterIconDescription Content description of the icon. */ @Composable internal fun MenuItem( label: String, - description: String? = null, - onClick: (() -> Unit)? = null, beforeIconPainter: Painter, beforeIconDescription: String? = null, + description: String? = null, + state: MenuItemState = MenuItemState.ENABLED, + onClick: (() -> Unit)? = null, afterIconPainter: Painter? = null, afterIconDescription: String? = null, ) { - val iconTint = FirefoxTheme.colors.iconSecondary + val labelTextColor = getLabelTextColor(state = state) + val iconTint = getIconTint(state = state) + val enabled = state != MenuItemState.DISABLED IconListItem( label = label, + labelTextColor = labelTextColor, description = description, + enabled = enabled, onClick = onClick, beforeIconPainter = beforeIconPainter, beforeIconDescription = beforeIconDescription, @@ -46,3 +63,140 @@ internal fun MenuItem( afterIconTint = iconTint, ) } + +/** + * An [IconListItem] wrapper for menu items in a [MenuGroup] with an optional text button at the end. + * + * @param label The label in the menu item. + * @param beforeIconPainter [Painter] used to display an [Icon] before the list item. + * @param beforeIconDescription Content description of the icon. + * @param description An optional description text below the label. + * @param state The state of the menu item to display. + * @param onClick Invoked when the user clicks on the item. + * @param afterButtonText The button text to be displayed after the list item. + * @param afterButtonTextColor [Color] to apply to [afterButtonText]. + * @param onAfterButtonClick Called when the user clicks on the text button. + */ +@Composable +internal fun MenuItem( + label: String, + beforeIconPainter: Painter, + beforeIconDescription: String? = null, + description: String? = null, + state: MenuItemState = MenuItemState.ENABLED, + onClick: (() -> Unit)? = null, + afterButtonText: String? = null, + afterButtonTextColor: Color = FirefoxTheme.colors.actionPrimary, + onAfterButtonClick: (() -> Unit)? = null, +) { + val labelTextColor = getLabelTextColor(state = state) + val iconTint = getIconTint(state = state) + val enabled = state != MenuItemState.DISABLED + + IconListItem( + label = label, + labelTextColor = labelTextColor, + description = description, + enabled = enabled, + onClick = onClick, + beforeIconPainter = beforeIconPainter, + beforeIconDescription = beforeIconDescription, + beforeIconTint = iconTint, + afterButtonText = afterButtonText, + afterButtonTextColor = afterButtonTextColor, + onAfterButtonClick = onAfterButtonClick, + ) +} + +/** + * Enum containing all the supported state for the menu item. + */ +enum class MenuItemState { + /** + * The menu item is enabled. + */ + ENABLED, + + /** + * The menu item is disabled and is not clickable. + */ + DISABLED, + + /** + * The menu item is highlighted to indicate the feature behind the menu item is active. + */ + ACTIVE, + + /** + * The menu item is highlighted to indicate the feature behind the menu item is destructive. + */ + WARNING, +} + +@Composable +private fun getLabelTextColor(state: MenuItemState): Color { + return when (state) { + MenuItemState.ACTIVE -> FirefoxTheme.colors.textAccent + MenuItemState.WARNING -> FirefoxTheme.colors.textWarning + else -> FirefoxTheme.colors.textPrimary + } +} + +@Composable +private fun getIconTint(state: MenuItemState): Color { + return when (state) { + MenuItemState.ACTIVE -> FirefoxTheme.colors.iconAccentViolet + MenuItemState.WARNING -> FirefoxTheme.colors.iconWarning + else -> FirefoxTheme.colors.iconSecondary + } +} + +@LightDarkPreview +@Composable +private fun MenuItemPreview() { + FirefoxTheme { + Column( + modifier = Modifier + .background(color = FirefoxTheme.colors.layer3) + .padding(16.dp), + ) { + MenuGroup { + for (state in MenuItemState.entries) { + MenuItem( + label = stringResource(id = R.string.browser_menu_translations), + beforeIconPainter = painterResource(id = R.drawable.mozac_ic_translate_24), + state = state, + onClick = {}, + ) + + Divider(color = FirefoxTheme.colors.borderSecondary) + } + + for (state in MenuItemState.entries) { + MenuItem( + label = stringResource(id = R.string.browser_menu_extensions), + beforeIconPainter = painterResource(id = R.drawable.mozac_ic_extension_24), + state = state, + onClick = {}, + afterIconPainter = painterResource(id = R.drawable.mozac_ic_chevron_right_24), + ) + + Divider(color = FirefoxTheme.colors.borderSecondary) + } + + for (state in MenuItemState.entries) { + MenuItem( + label = stringResource(id = R.string.library_bookmarks), + beforeIconPainter = painterResource(id = R.drawable.mozac_ic_bookmark_tray_fill_24), + state = state, + onClick = {}, + afterButtonText = stringResource(id = R.string.browser_menu_edit), + onAfterButtonClick = {}, + ) + + Divider(color = FirefoxTheme.colors.borderSecondary) + } + } + } + } +}