Skip to content

Instantly share code, notes, and snippets.

@fvilarino
Created November 7, 2022 06:47
Show Gist options
  • Save fvilarino/82b03461a158a9b0e17565eac0105048 to your computer and use it in GitHub Desktop.
Save fvilarino/82b03461a158a9b0e17565eac0105048 to your computer and use it in GitHub Desktop.
App Bar Final
sealed interface ActionMenuItem {
val title: String
val onClick: () -> Unit
sealed interface IconMenuItem : ActionMenuItem {
val icon: ImageVector
val contentDescription: String?
data class AlwaysShown(
override val title: String,
override val contentDescription: String?,
override val onClick: () -> Unit,
override val icon: ImageVector,
) : IconMenuItem
data class ShownIfRoom(
override val title: String,
override val contentDescription: String?,
override val onClick: () -> Unit,
override val icon: ImageVector,
) : IconMenuItem
}
data class NeverShown(
override val title: String,
override val onClick: () -> Unit,
) : ActionMenuItem
}
@Composable
fun ActionsMenu(
items: List<ActionMenuItem>,
isOpen: Boolean,
onToggleOverflow: () -> Unit,
maxVisibleItems: Int,
) {
val menuItems = remember(
key1 = items,
key2 = maxVisibleItems,
) {
splitMenuItems(items, maxVisibleItems)
}
menuItems.alwaysShownItems.forEach { item ->
IconButton(onClick = item.onClick) {
Icon(
imageVector = item.icon,
contentDescription = item.contentDescription,
)
}
}
if (menuItems.overflowItems.isNotEmpty()) {
IconButton(onClick = onToggleOverflow) {
Icon(
imageVector = Icons.Filled.MoreVert,
contentDescription = "Overflow",
)
}
DropdownMenu(
expanded = isOpen,
onDismissRequest = onToggleOverflow,
) {
menuItems.overflowItems.forEach { item ->
DropdownMenuItem(
text = {
Text(item.title)
},
onClick = item.onClick
)
}
}
}
}
private data class MenuItems(
val alwaysShownItems: List<ActionMenuItem.IconMenuItem>,
val overflowItems: List<ActionMenuItem>,
)
private fun splitMenuItems(
items: List<ActionMenuItem>,
maxVisibleItems: Int,
): MenuItems {
val alwaysShownItems: MutableList<ActionMenuItem.IconMenuItem> =
items.filterIsInstance<ActionMenuItem.IconMenuItem.AlwaysShown>().toMutableList()
val ifRoomItems: MutableList<ActionMenuItem.IconMenuItem> =
items.filterIsInstance<ActionMenuItem.IconMenuItem.ShownIfRoom>().toMutableList()
val overflowItems = items.filterIsInstance<ActionMenuItem.NeverShown>()
val hasOverflow = overflowItems.isNotEmpty() ||
(alwaysShownItems.size + ifRoomItems.size - 1) > maxVisibleItems
val usedSlots = alwaysShownItems.size + (if (hasOverflow) 1 else 0)
val availableSlots = maxVisibleItems - usedSlots
if (availableSlots > 0 && ifRoomItems.isNotEmpty()) {
val visible = ifRoomItems.subList(0, availableSlots.coerceAtMost(ifRoomItems.size))
alwaysShownItems.addAll(visible)
ifRoomItems.removeAll(visible)
}
return MenuItems(
alwaysShownItems = alwaysShownItems,
overflowItems = ifRoomItems + overflowItems,
)
}
@OptIn(ExperimentalMaterial3Api::class)
@Preview(widthDp = 440, showBackground = true)
@Preview(widthDp = 440, uiMode = Configuration.UI_MODE_NIGHT_YES, showBackground = true)
@Composable
private fun ActionMenuPreview(
@PreviewParameter(ActionMenuParameterProvider::class) items: List<ActionMenuItem>
) {
PlaygroundTheme {
var menuOpen by remember {
mutableStateOf(false)
}
val numAlwaysShown = items.count { item -> item is ActionMenuItem.IconMenuItem.AlwaysShown }
val numIfRoom = items.count { item -> item is ActionMenuItem.IconMenuItem.ShownIfRoom }
val numOverflow = items.count { item -> item is ActionMenuItem.NeverShown }
val label = "Always: $numAlwaysShown Room: $numIfRoom Over: $numOverflow"
TopAppBar(
title = { Text(label) },
modifier = Modifier.fillMaxWidth(),
actions = {
ActionsMenu(
items = items,
isOpen = menuOpen,
onToggleOverflow = { menuOpen = !menuOpen },
maxVisibleItems = 3
)
}
)
}
}
private class ActionMenuParameterProvider : PreviewParameterProvider<List<ActionMenuItem>> {
override val values: Sequence<List<ActionMenuItem>>
get() = sequenceOf(
listOf(
ActionMenuItem.IconMenuItem.AlwaysShown(
title = "Search",
onClick = {},
icon = Icons.Filled.Search,
contentDescription = null,
),
ActionMenuItem.IconMenuItem.AlwaysShown(
title = "Favorite",
onClick = {},
icon = Icons.Filled.FavoriteBorder,
contentDescription = null,
),
ActionMenuItem.IconMenuItem.AlwaysShown(
title = "Star",
onClick = {},
icon = Icons.Filled.Star,
contentDescription = null,
),
ActionMenuItem.IconMenuItem.ShownIfRoom(
title = "Refresh",
onClick = {},
icon = Icons.Filled.Refresh,
contentDescription = null,
),
ActionMenuItem.NeverShown(
title = "Settings",
onClick = {},
),
ActionMenuItem.NeverShown(
title = "About",
onClick = {},
),
),
listOf(
ActionMenuItem.IconMenuItem.AlwaysShown(
title = "Search",
onClick = {},
icon = Icons.Filled.Search,
contentDescription = null,
),
ActionMenuItem.IconMenuItem.AlwaysShown(
title = "Favorite",
onClick = {},
icon = Icons.Filled.FavoriteBorder,
contentDescription = null,
),
ActionMenuItem.IconMenuItem.ShownIfRoom(
title = "Star",
onClick = {},
icon = Icons.Filled.Star,
contentDescription = null,
),
ActionMenuItem.IconMenuItem.ShownIfRoom(
title = "Refresh",
onClick = {},
icon = Icons.Filled.Refresh,
contentDescription = null,
),
ActionMenuItem.NeverShown(
title = "Settings",
onClick = {},
),
ActionMenuItem.NeverShown(
title = "About",
onClick = {},
),
),
listOf(
ActionMenuItem.IconMenuItem.AlwaysShown(
title = "Search",
onClick = {},
icon = Icons.Filled.Search,
contentDescription = null,
),
ActionMenuItem.IconMenuItem.ShownIfRoom(
title = "Favorite",
onClick = {},
icon = Icons.Filled.FavoriteBorder,
contentDescription = null,
),
ActionMenuItem.IconMenuItem.ShownIfRoom(
title = "Star",
onClick = {},
icon = Icons.Filled.Star,
contentDescription = null,
),
ActionMenuItem.IconMenuItem.ShownIfRoom(
title = "Refresh",
onClick = {},
icon = Icons.Filled.Refresh,
contentDescription = null,
),
ActionMenuItem.NeverShown(
title = "Settings",
onClick = {},
),
ActionMenuItem.NeverShown(
title = "About",
onClick = {},
),
),
listOf(
ActionMenuItem.IconMenuItem.ShownIfRoom(
title = "Search",
onClick = {},
icon = Icons.Filled.Search,
contentDescription = null,
),
ActionMenuItem.IconMenuItem.ShownIfRoom(
title = "Favorite",
onClick = {},
icon = Icons.Filled.FavoriteBorder,
contentDescription = null,
),
ActionMenuItem.IconMenuItem.ShownIfRoom(
title = "Star",
onClick = {},
icon = Icons.Filled.Star,
contentDescription = null,
),
ActionMenuItem.IconMenuItem.ShownIfRoom(
title = "Refresh",
onClick = {},
icon = Icons.Filled.Refresh,
contentDescription = null,
),
ActionMenuItem.NeverShown(
title = "Settings",
onClick = {},
),
ActionMenuItem.NeverShown(
title = "About",
onClick = {},
),
),
listOf(
ActionMenuItem.IconMenuItem.ShownIfRoom(
title = "Search",
onClick = {},
icon = Icons.Filled.Search,
contentDescription = null,
),
ActionMenuItem.IconMenuItem.ShownIfRoom(
title = "Favorite",
onClick = {},
icon = Icons.Filled.FavoriteBorder,
contentDescription = null,
),
),
listOf(
ActionMenuItem.NeverShown(
title = "Search",
onClick = {},
),
ActionMenuItem.NeverShown(
title = "Favorite",
onClick = {},
),
),
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment