From 3429555c8da7cb760375fe67de6dafda8e5bb073 Mon Sep 17 00:00:00 2001 From: MM20 <15646950+MM2-0@users.noreply.github.com> Date: Sun, 30 Nov 2025 21:30:38 +0100 Subject: [PATCH] update dropdown menus --- .../de/mm20/launcher2/ui/common/IconPicker.kt | 61 ++-- .../ui/component/OutlinedTagsInputField.kt | 43 ++- .../de/mm20/launcher2/ui/component/Toolbar.kt | 35 ++- .../ui/launcher/searchbar/SearchBarMenu.kt | 153 +++++----- .../ui/launcher/sheets/EditFavoritesSheet.kt | 118 +++++--- .../widgets/calendar/CalendarWidget.kt | 56 +++- .../ui/launcher/widgets/clock/ClockWidget.kt | 109 ++++--- .../widgets/clock/WatchFaceSelector.kt | 267 +++++++++++------- .../ui/launcher/widgets/music/MusicWidget.kt | 51 ++-- .../ui/launcher/widgets/notes/NotesWidget.kt | 185 ++++++------ .../appearance/ExportThemeSettingsScreen.kt | 39 +-- .../colorscheme/ColorSchemesSettingsScreen.kt | 114 +++++--- .../hiddenitems/HiddenItemsSettingsScreen.kt | 142 +++++----- .../searchactions/EditSearchActionSheet.kt | 210 ++++++++------ .../SearchActionsSettingsScreen.kt | 88 +++--- .../shapes/ShapeSchemesSettingsScreen.kt | 111 +++++--- .../ui/settings/tags/TagsSettingsScreen.kt | 62 ++-- .../TransparencySchemesSettingsScreen.kt | 118 +++++--- .../typography/TypographiesSettingsScreen.kt | 111 +++++--- .../main/res/drawable/arrow_right_24px.xml | 11 + 20 files changed, 1267 insertions(+), 817 deletions(-) create mode 100644 core/base/src/main/res/drawable/arrow_right_24px.xml diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/common/IconPicker.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/common/IconPicker.kt index 3f192c703..584cda72d 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/common/IconPicker.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/common/IconPicker.kt @@ -16,9 +16,11 @@ import androidx.compose.foundation.lazy.grid.items import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuGroup import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.DropdownMenuPopup import androidx.compose.material3.Icon +import androidx.compose.material3.MenuDefaults import androidx.compose.material3.SearchBar import androidx.compose.material3.SearchBarDefaults import androidx.compose.material3.Text @@ -182,31 +184,54 @@ fun IconPicker( contentDescription = null ) } - DropdownMenu( + DropdownMenuPopup( + expanded = showIconPackFilter, - onDismissRequest = { showIconPackFilter = false }) { - DropdownMenuItem( - text = { Text(stringResource(id = R.string.icon_picker_filter_all_packs)) }, - onClick = { - showIconPackFilter = false - filterIconPack = null - scope.launch { - viewModel.searchIcon(query, filterIconPack) - } - } - ) - installedIconPacks?.forEach { iconPack -> + onDismissRequest = { showIconPackFilter = false } + ) { + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes() + ) { DropdownMenuItem( + selected = filterIconPack == null, + shapes = MenuDefaults.itemShape( + 0, + installedIconPacks?.size?.plus(1) ?: 1 + ), + text = { Text(stringResource(id = R.string.icon_picker_filter_all_packs)) }, onClick = { showIconPackFilter = false - filterIconPack = iconPack + filterIconPack = null scope.launch { viewModel.searchIcon(query, filterIconPack) } }, - text = { - Text(iconPack.name) - }) + checkedLeadingIcon = { + Icon(painterResource(R.drawable.check_24px), null) + } + ) + installedIconPacks?.forEachIndexed { i, iconPack -> + DropdownMenuItem( + selected = filterIconPack == iconPack, + shapes = MenuDefaults.itemShape( + i + 1, + installedIconPacks!!.size + 1 + ), + onClick = { + showIconPackFilter = false + filterIconPack = iconPack + scope.launch { + viewModel.searchIcon(query, filterIconPack) + } + }, + text = { + Text(iconPack.name) + }, + checkedLeadingIcon = { + Icon(painterResource(R.drawable.check_24px), null) + }, + ) + } } } Text( diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/component/OutlinedTagsInputField.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/component/OutlinedTagsInputField.kt index 40dc6b5e4..37111730c 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/component/OutlinedTagsInputField.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/component/OutlinedTagsInputField.kt @@ -4,6 +4,7 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth @@ -14,14 +15,16 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardActions -import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuGroup import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.DropdownMenuPopup import androidx.compose.material3.Icon import androidx.compose.material3.InputChip import androidx.compose.material3.InputChipDefaults import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.MenuDefaults import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -134,9 +137,7 @@ fun OutlinedTagsInputField( label = label, leadingIcon = leadingIcon, innerTextField = { - Box( - contentAlignment = Alignment.CenterStart, - ) { + Column { Row( modifier = Modifier .requiredHeight(32.dp) @@ -188,21 +189,33 @@ fun OutlinedTagsInputField( } } if (completions.isNotEmpty()) { - Box(modifier = Modifier.fillMaxWidth()) { - DropdownMenu( + Box { + DropdownMenuPopup( expanded = true, onDismissRequest = { completions = emptyList() }, properties = PopupProperties(focusable = false) ) { - for (completion in completions) { - DropdownMenuItem( - text = { Text(completion) }, - onClick = { - onTagsChange(tags + completion) - value = "" - completions = emptyList() - }, - ) + DropdownMenuGroup( + modifier = Modifier.fillMaxWidth(), + shapes = MenuDefaults.groupShapes() + ) { + for ((i, completion) in completions.withIndex()) { + DropdownMenuItem( + shape = + if (completions.size == 1) MenuDefaults.standaloneItemShape + else when (i) { + 0 -> MenuDefaults.leadingItemShape + completions.lastIndex -> MenuDefaults.trailingItemShape + else -> MenuDefaults.middleItemShape + }, + text = { Text(completion) }, + onClick = { + onTagsChange(tags + completion) + value = "" + completions = emptyList() + }, + ) + } } } } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/component/Toolbar.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/component/Toolbar.kt index da68111df..f310bc30c 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/component/Toolbar.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/component/Toolbar.kt @@ -9,9 +9,12 @@ import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuGroup import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.DropdownMenuPopup import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.MenuDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -61,13 +64,17 @@ fun Icons(actions: List, slots: Int) { modifier = Modifier .size(48.dp) ) { - DropdownMenu( + DropdownMenuPopup( expanded = showMenu, onDismissRequest = { showMenu = false }, modifier = Modifier.animateContentSize() ) { - OverflowMenuItems(items = actions.subList(slots - 1, actions.size)) { - showMenu = false + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes() + ) { + OverflowMenuItems(items = actions.subList(slots - 1, actions.size)) { + showMenu = false + } } } } @@ -102,13 +109,17 @@ fun Icons(actions: List, slots: Int) { .size(48.dp) .offset(0.dp, LocalWindowPosition.current.toDp()) ) { - DropdownMenu( + DropdownMenuPopup( expanded = showMenu, onDismissRequest = { showMenu = false }, modifier = Modifier.animateContentSize() ) { - OverflowMenuItems(items = action.children) { - showMenu = false + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes() + ) { + OverflowMenuItems(items = action.children) { + showMenu = false + } } } } @@ -138,7 +149,12 @@ fun ColumnScope.OverflowMenuItems(items: List, onDismiss: () -> U Icon(painterResource(action.icon), null) }, trailingIcon = { - Icon(painterResource(R.drawable.chevron_forward_24px), null) + Icon(painterResource(R.drawable.arrow_right_24px), null) + }, + shape = when { + i == 0 -> MenuDefaults.leadingItemShape + i == items.lastIndex -> MenuDefaults.trailingItemShape + else -> MenuDefaults.middleItemShape } ) } @@ -156,6 +172,11 @@ fun ColumnScope.OverflowMenuItems(items: List, onDismiss: () -> U }, leadingIcon = { Icon(painterResource(action.icon), null) + }, + shape = when { + i == 0 -> MenuDefaults.leadingItemShape + i == items.lastIndex -> MenuDefaults.trailingItemShape + else -> MenuDefaults.middleItemShape } ) } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/searchbar/SearchBarMenu.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/searchbar/SearchBarMenu.kt index a81fac72a..d726d8fad 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/searchbar/SearchBarMenu.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/searchbar/SearchBarMenu.kt @@ -7,27 +7,30 @@ import androidx.browser.customtabs.CustomTabsIntent import androidx.compose.animation.graphics.res.animatedVectorResource import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter import androidx.compose.animation.graphics.vector.AnimatedImageVector +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.RowScope -import androidx.compose.material3.DropdownMenu +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.material3.DropdownMenuGroup import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.DropdownMenuPopup import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.LocalContentColor import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.MenuDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource -import androidx.lifecycle.viewmodel.compose.viewModel import de.mm20.launcher2.ui.R -import de.mm20.launcher2.ui.launcher.LauncherScaffoldVM -import de.mm20.launcher2.ui.launcher.widgets.WidgetsVM import de.mm20.launcher2.ui.settings.SettingsActivity @Composable @@ -38,72 +41,88 @@ fun RowScope.SearchBarMenu( val context = LocalContext.current var showOverflowMenu by remember { mutableStateOf(false) } val rightIcon = AnimatedImageVector.animatedVectorResource(R.drawable.anim_ic_menu_clear) - val launcherVM: LauncherScaffoldVM = viewModel() - val widgetsVM: WidgetsVM = viewModel() - IconButton(onClick = { - if (searchBarValue.isNotBlank()) onInputClear() - else showOverflowMenu = true - }) { - Icon( - painter = rememberAnimatedVectorPainter( - rightIcon, - atEnd = searchBarValue.isNotEmpty() - ), - contentDescription = stringResource(if (searchBarValue.isNotBlank()) R.string.action_clear else R.string.action_more_actions), - tint = LocalContentColor.current - ) - } - DropdownMenu(expanded = showOverflowMenu, onDismissRequest = { showOverflowMenu = false }) { - DropdownMenuItem( - onClick = { - context.startActivity( - Intent.createChooser( - Intent(Intent.ACTION_SET_WALLPAPER), - null - ) + Box(contentAlignment = Alignment.TopEnd) { + IconButton(onClick = { + if (searchBarValue.isNotBlank()) onInputClear() + else showOverflowMenu = true + }) { + Icon( + painter = rememberAnimatedVectorPainter( + rightIcon, + atEnd = searchBarValue.isNotEmpty() + ), + contentDescription = stringResource(if (searchBarValue.isNotBlank()) R.string.action_clear else R.string.action_more_actions), + tint = LocalContentColor.current + ) + } + DropdownMenuPopup( + expanded = showOverflowMenu, + onDismissRequest = { showOverflowMenu = false }, + ) { + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes(), + modifier = Modifier + .fillMaxWidth() + .align(Alignment.Start) + ) { + DropdownMenuItem( + shape = MenuDefaults.leadingItemShape, + onClick = { + context.startActivity( + Intent.createChooser( + Intent(Intent.ACTION_SET_WALLPAPER), + null + ) + ) + showOverflowMenu = false + }, + text = { + Text(stringResource(R.string.wallpaper)) + }, + leadingIcon = { + Icon(painterResource(R.drawable.wallpaper_24px), contentDescription = null) + } ) - showOverflowMenu = false - }, - text = { - Text(stringResource(R.string.wallpaper)) - }, - leadingIcon = { - Icon(painterResource(R.drawable.wallpaper_24px), contentDescription = null) - } - ) - DropdownMenuItem( - onClick = { - context.startActivity(Intent(context, SettingsActivity::class.java)) - showOverflowMenu = false - }, - text = { - Text(stringResource(R.string.settings)) - }, - leadingIcon = { - Icon(painterResource(R.drawable.settings_24px), contentDescription = null) - } - ) - val colorScheme = MaterialTheme.colorScheme - DropdownMenuItem( - onClick = { - CustomTabsIntent.Builder() - .setDefaultColorSchemeParams( - CustomTabColorSchemeParams.Builder() - .setToolbarColor(colorScheme.primaryContainer.toArgb()) - .setSecondaryToolbarColor(colorScheme.secondaryContainer.toArgb()) + DropdownMenuItem( + shape = MenuDefaults.middleItemShape, + onClick = { + context.startActivity(Intent(context, SettingsActivity::class.java)) + showOverflowMenu = false + }, + text = { + Text(stringResource(R.string.settings)) + }, + leadingIcon = { + Icon(painterResource(R.drawable.settings_24px), contentDescription = null) + } + ) + val colorScheme = MaterialTheme.colorScheme + DropdownMenuItem( + shape = MenuDefaults.trailingItemShape, + onClick = { + CustomTabsIntent.Builder() + .setDefaultColorSchemeParams( + CustomTabColorSchemeParams.Builder() + .setToolbarColor(colorScheme.primaryContainer.toArgb()) + .setSecondaryToolbarColor(colorScheme.secondaryContainer.toArgb()) + .build() + ) .build() - ) - .build() - .launchUrl(context, Uri.parse("https://kvaesitso.mm20.de/docs/user-guide")) - showOverflowMenu = false - }, - text = { - Text(stringResource(R.string.help)) - }, - leadingIcon = { - Icon(painterResource(R.drawable.help_24px), contentDescription = null) + .launchUrl( + context, + Uri.parse("https://kvaesitso.mm20.de/docs/user-guide") + ) + showOverflowMenu = false + }, + text = { + Text(stringResource(R.string.help)) + }, + leadingIcon = { + Icon(painterResource(R.drawable.help_24px), contentDescription = null) + } + ) } - ) + } } } \ No newline at end of file diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/EditFavoritesSheet.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/EditFavoritesSheet.kt index e608e94b6..3859103c1 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/EditFavoritesSheet.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/EditFavoritesSheet.kt @@ -26,14 +26,14 @@ import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuGroup import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.DropdownMenuPopup import androidx.compose.material3.FilledTonalIconButton import androidx.compose.material3.FilledTonalIconToggleButton -import androidx.compose.material3.FilterChipDefaults -import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.MenuDefaults import androidx.compose.material3.OutlinedCard import androidx.compose.material3.Slider import androidx.compose.material3.SliderDefaults @@ -117,7 +117,7 @@ fun EditFavoritesSheet( } else { ReorderFavoritesGrid(viewModel, it) if (createShortcutTarget != null) { - BottomSheetDialog({viewModel.cancelPickShortcut()}) { + BottomSheetDialog({ viewModel.cancelPickShortcut() }) { ShortcutPicker(viewModel, it) } } @@ -243,23 +243,28 @@ fun ReorderFavoritesGrid(viewModel: EditFavoritesSheetVM, paddingValues: Padding badge = badge ) if (contextMenuItemKey == it.item.key) { - DropdownMenu( + DropdownMenuPopup( expanded = true, onDismissRequest = { contextMenuItemKey = null }) { - DropdownMenuItem( - leadingIcon = { - Icon( - painterResource(R.drawable.delete_24px), - contentDescription = null - ) - }, - text = { - Text(stringResource(R.string.menu_remove)) - }, onClick = { - contextMenuItemKey?.let { viewModel.remove(it) } - contextMenuItemKey = null - } - ) + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes() + ) { + DropdownMenuItem( + shape = MenuDefaults.standaloneItemShape, + leadingIcon = { + Icon( + painterResource(R.drawable.delete_24px), + contentDescription = null + ) + }, + text = { + Text(stringResource(R.string.menu_remove)) + }, onClick = { + contextMenuItemKey?.let { viewModel.remove(it) } + contextMenuItemKey = null + } + ) + } } } } @@ -474,37 +479,60 @@ fun ReorderFavoritesGrid(viewModel: EditFavoritesSheetVM, paddingValues: Padding contentDescription = null ) } - DropdownMenu( + DropdownMenuPopup( expanded = showAddMenu, onDismissRequest = { showAddMenu = false }) { - for (tag in availableTags) { - DropdownMenuItem( - leadingIcon = { - Icon(painterResource(R.drawable.tag_24px), null) - }, - text = { Text(tag.tag) }, - onClick = { - viewModel.pinTag(tag) - showAddMenu = false - }) - } if (availableTags.isNotEmpty()) { - HorizontalDivider() - } - DropdownMenuItem( - leadingIcon = { - Icon(painterResource(R.drawable.add_24px), null) - }, - text = { - Text( - stringResource(R.string.edit_favorites_dialog_new_tag), - ) - }, - onClick = { - createTag = true - showAddMenu = false + DropdownMenuGroup( + shapes = MenuDefaults.groupShape(0, 2), + ) { + for ((i, tag) in availableTags.withIndex()) { + DropdownMenuItem( + shape = if (availableTags.size == 1) MenuDefaults.standaloneItemShape + else when (i) { + 0 -> MenuDefaults.leadingItemShape + availableTags.lastIndex -> MenuDefaults.trailingItemShape + else -> MenuDefaults.middleItemShape + }, + leadingIcon = { + Icon( + painterResource(R.drawable.tag_24px), + null + ) + }, + text = { Text(tag.tag) }, + onClick = { + viewModel.pinTag(tag) + showAddMenu = false + }) + } } + } + Spacer( + modifier = Modifier.height(MenuDefaults.GroupSpacing) ) + DropdownMenuGroup( + shapes = MenuDefaults.groupShape( + if (availableTags.isEmpty()) 0 else 1, + if (availableTags.isEmpty()) 1 else 2, + ) + ) { + DropdownMenuItem( + shape = MenuDefaults.standaloneItemShape, + leadingIcon = { + Icon(painterResource(R.drawable.add_24px), null) + }, + text = { + Text( + stringResource(R.string.edit_favorites_dialog_new_tag), + ) + }, + onClick = { + createTag = true + showAddMenu = false + } + ) + } } } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/calendar/CalendarWidget.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/calendar/CalendarWidget.kt index 7285c5b14..e4c135a42 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/calendar/CalendarWidget.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/calendar/CalendarWidget.kt @@ -16,11 +16,13 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuGroup import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.DropdownMenuPopup import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.MenuDefaults import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable @@ -44,10 +46,8 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.viewmodel.compose.viewModel -import de.mm20.launcher2.Quadruple import de.mm20.launcher2.Quintuple import de.mm20.launcher2.ui.R -import de.mm20.launcher2.ui.component.InnerCard import de.mm20.launcher2.ui.component.MissingPermissionBanner import de.mm20.launcher2.ui.launcher.search.common.list.SearchResultList import de.mm20.launcher2.widgets.CalendarWidget @@ -80,7 +80,10 @@ fun CalendarWidget( modifier = Modifier.padding(start = 8.dp, end = 8.dp, top = 8.dp, bottom = 4.dp) ) { IconButton(onClick = { viewModel.previousDay() }) { - Icon(painter = painterResource(R.drawable.chevron_backward_24px), contentDescription = stringResource(R.string.calendar_widget_previous_day)) + Icon( + painter = painterResource(R.drawable.chevron_backward_24px), + contentDescription = stringResource(R.string.calendar_widget_previous_day) + ) } Box( modifier = Modifier.weight(1f), @@ -101,26 +104,49 @@ fun CalendarWidget( tint = MaterialTheme.colorScheme.onSurface, ) } - DropdownMenu(expanded = showDropdown, onDismissRequest = { showDropdown = false }) { + DropdownMenuPopup( + expanded = showDropdown, + onDismissRequest = { showDropdown = false }) { val availableDates = viewModel.availableDates - for (date in availableDates) { - DropdownMenuItem(text = { - Text(formatDay(context, date)) - }, onClick = { - viewModel.selectDate(date) - showDropdown = false - }) + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes() + ) { + for ((i, date) in availableDates.withIndex()) { + DropdownMenuItem( + shape = if (availableDates.size == 1) MenuDefaults.standaloneItemShape + else when (i) { + 0 -> MenuDefaults.leadingItemShape + availableDates.lastIndex -> MenuDefaults.trailingItemShape + else -> MenuDefaults.middleItemShape + }, + text = { + Text(formatDay(context, date)) + }, + onClick = { + viewModel.selectDate(date) + showDropdown = false + }) + } } } } IconButton(onClick = { viewModel.nextDay() }) { - Icon(painter = painterResource(R.drawable.chevron_forward_24px), contentDescription = stringResource(R.string.calendar_widget_next_day)) + Icon( + painter = painterResource(R.drawable.chevron_forward_24px), + contentDescription = stringResource(R.string.calendar_widget_next_day) + ) } IconButton(onClick = { viewModel.createEvent(context) }) { - Icon(painter = painterResource(R.drawable.add_24px), contentDescription = stringResource(R.string.calendar_widget_create_event)) + Icon( + painter = painterResource(R.drawable.add_24px), + contentDescription = stringResource(R.string.calendar_widget_create_event) + ) } IconButton(onClick = { viewModel.openCalendarApp(context) }) { - Icon(painter = painterResource(R.drawable.open_in_new_24px), contentDescription = stringResource(R.string.calendar_widget_open_calendar)) + Icon( + painter = painterResource(R.drawable.open_in_new_24px), + contentDescription = stringResource(R.string.calendar_widget_open_calendar) + ) } } val events by viewModel.calendarEvents diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidget.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidget.kt index edea5c7f6..5eff44648 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidget.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidget.kt @@ -16,13 +16,15 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuGroup import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.DropdownMenuPopup import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.LocalContentColor import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.MenuDefaults import androidx.compose.material3.OutlinedCard import androidx.compose.material3.SegmentedButton import androidx.compose.material3.SegmentedButtonDefaults @@ -50,7 +52,6 @@ import androidx.lifecycle.viewmodel.compose.viewModel import de.mm20.launcher2.preferences.ClockWidgetAlignment import de.mm20.launcher2.preferences.ClockWidgetColors import de.mm20.launcher2.preferences.ClockWidgetStyle -import de.mm20.launcher2.preferences.TimeFormat import de.mm20.launcher2.preferences.ui.ClockWidgetSettings import de.mm20.launcher2.ui.R import de.mm20.launcher2.ui.base.LocalTime @@ -548,46 +549,74 @@ fun ConfigureClockWidgetSheet( }, enabled = fillHeight == true, ) - DropdownMenu( + DropdownMenuPopup( expanded = showDropdown, onDismissRequest = { showDropdown = false }) { - DropdownMenuItem( - leadingIcon = { - Icon( - painterResource(R.drawable.align_vertical_top_24px), - null - ) - }, - text = { Text(stringResource(R.string.preference_clock_widget_alignment_top)) }, - onClick = { - viewModel.setAlignment(ClockWidgetAlignment.Top) - showDropdown = false - } - ) - DropdownMenuItem( - leadingIcon = { - Icon( - painterResource(R.drawable.align_vertical_center_24px), - null - ) - }, - text = { Text(stringResource(R.string.preference_clock_widget_alignment_center)) }, - onClick = { - viewModel.setAlignment(ClockWidgetAlignment.Center) - showDropdown = false - }) - DropdownMenuItem( - leadingIcon = { - Icon( - painterResource(R.drawable.align_vertical_bottom_24px), - null - ) - }, - text = { Text(stringResource(R.string.preference_clock_widget_alignment_bottom)) }, - onClick = { - viewModel.setAlignment(ClockWidgetAlignment.Bottom) - showDropdown = false - }) + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes() + ) { + DropdownMenuItem( + shapes = MenuDefaults.itemShape(0, 3), + selected = alignment == ClockWidgetAlignment.Top, + checkedLeadingIcon = { + Icon( + painterResource(R.drawable.check_24px), + null + ) + }, + leadingIcon = { + Icon( + painterResource(R.drawable.align_vertical_top_24px), + null + ) + }, + text = { Text(stringResource(R.string.preference_clock_widget_alignment_top)) }, + onClick = { + viewModel.setAlignment(ClockWidgetAlignment.Top) + showDropdown = false + } + ) + DropdownMenuItem( + shapes = MenuDefaults.itemShape(1, 3), + selected = alignment == ClockWidgetAlignment.Center, + checkedLeadingIcon = { + Icon( + painterResource(R.drawable.check_24px), + null + ) + }, + leadingIcon = { + Icon( + painterResource(R.drawable.align_vertical_center_24px), + null + ) + }, + text = { Text(stringResource(R.string.preference_clock_widget_alignment_center)) }, + onClick = { + viewModel.setAlignment(ClockWidgetAlignment.Center) + showDropdown = false + }) + DropdownMenuItem( + shapes = MenuDefaults.itemShape(2, 3), + selected = alignment == ClockWidgetAlignment.Bottom, + checkedLeadingIcon = { + Icon( + painterResource(R.drawable.check_24px), + null + ) + }, + leadingIcon = { + Icon( + painterResource(R.drawable.align_vertical_bottom_24px), + null + ) + }, + text = { Text(stringResource(R.string.preference_clock_widget_alignment_bottom)) }, + onClick = { + viewModel.setAlignment(ClockWidgetAlignment.Bottom) + showDropdown = false + }) + } } } } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/WatchFaceSelector.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/WatchFaceSelector.kt index 8ddf7e7b8..f9d41728c 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/WatchFaceSelector.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/WatchFaceSelector.kt @@ -28,12 +28,15 @@ import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuGroup import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.DropdownMenuPopup import androidx.compose.material3.FilledIconButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.LocalContentColor import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.MenuDefaults import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextButton @@ -151,108 +154,153 @@ fun WatchFaceSelector( .padding(4.dp) ) { Icon(painterResource(R.drawable.tune_24px), null) - DropdownMenu( + DropdownMenuPopup( expanded = showStyleSettings, onDismissRequest = { showStyleSettings = false }) { if (selected is ClockWidgetStyle.Digital1) { - DropdownMenuItem( - text = { Text(stringResource(R.string.clock_variant_outlined)) }, - leadingIcon = { - Icon( - painterResource( - if (selected.outlined) R.drawable.check_circle_24px_filled - else R.drawable.circle_24px, - ), - null - ) - }, - onClick = { - onSelect(selected.copy(outlined = !selected.outlined)) - } - ) + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes() + ) { + DropdownMenuItem( + checked = selected.outlined, + onCheckedChange = { + onSelect(selected.copy(outlined = it)) + }, + shapes = MenuDefaults.itemShapes(), + text = { Text(stringResource(R.string.clock_variant_outlined)) }, + leadingIcon = { + Icon( + painterResource(R.drawable.circle_24px), + null + ) + }, + checkedLeadingIcon = { + Icon( + painterResource(R.drawable.check_circle_24px_filled), + null + ) + }, + ) + } } if (selected is ClockWidgetStyle.Analog) { - DropdownMenuItem( - text = { Text(stringResource(R.string.clock_variant_analog_ticks)) }, - leadingIcon = { - Icon( - painterResource( - if (selected.showTicks) R.drawable.check_circle_24px_filled - else R.drawable.circle_24px, - ), - null - ) - }, - onClick = { - onSelect(selected.copy(showTicks = !selected.showTicks)) - } - ) + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes() + ) { + DropdownMenuItem( + text = { Text(stringResource(R.string.clock_variant_analog_ticks)) }, + leadingIcon = { + Icon( + painterResource(R.drawable.circle_24px), + null + ) + }, + checkedLeadingIcon = { + Icon( + painterResource(R.drawable.check_circle_24px_filled), + null + ) + }, + shapes = MenuDefaults.itemShapes(), + checked = selected.showTicks, + onCheckedChange = { + onSelect(selected.copy(showTicks = it)) + } + ) + } } if (selected is ClockWidgetStyle.Custom) { - DropdownMenuItem( - text = { Text(stringResource(R.string.widget_pick_widget)) }, - leadingIcon = { - Icon(painterResource(R.drawable.swap_horiz_24px), null) - }, - onClick = { - showWidgetPicker = true - showStyleSettings = false + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes() + ) { + val widget = remember(selected.widgetId) { + val id = selected.widgetId ?: return@remember null + AppWidgetManager.getInstance(context) + .getAppWidgetInfo(id) } - ) - DropdownMenuItem( - leadingIcon = { - Icon(painterResource(R.drawable.resize_24px), null) - }, - text = { Text(stringResource(R.string.widget_config_appwidget_resize)) }, - onClick = { resizeCustomWidget = true } - ) - val widget = remember(selected.widgetId) { - val id = selected.widgetId ?: return@remember null - AppWidgetManager.getInstance(context) - .getAppWidgetInfo(id) - } - val appWidgetHost = LocalAppWidgetHost.current - if (widget?.configure != null) { DropdownMenuItem( - text = { Text(stringResource(R.string.widget_config_appwidget_configure)) }, + text = { Text(stringResource(R.string.widget_pick_widget)) }, leadingIcon = { - Icon(painterResource(R.drawable.settings_24px), null) + Icon( + painterResource(R.drawable.swap_horiz_24px), + null + ) }, onClick = { - appWidgetHost.startAppWidgetConfigureActivityForResult( - getActivityFromContext(context) ?: return@DropdownMenuItem, - selected.widgetId ?: return@DropdownMenuItem, - 0, - 0, - if (Build.VERSION.SDK_INT < 34) { + showWidgetPicker = true + showStyleSettings = false + }, + shape = MenuDefaults.leadingItemShape, + ) + DropdownMenuItem( + leadingIcon = { + Icon(painterResource(R.drawable.resize_24px), null) + }, + text = { Text(stringResource(R.string.widget_config_appwidget_resize)) }, + onClick = { resizeCustomWidget = true }, + shape = if (widget?.configure == null && !BuildConfig.DEBUG) { + MenuDefaults.trailingItemShape + } else { + MenuDefaults.middleItemShape + }, + ) + val appWidgetHost = LocalAppWidgetHost.current + if (widget?.configure != null) { + DropdownMenuItem( + text = { Text(stringResource(R.string.widget_config_appwidget_configure)) }, + leadingIcon = { + Icon( + painterResource(R.drawable.settings_24px), null - } else { - ActivityOptions.makeBasic() - .setPendingIntentBackgroundActivityStartMode( - ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED - ) - .toBundle() + ) + }, + onClick = { + appWidgetHost.startAppWidgetConfigureActivityForResult( + getActivityFromContext(context) + ?: return@DropdownMenuItem, + selected.widgetId + ?: return@DropdownMenuItem, + 0, + 0, + if (Build.VERSION.SDK_INT < 34) { + null + } else { + ActivityOptions.makeBasic() + .setPendingIntentBackgroundActivityStartMode( + ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED + ) + .toBundle() + } + ) + }, + shape = if (!BuildConfig.DEBUG) { + MenuDefaults.trailingItemShape + } else { + MenuDefaults.middleItemShape + }, + ) + } + if (BuildConfig.DEBUG) { + DropdownMenuItem( + shape = MenuDefaults.trailingItemShape, + leadingIcon = { + Icon( + painterResource(R.drawable.restart_alt_24px), + null + ) + }, + text = { Text("Reset") }, + onClick = { + val widgetId = selected.widgetId + if (widgetId != null) { + appWidgetHost.deleteAppWidgetId(widgetId) } - ) - } - ) - } - if (BuildConfig.DEBUG) { - DropdownMenuItem( - leadingIcon = { - Icon(painterResource(R.drawable.restart_alt_24px), null) - }, - text = { Text("Reset") }, - onClick = { - val widgetId = selected.widgetId - if (widgetId != null) { - appWidgetHost.deleteAppWidgetId(widgetId) - } - onSelect( - ClockWidgetStyle.Custom() - ) - } - ) + onSelect( + ClockWidgetStyle.Custom() + ) + }, + ) + } } } } @@ -376,27 +424,38 @@ fun WatchFaceSelector( .padding(ButtonDefaults.IconSpacing) .size(ButtonDefaults.IconSize) ) - DropdownMenu( + DropdownMenuPopup( expanded = showStyleDropdown, onDismissRequest = { showStyleDropdown = false } ) { - for (style in styles.withIndex()) { - DropdownMenuItem( - onClick = { - scope.launch { - pagerState.animateScrollToPage( - style.index, + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes() + ) { + for (style in styles.withIndex()) { + DropdownMenuItem( + shapes = MenuDefaults.itemShape(style.index, styles.size), + selected = style.index == pagerState.currentPage, + onClick = { + scope.launch { + pagerState.animateScrollToPage( + style.index, + ) + } + showStyleDropdown = false + }, + text = { + Text( + text = getClockStyleName(context, style.value), + ) + }, + checkedLeadingIcon = { + Icon( + painterResource(R.drawable.check_24px), + null, ) } - showStyleDropdown = false - }, - text = { - Text( - text = getClockStyleName(context, style.value), - ) - } - ) - } + ) + }} } } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/music/MusicWidget.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/music/MusicWidget.kt index bcb7433be..0440970ee 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/music/MusicWidget.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/music/MusicWidget.kt @@ -31,14 +31,16 @@ import androidx.compose.foundation.layout.requiredHeightIn import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuGroup import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.DropdownMenuPopup import androidx.compose.material3.FilledTonalIconButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.MenuDefaults import androidx.compose.material3.Slider import androidx.compose.material3.SliderDefaults import androidx.compose.material3.Text @@ -433,27 +435,38 @@ fun CustomActions( ) } } - DropdownMenu( + DropdownMenuPopup( expanded = showOverflowMenu, onDismissRequest = { showOverflowMenu = false }, ) { - for (i in slots - 1 until actions.customActions.size) { - val action = actions.customActions[i] - DropdownMenuItem( - leadingIcon = { - CustomActionIcon(action, playerPackage) - }, - text = { - Text( - text = action.name.toString(), - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) - }, - onClick = { - onActionSelected(action) - } - ) + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes(), + ) { + for (i in slots - 1 until actions.customActions.size) { + val action = actions.customActions[i] + DropdownMenuItem( + shape = + if (actions.customActions.size == 1) MenuDefaults.standaloneItemShape + else when (i) { + 0 -> MenuDefaults.leadingItemShape + actions.customActions.lastIndex -> MenuDefaults.trailingItemShape + else -> MenuDefaults.middleItemShape + }, + leadingIcon = { + CustomActionIcon(action, playerPackage) + }, + text = { + Text( + text = action.name.toString(), + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + }, + onClick = { + onActionSelected(action) + } + ) + } } } } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/notes/NotesWidget.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/notes/NotesWidget.kt index 2d5a942bb..1a26120aa 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/notes/NotesWidget.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/notes/NotesWidget.kt @@ -23,11 +23,13 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuGroup import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.DropdownMenuPopup import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.MenuDefaults import androidx.compose.material3.OutlinedButton import androidx.compose.material3.SnackbarDuration import androidx.compose.material3.SnackbarResult @@ -255,103 +257,118 @@ fun NotesWidget( tooltipText = stringResource(R.string.action_more_actions) ) { IconButton(onClick = { showMenu = true }) { - Icon(painterResource(R.drawable.more_vert_24px), stringResource(R.string.action_more_actions)) + Icon( + painterResource(R.drawable.more_vert_24px), + stringResource(R.string.action_more_actions) + ) } } - DropdownMenu(expanded = showMenu, onDismissRequest = { showMenu = false }) { - DropdownMenuItem( - text = { Text(stringResource(R.string.notes_widget_action_new)) }, - leadingIcon = { - Icon(painterResource(R.drawable.add_24px), null) - }, - onClick = { - val newWidget = NotesWidget( - id = UUID.randomUUID(), - ) - onWidgetAdd(newWidget, 1) - showMenu = false - }, - ) - DropdownMenuItem( - text = { Text(stringResource(R.string.menu_share)) }, - leadingIcon = { - Icon(painterResource(R.drawable.share_24px), null) - }, - onClick = { - Intent(Intent.ACTION_SEND).apply { - type = "text/plain" - putExtra(Intent.EXTRA_TEXT, text.text) - context.startActivity(Intent.createChooser(this, null)) - } - showMenu = false - }, - ) - DropdownMenuItem( - text = { Text(stringResource(R.string.notes_widget_action_save)) }, - leadingIcon = { - Icon(painterResource(R.drawable.file_save_24px), null) - }, - onClick = { - val fileName = getDefaultNoteFileName(context) - exportLauncher.launch(fileName) - showMenu = false - }, - ) - if (widget.config.linkedFile == null) { + DropdownMenuPopup( + expanded = showMenu, + onDismissRequest = { showMenu = false }) { + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes(), + ) { DropdownMenuItem( - text = { Text(stringResource(R.string.note_widget_link_file)) }, + shape = MenuDefaults.leadingItemShape, + text = { Text(stringResource(R.string.notes_widget_action_new)) }, leadingIcon = { - Icon(painterResource(R.drawable.link_24px), null) + Icon(painterResource(R.drawable.add_24px), null) }, onClick = { - linkFileLauncher.launch(getDefaultNoteFileName(context)) + val newWidget = NotesWidget( + id = UUID.randomUUID(), + ) + onWidgetAdd(newWidget, 1) showMenu = false }, ) - } else { DropdownMenuItem( - text = { Text(stringResource(R.string.note_widget_action_unlink_file)) }, + shape = MenuDefaults.middleItemShape, + text = { Text(stringResource(R.string.menu_share)) }, leadingIcon = { - Icon(painterResource(R.drawable.link_off_24px), null) + Icon(painterResource(R.drawable.share_24px), null) }, onClick = { - viewModel.unlinkFile(context) + Intent(Intent.ACTION_SEND).apply { + type = "text/plain" + putExtra(Intent.EXTRA_TEXT, text.text) + context.startActivity(Intent.createChooser(this, null)) + } + showMenu = false + }, + ) + DropdownMenuItem( + shape = MenuDefaults.middleItemShape, + text = { Text(stringResource(R.string.notes_widget_action_save)) }, + leadingIcon = { + Icon(painterResource(R.drawable.file_save_24px), null) + }, + onClick = { + val fileName = getDefaultNoteFileName(context) + exportLauncher.launch(fileName) + showMenu = false + }, + ) + if (widget.config.linkedFile == null) { + DropdownMenuItem( + shape = MenuDefaults.middleItemShape, + text = { Text(stringResource(R.string.note_widget_link_file)) }, + leadingIcon = { + Icon(painterResource(R.drawable.link_24px), null) + }, + onClick = { + linkFileLauncher.launch(getDefaultNoteFileName(context)) + showMenu = false + }, + ) + } else { + DropdownMenuItem( + shape = MenuDefaults.middleItemShape, + text = { Text(stringResource(R.string.note_widget_action_unlink_file)) }, + leadingIcon = { + Icon(painterResource(R.drawable.link_off_24px), null) + }, + onClick = { + viewModel.unlinkFile(context) + showMenu = false + }, + ) + } + DropdownMenuItem( + shape = MenuDefaults.trailingItemShape, + text = { Text(stringResource(R.string.notes_widget_action_dismiss)) }, + leadingIcon = { + Icon(painterResource(R.drawable.delete_24px), null) + }, + onClick = { + val wasLast = isLastWidget != false + + if (wasLast) { + viewModel.updateWidgetContent(NotesWidgetConfig()) + } else { + viewModel.dismissWidget(widget) + } + + lifecycleOwner.lifecycleScope.launch { + val result = snackbarHostState.showSnackbar( + message = context.getString(R.string.notes_widget_dismissed), + actionLabel = context.getString(R.string.action_undo), + duration = SnackbarDuration.Short, + ) + if (result == SnackbarResult.ActionPerformed) { + if (wasLast) { + viewModel.updateWidgetContent(widget.config) + } else { + onWidgetAdd(widget, 0) + } + } + } + showMenu = false }, ) } - DropdownMenuItem( - text = { Text(stringResource(R.string.notes_widget_action_dismiss)) }, - leadingIcon = { - Icon(painterResource(R.drawable.delete_24px), null) - }, - onClick = { - val wasLast = isLastWidget != false - - if (wasLast) { - viewModel.updateWidgetContent(NotesWidgetConfig()) - } else { - viewModel.dismissWidget(widget) - } - - lifecycleOwner.lifecycleScope.launch { - val result = snackbarHostState.showSnackbar( - message = context.getString(R.string.notes_widget_dismissed), - actionLabel = context.getString(R.string.action_undo), - duration = SnackbarDuration.Short, - ) - if (result == SnackbarResult.ActionPerformed) { - if (wasLast) { - viewModel.updateWidgetContent(widget.config) - } else { - onWidgetAdd(widget, 0) - } - } - } - - showMenu = false - }, - ) } } } @@ -424,10 +441,10 @@ fun NoteWidgetConflictResolveSheet( selected = selectedStrategy == LinkedFileConflictStrategy.KeepFile, onSelect = { selectedStrategy = LinkedFileConflictStrategy.KeepFile }, ) - Column ( + Column( modifier = Modifier.padding(top = 8.dp), - ){ - OutlinedButton ( + ) { + OutlinedButton( onClick = { onResolve(LinkedFileConflictStrategy.Unlink) }, modifier = Modifier.fillMaxWidth(), colors = ButtonDefaults.outlinedButtonColors( diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/ExportThemeSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/ExportThemeSettingsScreen.kt index 3f0c7fd56..782858fe1 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/ExportThemeSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/ExportThemeSettingsScreen.kt @@ -10,10 +10,12 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuGroup import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.DropdownMenuPopup import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.MenuDefaults import androidx.compose.material3.SplitButtonDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -40,7 +42,7 @@ import de.mm20.launcher2.ui.component.preferences.TextPreference import kotlinx.serialization.Serializable @Serializable -data object ExportThemeSettingsRoute: NavKey +data object ExportThemeSettingsRoute : NavKey @Composable fun ExportThemeSettingsScreen() { @@ -188,22 +190,27 @@ fun ExportThemeSettingsScreen() { contentDescription = null ) - DropdownMenu( + DropdownMenuPopup( expanded = showDropdown, onDismissRequest = { showDropdown = false }) { - DropdownMenuItem( - text = { Text(stringResource(R.string.save_as_file)) }, - onClick = { - fileChooserLauncher.launch("${viewModel.themeName}.kvtheme") - showDropdown = false - }, - leadingIcon = { - Icon( - painterResource(R.drawable.save_24px), - contentDescription = null - ) - } - ) + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes() + ) { + DropdownMenuItem( + shape = MenuDefaults.standaloneItemShape, + text = { Text(stringResource(R.string.save_as_file)) }, + onClick = { + fileChooserLauncher.launch("${viewModel.themeName}.kvtheme") + showDropdown = false + }, + leadingIcon = { + Icon( + painterResource(R.drawable.save_24px), + contentDescription = null + ) + } + ) + } } } } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/ColorSchemesSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/ColorSchemesSettingsScreen.kt index 5a580c267..cabb177de 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/ColorSchemesSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/ColorSchemesSettingsScreen.kt @@ -11,11 +11,13 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material3.AlertDialog -import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuGroup import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.DropdownMenuPopup import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.MenuDefaults import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable @@ -45,7 +47,7 @@ import de.mm20.launcher2.ui.theme.colorscheme.lightColorSchemeOf import kotlinx.serialization.Serializable @Serializable -data object ColorSchemesSettingsRoute: NavKey +data object ColorSchemesSettingsRoute : NavKey @Composable fun ColorSchemesSettingsScreen() { @@ -85,20 +87,28 @@ fun ColorSchemesSettingsScreen() { onClick = { showMenu = true }) { Icon(painterResource(R.drawable.more_vert_24px), null) } - DropdownMenu( + DropdownMenuPopup( expanded = showMenu, onDismissRequest = { showMenu = false } ) { - DropdownMenuItem( - leadingIcon = { - Icon(painterResource(R.drawable.content_copy_24px), null) - }, - text = { Text(stringResource(R.string.duplicate)) }, - onClick = { - viewModel.duplicate(theme) - showMenu = false - } - ) + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes(), + ) { + DropdownMenuItem( + shape = MenuDefaults.standaloneItemShape, + leadingIcon = { + Icon( + painterResource(R.drawable.content_copy_24px), + null + ) + }, + text = { Text(stringResource(R.string.duplicate)) }, + onClick = { + viewModel.duplicate(theme) + showMenu = false + } + ) + } } } @@ -128,40 +138,56 @@ fun ColorSchemesSettingsScreen() { onClick = { showMenu = true }) { Icon(painterResource(R.drawable.more_vert_24px), null) } - DropdownMenu( + DropdownMenuPopup( expanded = showMenu, onDismissRequest = { showMenu = false } ) { - DropdownMenuItem( - leadingIcon = { - Icon(painterResource(R.drawable.edit_24px), null) - }, - text = { Text(stringResource(R.string.edit)) }, - onClick = { - backStack.add(ColorSchemeSettingsRoute(id = theme.id)) - showMenu = false - } - ) - DropdownMenuItem( - leadingIcon = { - Icon(painterResource(R.drawable.content_copy_24px), null) - }, - text = { Text(stringResource(R.string.duplicate)) }, - onClick = { - viewModel.duplicate(theme) - showMenu = false - } - ) - DropdownMenuItem( - leadingIcon = { - Icon(painterResource(R.drawable.delete_24px), null) - }, - text = { Text(stringResource(R.string.menu_delete)) }, - onClick = { - deleteColors = theme - showMenu = false - } - ) + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes(), + ) { + DropdownMenuItem( + shape = MenuDefaults.leadingItemShape, + leadingIcon = { + Icon( + painterResource(R.drawable.edit_24px), + null + ) + }, + text = { Text(stringResource(R.string.edit)) }, + onClick = { + backStack.add(ColorSchemeSettingsRoute(id = theme.id)) + showMenu = false + } + ) + DropdownMenuItem( + shape = MenuDefaults.middleItemShape, + leadingIcon = { + Icon( + painterResource(R.drawable.content_copy_24px), + null + ) + }, + text = { Text(stringResource(R.string.duplicate)) }, + onClick = { + viewModel.duplicate(theme) + showMenu = false + } + ) + DropdownMenuItem( + shape = MenuDefaults.trailingItemShape, + leadingIcon = { + Icon( + painterResource(R.drawable.delete_24px), + null + ) + }, + text = { Text(stringResource(R.string.menu_delete)) }, + onClick = { + deleteColors = theme + showMenu = false + } + ) + } } } }, diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/hiddenitems/HiddenItemsSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/hiddenitems/HiddenItemsSettingsScreen.kt index cc6058182..046ae555a 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/hiddenitems/HiddenItemsSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/hiddenitems/HiddenItemsSettingsScreen.kt @@ -10,9 +10,12 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuGroup import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.DropdownMenuPopup import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.MenuDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState @@ -209,95 +212,96 @@ private fun VisibilityDropdown( value: VisibilityLevel?, onValueChanged: (VisibilityLevel) -> Unit, ) { - DropdownMenu(expanded = expanded, onDismissRequest = onDismissRequest) { - Text( - text = stringResource(R.string.customize_item_visibility), - color = MaterialTheme.colorScheme.secondary, - style = MaterialTheme.typography.labelMedium, - modifier = Modifier.padding( - start = 48.dp, - top = 12.dp, - bottom = 8.dp, - end = 12.dp, - ) - ) - DropdownMenuItem( - leadingIcon = { - Icon( - painterResource(R.drawable.visibility_24px_filled), - contentDescription = null - ) - }, - text = { + DropdownMenuPopup( + expanded = expanded, + onDismissRequest = onDismissRequest, + ) { + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes(), + ) { + MenuDefaults.Label { Text( - when (item) { - is Application -> stringResource(R.string.item_visibility_app_default) - is CalendarEvent -> stringResource(R.string.item_visibility_calendar_default) - else -> stringResource(R.string.item_visibility_search_only) - } + text = stringResource(R.string.customize_item_visibility), ) - }, - onClick = { - onValueChanged(VisibilityLevel.Default) - }, - trailingIcon = { - if (value == VisibilityLevel.Default) { - Icon( - painterResource(R.drawable.check_24px), - tint = MaterialTheme.colorScheme.primary, - contentDescription = null - ) - } } - ) - if (item is Application || item is CalendarEvent) { + + val count = if (item is Application || item is CalendarEvent) 3 else 2 + DropdownMenuItem( + selected = value == VisibilityLevel.Default, + shapes = MenuDefaults.itemShape(0, count), leadingIcon = { Icon( - painterResource(R.drawable.visibility_24px), + painterResource(R.drawable.visibility_24px_filled), + contentDescription = null + ) + }, + checkedLeadingIcon = { + Icon( + painterResource(R.drawable.check_24px), contentDescription = null ) }, text = { - Text(stringResource(R.string.item_visibility_search_only)) + Text( + when (item) { + is Application -> stringResource(R.string.item_visibility_app_default) + is CalendarEvent -> stringResource(R.string.item_visibility_calendar_default) + else -> stringResource(R.string.item_visibility_search_only) + } + ) }, onClick = { - onValueChanged(VisibilityLevel.SearchOnly) + onValueChanged(VisibilityLevel.Default) }, - trailingIcon = { - if (value == VisibilityLevel.SearchOnly) { + ) + if (item is Application || item is CalendarEvent) { + DropdownMenuItem( + selected = value == VisibilityLevel.SearchOnly, + shapes = MenuDefaults.itemShape(1, count), + leadingIcon = { Icon( - painterResource(R.drawable.check_24px), - tint = MaterialTheme.colorScheme.primary, + painterResource(R.drawable.visibility_24px), contentDescription = null ) - } - } - ) - } - DropdownMenuItem( - leadingIcon = { - Icon( - painterResource(R.drawable.visibility_off_24px), - contentDescription = null + }, + checkedLeadingIcon = { + Icon( + painterResource(R.drawable.check_24px), + contentDescription = null + ) + }, + text = { + Text(stringResource(R.string.item_visibility_search_only)) + }, + onClick = { + onValueChanged(VisibilityLevel.SearchOnly) + }, ) - }, - text = { - Text(stringResource(R.string.item_visibility_hidden)) - }, - onClick = { - onValueChanged(VisibilityLevel.Hidden) - }, - trailingIcon = { - if (value == VisibilityLevel.Hidden) { + } + DropdownMenuItem( + selected = value == VisibilityLevel.Hidden, + shapes = MenuDefaults.itemShape(count - 1, count), + leadingIcon = { Icon( - painterResource(R.drawable.check_24px), - tint = MaterialTheme.colorScheme.primary, + painterResource(R.drawable.visibility_off_24px), contentDescription = null ) - } - } - ) + }, + checkedLeadingIcon = { + Icon( + painterResource(R.drawable.check_24px), + contentDescription = null + ) + }, + text = { + Text(stringResource(R.string.item_visibility_hidden)) + }, + onClick = { + onValueChanged(VisibilityLevel.Hidden) + }, + ) + } } } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/searchactions/EditSearchActionSheet.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/searchactions/EditSearchActionSheet.kt index 3332049c6..ee6778838 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/searchactions/EditSearchActionSheet.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/searchactions/EditSearchActionSheet.kt @@ -31,14 +31,16 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuGroup import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.DropdownMenuPopup import androidx.compose.material3.FilledIconButton import androidx.compose.material3.FilledTonalIconButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.MenuDefaults import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedCard import androidx.compose.material3.OutlinedTextField @@ -580,25 +582,36 @@ fun CustomizeAppSearch(viewModel: EditSearchActionSheetVM) { ) } ) - DropdownMenu( + DropdownMenuPopup( expanded = showAppDropdown, onDismissRequest = { showAppDropdown = false }) { - for (app in availableSearchApps) { - DropdownMenuItem( - text = { Text(app.label) }, - onClick = { - viewModel.setComponentName(app.componentName) - showAppDropdown = false - }, - leadingIcon = { - SearchActionIcon( - size = 24.dp, - componentName = app.componentName, - icon = SearchActionIcon.Custom, - color = 1, - ) - } - ) + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes() + ) { + for ((i, app) in availableSearchApps.withIndex()) { + DropdownMenuItem( + shape = + if (availableSearchApps.size == 1) MenuDefaults.standaloneItemShape + else when (i) { + 0 -> MenuDefaults.leadingItemShape + availableSearchApps.lastIndex -> MenuDefaults.trailingItemShape + else -> MenuDefaults.middleItemShape + }, + text = { Text(app.label) }, + onClick = { + viewModel.setComponentName(app.componentName) + showAppDropdown = false + }, + leadingIcon = { + SearchActionIcon( + size = 24.dp, + componentName = app.componentName, + icon = SearchActionIcon.Custom, + color = 1, + ) + } + ) + } } } } @@ -1112,7 +1125,10 @@ private fun IntentExtrasEditor(viewModel: EditSearchActionSheetVM) { onClick = { viewModel.removeExtra(key) }, modifier = Modifier.padding(horizontal = 8.dp) ) { - Icon(painterResource(R.drawable.do_not_disturb_on_24px), contentDescription = null) + Icon( + painterResource(R.drawable.do_not_disturb_on_24px), + contentDescription = null + ) } } } @@ -1138,7 +1154,10 @@ private fun IntentExtrasEditor(viewModel: EditSearchActionSheetVM) { ) { when (newType) { "bool" -> { - Icon(painterResource(R.drawable.toggle_on_24px), contentDescription = null) + Icon( + painterResource(R.drawable.toggle_on_24px), + contentDescription = null + ) } "string" -> { @@ -1161,76 +1180,91 @@ private fun IntentExtrasEditor(viewModel: EditSearchActionSheetVM) { Text("1.00", style = MaterialTheme.typography.labelSmall) } } - DropdownMenu( + DropdownMenuPopup( expanded = showTypeDropdown, onDismissRequest = { showTypeDropdown = false }) { - DropdownMenuItem( - leadingIcon = { - Text( - "ABC", - style = MaterialTheme.typography.labelSmall - ) - }, - text = { Text("String") }, - onClick = { - newType = "string" - showTypeDropdown = false - }) - DropdownMenuItem( - leadingIcon = { - Text( - "123", - style = MaterialTheme.typography.labelSmall - ) - }, - text = { Text("Integer") }, - onClick = { - newType = "int" - showTypeDropdown = false - }) - DropdownMenuItem( - leadingIcon = { - Text( - "1234", - style = MaterialTheme.typography.labelSmall - ) - }, - text = { Text("Long") }, - onClick = { - newType = "long" - showTypeDropdown = false - }) - DropdownMenuItem( - leadingIcon = { - Text( - "1.0", - style = MaterialTheme.typography.labelSmall - ) - }, - text = { Text("Float") }, - onClick = { - newType = "float" - showTypeDropdown = false - }) - DropdownMenuItem( - leadingIcon = { - Text( - "1.00", - style = MaterialTheme.typography.labelSmall - ) - }, - text = { Text("Double") }, - onClick = { - newType = "double" - showTypeDropdown = false - }) - DropdownMenuItem( - leadingIcon = { Icon(painterResource(R.drawable.toggle_on_24px), null) }, - text = { Text("Boolean") }, - onClick = { - newType = "bool" - showTypeDropdown = false - }) + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes() + ) { + DropdownMenuItem( + shape = MenuDefaults.leadingItemShape, + leadingIcon = { + Text( + "ABC", + style = MaterialTheme.typography.labelSmall + ) + }, + text = { Text("String") }, + onClick = { + newType = "string" + showTypeDropdown = false + }) + DropdownMenuItem( + shape = MenuDefaults.middleItemShape, + leadingIcon = { + Text( + "123", + style = MaterialTheme.typography.labelSmall + ) + }, + text = { Text("Integer") }, + onClick = { + newType = "int" + showTypeDropdown = false + }) + DropdownMenuItem( + shape = MenuDefaults.middleItemShape, + leadingIcon = { + Text( + "1234", + style = MaterialTheme.typography.labelSmall + ) + }, + text = { Text("Long") }, + onClick = { + newType = "long" + showTypeDropdown = false + }) + DropdownMenuItem( + shape = MenuDefaults.middleItemShape, + leadingIcon = { + Text( + "1.0", + style = MaterialTheme.typography.labelSmall + ) + }, + text = { Text("Float") }, + onClick = { + newType = "float" + showTypeDropdown = false + }) + DropdownMenuItem( + shape = MenuDefaults.middleItemShape, + leadingIcon = { + Text( + "1.00", + style = MaterialTheme.typography.labelSmall + ) + }, + text = { Text("Double") }, + onClick = { + newType = "double" + showTypeDropdown = false + }) + DropdownMenuItem( + shape = MenuDefaults.trailingItemShape, + leadingIcon = { + Icon( + painterResource(R.drawable.toggle_on_24px), + null + ) + }, + text = { Text("Boolean") }, + onClick = { + newType = "bool" + showTypeDropdown = false + }) + } } } OutlinedTextField( diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/searchactions/SearchActionsSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/searchactions/SearchActionsSettingsScreen.kt index f574d621f..b909275f3 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/searchactions/SearchActionsSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/searchactions/SearchActionsSettingsScreen.kt @@ -16,12 +16,13 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.items import androidx.compose.material3.CenterAlignedTopAppBar -import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuGroup import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.DropdownMenuPopup import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.MenuDefaults import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -57,7 +58,7 @@ import de.mm20.launcher2.ui.locals.LocalBackStack import kotlinx.serialization.Serializable @Serializable -data object SearchActionsSettingsRoute: NavKey +data object SearchActionsSettingsRoute : NavKey @Composable fun SearchActionsSettingsScreen() { @@ -102,14 +103,18 @@ fun SearchActionsSettingsScreen() { backStack.removeLastOrNull() } }) { - Icon(painterResource(R.drawable.arrow_back_24px), contentDescription = "Back") + Icon( + painterResource(R.drawable.arrow_back_24px), + contentDescription = "Back" + ) } }, actions = { IconButton(onClick = { viewModel.createAction() }) { Icon( painterResource(R.drawable.add_24px), - contentDescription = null) + contentDescription = null + ) } IconButton(onClick = { CustomTabsIntent.Builder() @@ -193,41 +198,50 @@ fun SearchActionsSettingsScreen() { showDropdown = true } ) { - Icon(painterResource(R.drawable.more_vert_24px), stringResource(R.string.edit)) - DropdownMenu( + Icon( + painterResource(R.drawable.more_vert_24px), + stringResource(R.string.edit) + ) + DropdownMenuPopup( expanded = showDropdown, onDismissRequest = { showDropdown = false } ) { - DropdownMenuItem( - leadingIcon = { - Icon( - painterResource(R.drawable.edit_24px), - contentDescription = null - ) - }, - text = { - Text(stringResource(R.string.edit)) - }, - onClick = { - viewModel.editAction(item) - showDropdown = false - } - ) - DropdownMenuItem( - leadingIcon = { - Icon( - painterResource(R.drawable.delete_24px), - contentDescription = null - ) - }, - text = { - Text(stringResource(R.string.menu_delete)) - }, - onClick = { - viewModel.removeAction(item) - showDropdown = false - } - ) + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes() + ) { + DropdownMenuItem( + shape = MenuDefaults.leadingItemShape, + leadingIcon = { + Icon( + painterResource(R.drawable.edit_24px), + contentDescription = null + ) + }, + text = { + Text(stringResource(R.string.edit)) + }, + onClick = { + viewModel.editAction(item) + showDropdown = false + } + ) + DropdownMenuItem( + shape = MenuDefaults.trailingItemShape, + leadingIcon = { + Icon( + painterResource(R.drawable.delete_24px), + contentDescription = null + ) + }, + text = { + Text(stringResource(R.string.menu_delete)) + }, + onClick = { + viewModel.removeAction(item) + showDropdown = false + } + ) + } } } } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/shapes/ShapeSchemesSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/shapes/ShapeSchemesSettingsScreen.kt index 4582a6804..6b86f279a 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/shapes/ShapeSchemesSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/shapes/ShapeSchemesSettingsScreen.kt @@ -9,10 +9,13 @@ import androidx.compose.foundation.shape.CutCornerShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.AlertDialog import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuGroup import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.DropdownMenuPopup import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.MenuDefaults import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable @@ -79,20 +82,28 @@ fun ShapeSchemesSettingsScreen() { onClick = { showMenu = true }) { Icon(painterResource(R.drawable.more_vert_24px), null) } - DropdownMenu( + DropdownMenuPopup( expanded = showMenu, onDismissRequest = { showMenu = false } ) { - DropdownMenuItem( - leadingIcon = { - Icon(painterResource(R.drawable.content_copy_24px), null) - }, - text = { Text(stringResource(R.string.duplicate)) }, - onClick = { - viewModel.duplicate(theme) - showMenu = false - } - ) + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes(), + ) { + DropdownMenuItem( + shape = MenuDefaults.standaloneItemShape, + leadingIcon = { + Icon( + painterResource(R.drawable.content_copy_24px), + null + ) + }, + text = { Text(stringResource(R.string.duplicate)) }, + onClick = { + viewModel.duplicate(theme) + showMenu = false + } + ) + } } } }, @@ -121,40 +132,56 @@ fun ShapeSchemesSettingsScreen() { onClick = { showMenu = true }) { Icon(painterResource(R.drawable.more_vert_24px), null) } - DropdownMenu( + DropdownMenuPopup( expanded = showMenu, onDismissRequest = { showMenu = false } ) { - DropdownMenuItem( - leadingIcon = { - Icon(painterResource(R.drawable.edit_24px), null) - }, - text = { Text(stringResource(R.string.edit)) }, - onClick = { - backStack.add(ShapeSchemeSettingsRoute(id = theme.id)) - showMenu = false - } - ) - DropdownMenuItem( - leadingIcon = { - Icon(painterResource(R.drawable.content_copy_24px), null) - }, - text = { Text(stringResource(R.string.duplicate)) }, - onClick = { - viewModel.duplicate(theme) - showMenu = false - } - ) - DropdownMenuItem( - leadingIcon = { - Icon(painterResource(R.drawable.delete_24px), null) - }, - text = { Text(stringResource(R.string.menu_delete)) }, - onClick = { - deleteShapes = theme - showMenu = false - } - ) + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes(), + ) { + DropdownMenuItem( + shape = MenuDefaults.leadingItemShape, + leadingIcon = { + Icon( + painterResource(R.drawable.edit_24px), + null + ) + }, + text = { Text(stringResource(R.string.edit)) }, + onClick = { + backStack.add(ShapeSchemeSettingsRoute(id = theme.id)) + showMenu = false + } + ) + DropdownMenuItem( + shape = MenuDefaults.middleItemShape, + leadingIcon = { + Icon( + painterResource(R.drawable.content_copy_24px), + null + ) + }, + text = { Text(stringResource(R.string.duplicate)) }, + onClick = { + viewModel.duplicate(theme) + showMenu = false + } + ) + DropdownMenuItem( + shape = MenuDefaults.trailingItemShape, + leadingIcon = { + Icon( + painterResource(R.drawable.delete_24px), + null + ) + }, + text = { Text(stringResource(R.string.menu_delete)) }, + onClick = { + deleteShapes = theme + showMenu = false + } + ) + } } } }, diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/tags/TagsSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/tags/TagsSettingsScreen.kt index b39f7d879..2c6707454 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/tags/TagsSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/tags/TagsSettingsScreen.kt @@ -1,10 +1,11 @@ package de.mm20.launcher2.ui.settings.tags -import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuGroup import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.DropdownMenuPopup import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.MenuDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState @@ -26,7 +27,7 @@ import de.mm20.launcher2.ui.launcher.sheets.EditTagSheet import kotlinx.serialization.Serializable @Serializable -data object TagsSettingsRoute: NavKey +data object TagsSettingsRoute : NavKey @Composable fun TagsSettingsScreen() { @@ -38,7 +39,10 @@ fun TagsSettingsScreen() { title = stringResource(R.string.preference_screen_tags), topBarActions = { IconButton(onClick = { viewModel.createTag.value = true }) { - Icon(painterResource(R.drawable.add_24px), stringResource(R.string.edit_favorites_dialog_new_tag)) + Icon( + painterResource(R.drawable.add_24px), + stringResource(R.string.edit_favorites_dialog_new_tag) + ) } }, helpUrl = "https://kvaesitso.mm20.de/docs/user-guide/concepts/tags" @@ -65,25 +69,41 @@ fun TagsSettingsScreen() { IconButton(onClick = { showMenu = true }) { Icon(painterResource(R.drawable.more_vert_24px), null) } - DropdownMenu( + DropdownMenuPopup( expanded = showMenu, onDismissRequest = { showMenu = false }) { - DropdownMenuItem( - text = { Text(stringResource(R.string.duplicate)) }, - leadingIcon = { Icon(painterResource(R.drawable.content_copy_24px), null) }, - onClick = { - viewModel.duplicateTag(tag) - showMenu = false - } - ) - DropdownMenuItem( - text = { Text(stringResource(R.string.menu_delete)) }, - leadingIcon = { Icon(painterResource(R.drawable.delete_24px), null) }, - onClick = { - viewModel.deleteTag(tag) - showMenu = false - } - ) + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes() + ) { + DropdownMenuItem( + shape = MenuDefaults.leadingItemShape, + text = { Text(stringResource(R.string.duplicate)) }, + leadingIcon = { + Icon( + painterResource(R.drawable.content_copy_24px), + null + ) + }, + onClick = { + viewModel.duplicateTag(tag) + showMenu = false + } + ) + DropdownMenuItem( + shape = MenuDefaults.trailingItemShape, + text = { Text(stringResource(R.string.menu_delete)) }, + leadingIcon = { + Icon( + painterResource(R.drawable.delete_24px), + null + ) + }, + onClick = { + viewModel.deleteTag(tag) + showMenu = false + } + ) + } } } ) diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/transparencies/TransparencySchemesSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/transparencies/TransparencySchemesSettingsScreen.kt index b97c19186..e4c8c5939 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/transparencies/TransparencySchemesSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/transparencies/TransparencySchemesSettingsScreen.kt @@ -7,11 +7,13 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.material3.AlertDialog -import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuGroup import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.DropdownMenuPopup import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.MenuDefaults import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.surfaceColorAtElevation @@ -43,7 +45,7 @@ import de.mm20.launcher2.ui.theme.wallpaperColorsAsState import kotlinx.serialization.Serializable @Serializable -data object TransparencySchemesSettingsRoute: NavKey +data object TransparencySchemesSettingsRoute : NavKey @Composable fun TransparencySchemesSettingsScreen() { @@ -85,20 +87,28 @@ fun TransparencySchemesSettingsScreen() { onClick = { showMenu = true }) { Icon(painterResource(R.drawable.more_vert_24px), null) } - DropdownMenu( + DropdownMenuPopup( expanded = showMenu, onDismissRequest = { showMenu = false } ) { - DropdownMenuItem( - leadingIcon = { - Icon(painterResource(R.drawable.content_copy_24px), null) - }, - text = { Text(stringResource(R.string.duplicate)) }, - onClick = { - viewModel.duplicate(theme) - showMenu = false - } - ) + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes(), + ) { + DropdownMenuItem( + shape = MenuDefaults.standaloneItemShape, + leadingIcon = { + Icon( + painterResource(R.drawable.content_copy_24px), + null + ) + }, + text = { Text(stringResource(R.string.duplicate)) }, + onClick = { + viewModel.duplicate(theme) + showMenu = false + } + ) + } } } }, @@ -127,40 +137,60 @@ fun TransparencySchemesSettingsScreen() { onClick = { showMenu = true }) { Icon(painterResource(R.drawable.more_vert_24px), null) } - DropdownMenu( + DropdownMenuPopup( expanded = showMenu, onDismissRequest = { showMenu = false } ) { - DropdownMenuItem( - leadingIcon = { - Icon(painterResource(R.drawable.edit_24px), null) - }, - text = { Text(stringResource(R.string.edit)) }, - onClick = { - backStack.add(TransparencySchemeSettingsRoute(theme.id)) - showMenu = false - } - ) - DropdownMenuItem( - leadingIcon = { - Icon(painterResource(R.drawable.content_copy_24px), null) - }, - text = { Text(stringResource(R.string.duplicate)) }, - onClick = { - viewModel.duplicate(theme) - showMenu = false - } - ) - DropdownMenuItem( - leadingIcon = { - Icon(painterResource(R.drawable.delete_24px), null) - }, - text = { Text(stringResource(R.string.menu_delete)) }, - onClick = { - deleteTransparencies = theme - showMenu = false - } - ) + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes(), + ) { + DropdownMenuItem( + shape = MenuDefaults.leadingItemShape, + leadingIcon = { + Icon( + painterResource(R.drawable.edit_24px), + null + ) + }, + text = { Text(stringResource(R.string.edit)) }, + onClick = { + backStack.add( + TransparencySchemeSettingsRoute( + theme.id + ) + ) + showMenu = false + } + ) + DropdownMenuItem( + shape = MenuDefaults.middleItemShape, + leadingIcon = { + Icon( + painterResource(R.drawable.content_copy_24px), + null + ) + }, + text = { Text(stringResource(R.string.duplicate)) }, + onClick = { + viewModel.duplicate(theme) + showMenu = false + } + ) + DropdownMenuItem( + shape = MenuDefaults.trailingItemShape, + leadingIcon = { + Icon( + painterResource(R.drawable.delete_24px), + null + ) + }, + text = { Text(stringResource(R.string.menu_delete)) }, + onClick = { + deleteTransparencies = theme + showMenu = false + } + ) + } } } }, diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/typography/TypographiesSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/typography/TypographiesSettingsScreen.kt index 400607bf9..fd011ea7d 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/typography/TypographiesSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/typography/TypographiesSettingsScreen.kt @@ -6,10 +6,13 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding import androidx.compose.material3.AlertDialog import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuGroup import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.DropdownMenuPopup import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.MenuDefaults import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable @@ -92,20 +95,28 @@ fun TypographiesSettingsScreen() { onClick = { showMenu = true }) { Icon(painterResource(R.drawable.more_vert_24px), null) } - DropdownMenu( + DropdownMenuPopup( expanded = showMenu, onDismissRequest = { showMenu = false } ) { - DropdownMenuItem( - leadingIcon = { - Icon(painterResource(R.drawable.content_copy_24px), null) - }, - text = { Text(stringResource(R.string.duplicate)) }, - onClick = { - viewModel.duplicate(theme) - showMenu = false - } - ) + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes(), + ) { + DropdownMenuItem( + shape = MenuDefaults.standaloneItemShape, + leadingIcon = { + Icon( + painterResource(R.drawable.content_copy_24px), + null + ) + }, + text = { Text(stringResource(R.string.duplicate)) }, + onClick = { + viewModel.duplicate(theme) + showMenu = false + } + ) + } } } }, @@ -149,40 +160,56 @@ fun TypographiesSettingsScreen() { onClick = { showMenu = true }) { Icon(painterResource(R.drawable.more_vert_24px), null) } - DropdownMenu( + DropdownMenuPopup( expanded = showMenu, onDismissRequest = { showMenu = false } ) { - DropdownMenuItem( - leadingIcon = { - Icon(painterResource(R.drawable.edit_24px), null) - }, - text = { Text(stringResource(R.string.edit)) }, - onClick = { - backStack.add(TypographySettingsRoute(theme.id)) - showMenu = false - } - ) - DropdownMenuItem( - leadingIcon = { - Icon(painterResource(R.drawable.content_copy_24px), null) - }, - text = { Text(stringResource(R.string.duplicate)) }, - onClick = { - viewModel.duplicate(theme) - showMenu = false - } - ) - DropdownMenuItem( - leadingIcon = { - Icon(painterResource(R.drawable.delete_24px), null) - }, - text = { Text(stringResource(R.string.menu_delete)) }, - onClick = { - deleteTypography = theme - showMenu = false - } - ) + DropdownMenuGroup( + shapes = MenuDefaults.groupShapes(), + ) { + DropdownMenuItem( + shape = MenuDefaults.leadingItemShape, + leadingIcon = { + Icon( + painterResource(R.drawable.edit_24px), + null + ) + }, + text = { Text(stringResource(R.string.edit)) }, + onClick = { + backStack.add(TypographySettingsRoute(theme.id)) + showMenu = false + } + ) + DropdownMenuItem( + shape = MenuDefaults.middleItemShape, + leadingIcon = { + Icon( + painterResource(R.drawable.content_copy_24px), + null + ) + }, + text = { Text(stringResource(R.string.duplicate)) }, + onClick = { + viewModel.duplicate(theme) + showMenu = false + } + ) + DropdownMenuItem( + shape = MenuDefaults.trailingItemShape, + leadingIcon = { + Icon( + painterResource(R.drawable.delete_24px), + null + ) + }, + text = { Text(stringResource(R.string.menu_delete)) }, + onClick = { + deleteTypography = theme + showMenu = false + } + ) + } } } }, diff --git a/core/base/src/main/res/drawable/arrow_right_24px.xml b/core/base/src/main/res/drawable/arrow_right_24px.xml new file mode 100644 index 000000000..5ed1a5011 --- /dev/null +++ b/core/base/src/main/res/drawable/arrow_right_24px.xml @@ -0,0 +1,11 @@ + + +