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
This commit is contained in:
Gabriel Luong 2024-04-19 04:40:30 +00:00
parent 1be42fab76
commit 3ba1aab119
2 changed files with 165 additions and 11 deletions

View file

@ -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,
)
}
}

View file

@ -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)
}
}
}
}
}