update dropdown menus

This commit is contained in:
MM20
2025-11-30 21:30:38 +01:00
parent 28fe68ed8d
commit 3429555c8d
20 changed files with 1267 additions and 817 deletions

View File

@@ -16,9 +16,11 @@ import androidx.compose.foundation.lazy.grid.items
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuGroup
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.DropdownMenuPopup
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.SearchBar import androidx.compose.material3.SearchBar
import androidx.compose.material3.SearchBarDefaults import androidx.compose.material3.SearchBarDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
@@ -182,31 +184,54 @@ fun IconPicker(
contentDescription = null contentDescription = null
) )
} }
DropdownMenu( DropdownMenuPopup(
expanded = showIconPackFilter, expanded = showIconPackFilter,
onDismissRequest = { showIconPackFilter = false }) { onDismissRequest = { showIconPackFilter = false }
DropdownMenuItem( ) {
text = { Text(stringResource(id = R.string.icon_picker_filter_all_packs)) }, DropdownMenuGroup(
onClick = { shapes = MenuDefaults.groupShapes()
showIconPackFilter = false ) {
filterIconPack = null
scope.launch {
viewModel.searchIcon(query, filterIconPack)
}
}
)
installedIconPacks?.forEach { iconPack ->
DropdownMenuItem( 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 = { onClick = {
showIconPackFilter = false showIconPackFilter = false
filterIconPack = iconPack filterIconPack = null
scope.launch { scope.launch {
viewModel.searchIcon(query, filterIconPack) viewModel.searchIcon(query, filterIconPack)
} }
}, },
text = { checkedLeadingIcon = {
Text(iconPack.name) 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( Text(

View File

@@ -4,6 +4,7 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth 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.rememberScrollState
import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardActions 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.DropdownMenuItem
import androidx.compose.material3.DropdownMenuPopup
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.InputChip import androidx.compose.material3.InputChip
import androidx.compose.material3.InputChipDefaults import androidx.compose.material3.InputChipDefaults
import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.OutlinedTextFieldDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -134,9 +137,7 @@ fun OutlinedTagsInputField(
label = label, label = label,
leadingIcon = leadingIcon, leadingIcon = leadingIcon,
innerTextField = { innerTextField = {
Box( Column {
contentAlignment = Alignment.CenterStart,
) {
Row( Row(
modifier = Modifier modifier = Modifier
.requiredHeight(32.dp) .requiredHeight(32.dp)
@@ -188,21 +189,33 @@ fun OutlinedTagsInputField(
} }
} }
if (completions.isNotEmpty()) { if (completions.isNotEmpty()) {
Box(modifier = Modifier.fillMaxWidth()) { Box {
DropdownMenu( DropdownMenuPopup(
expanded = true, expanded = true,
onDismissRequest = { completions = emptyList() }, onDismissRequest = { completions = emptyList() },
properties = PopupProperties(focusable = false) properties = PopupProperties(focusable = false)
) { ) {
for (completion in completions) { DropdownMenuGroup(
DropdownMenuItem( modifier = Modifier.fillMaxWidth(),
text = { Text(completion) }, shapes = MenuDefaults.groupShapes()
onClick = { ) {
onTagsChange(tags + completion) for ((i, completion) in completions.withIndex()) {
value = "" DropdownMenuItem(
completions = emptyList() 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()
},
)
}
} }
} }
} }

View File

@@ -9,9 +9,12 @@ import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuGroup
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.DropdownMenuPopup
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@@ -61,13 +64,17 @@ fun Icons(actions: List<ToolbarAction>, slots: Int) {
modifier = Modifier modifier = Modifier
.size(48.dp) .size(48.dp)
) { ) {
DropdownMenu( DropdownMenuPopup(
expanded = showMenu, expanded = showMenu,
onDismissRequest = { showMenu = false }, onDismissRequest = { showMenu = false },
modifier = Modifier.animateContentSize() modifier = Modifier.animateContentSize()
) { ) {
OverflowMenuItems(items = actions.subList(slots - 1, actions.size)) { DropdownMenuGroup(
showMenu = false shapes = MenuDefaults.groupShapes()
) {
OverflowMenuItems(items = actions.subList(slots - 1, actions.size)) {
showMenu = false
}
} }
} }
} }
@@ -102,13 +109,17 @@ fun Icons(actions: List<ToolbarAction>, slots: Int) {
.size(48.dp) .size(48.dp)
.offset(0.dp, LocalWindowPosition.current.toDp()) .offset(0.dp, LocalWindowPosition.current.toDp())
) { ) {
DropdownMenu( DropdownMenuPopup(
expanded = showMenu, expanded = showMenu,
onDismissRequest = { showMenu = false }, onDismissRequest = { showMenu = false },
modifier = Modifier.animateContentSize() modifier = Modifier.animateContentSize()
) { ) {
OverflowMenuItems(items = action.children) { DropdownMenuGroup(
showMenu = false shapes = MenuDefaults.groupShapes()
) {
OverflowMenuItems(items = action.children) {
showMenu = false
}
} }
} }
} }
@@ -138,7 +149,12 @@ fun ColumnScope.OverflowMenuItems(items: List<ToolbarAction>, onDismiss: () -> U
Icon(painterResource(action.icon), null) Icon(painterResource(action.icon), null)
}, },
trailingIcon = { 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<ToolbarAction>, onDismiss: () -> U
}, },
leadingIcon = { leadingIcon = {
Icon(painterResource(action.icon), null) Icon(painterResource(action.icon), null)
},
shape = when {
i == 0 -> MenuDefaults.leadingItemShape
i == items.lastIndex -> MenuDefaults.trailingItemShape
else -> MenuDefaults.middleItemShape
} }
) )
} }

View File

@@ -7,27 +7,30 @@ import androidx.browser.customtabs.CustomTabsIntent
import androidx.compose.animation.graphics.res.animatedVectorResource import androidx.compose.animation.graphics.res.animatedVectorResource
import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter
import androidx.compose.animation.graphics.vector.AnimatedImageVector import androidx.compose.animation.graphics.vector.AnimatedImageVector
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.RowScope 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.DropdownMenuItem
import androidx.compose.material3.DropdownMenuPopup
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue 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.graphics.toArgb
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.ui.R 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 import de.mm20.launcher2.ui.settings.SettingsActivity
@Composable @Composable
@@ -38,72 +41,88 @@ fun RowScope.SearchBarMenu(
val context = LocalContext.current val context = LocalContext.current
var showOverflowMenu by remember { mutableStateOf(false) } var showOverflowMenu by remember { mutableStateOf(false) }
val rightIcon = AnimatedImageVector.animatedVectorResource(R.drawable.anim_ic_menu_clear) val rightIcon = AnimatedImageVector.animatedVectorResource(R.drawable.anim_ic_menu_clear)
val launcherVM: LauncherScaffoldVM = viewModel()
val widgetsVM: WidgetsVM = viewModel()
IconButton(onClick = { Box(contentAlignment = Alignment.TopEnd) {
if (searchBarValue.isNotBlank()) onInputClear() IconButton(onClick = {
else showOverflowMenu = true if (searchBarValue.isNotBlank()) onInputClear()
}) { else showOverflowMenu = true
Icon( }) {
painter = rememberAnimatedVectorPainter( Icon(
rightIcon, painter = rememberAnimatedVectorPainter(
atEnd = searchBarValue.isNotEmpty() rightIcon,
), atEnd = searchBarValue.isNotEmpty()
contentDescription = stringResource(if (searchBarValue.isNotBlank()) R.string.action_clear else R.string.action_more_actions), ),
tint = LocalContentColor.current 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( DropdownMenuPopup(
onClick = { expanded = showOverflowMenu,
context.startActivity( onDismissRequest = { showOverflowMenu = false },
Intent.createChooser( ) {
Intent(Intent.ACTION_SET_WALLPAPER), DropdownMenuGroup(
null 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 DropdownMenuItem(
}, shape = MenuDefaults.middleItemShape,
text = { onClick = {
Text(stringResource(R.string.wallpaper)) context.startActivity(Intent(context, SettingsActivity::class.java))
}, showOverflowMenu = false
leadingIcon = { },
Icon(painterResource(R.drawable.wallpaper_24px), contentDescription = null) text = {
} Text(stringResource(R.string.settings))
) },
DropdownMenuItem( leadingIcon = {
onClick = { Icon(painterResource(R.drawable.settings_24px), contentDescription = null)
context.startActivity(Intent(context, SettingsActivity::class.java)) }
showOverflowMenu = false )
}, val colorScheme = MaterialTheme.colorScheme
text = { DropdownMenuItem(
Text(stringResource(R.string.settings)) shape = MenuDefaults.trailingItemShape,
}, onClick = {
leadingIcon = { CustomTabsIntent.Builder()
Icon(painterResource(R.drawable.settings_24px), contentDescription = null) .setDefaultColorSchemeParams(
} CustomTabColorSchemeParams.Builder()
) .setToolbarColor(colorScheme.primaryContainer.toArgb())
val colorScheme = MaterialTheme.colorScheme .setSecondaryToolbarColor(colorScheme.secondaryContainer.toArgb())
DropdownMenuItem( .build()
onClick = { )
CustomTabsIntent.Builder()
.setDefaultColorSchemeParams(
CustomTabColorSchemeParams.Builder()
.setToolbarColor(colorScheme.primaryContainer.toArgb())
.setSecondaryToolbarColor(colorScheme.secondaryContainer.toArgb())
.build() .build()
) .launchUrl(
.build() context,
.launchUrl(context, Uri.parse("https://kvaesitso.mm20.de/docs/user-guide")) Uri.parse("https://kvaesitso.mm20.de/docs/user-guide")
showOverflowMenu = false )
}, showOverflowMenu = false
text = { },
Text(stringResource(R.string.help)) text = {
}, Text(stringResource(R.string.help))
leadingIcon = { },
Icon(painterResource(R.drawable.help_24px), contentDescription = null) leadingIcon = {
Icon(painterResource(R.drawable.help_24px), contentDescription = null)
}
)
} }
) }
} }
} }

View File

@@ -26,14 +26,14 @@ import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuGroup
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.DropdownMenuPopup
import androidx.compose.material3.FilledTonalIconButton import androidx.compose.material3.FilledTonalIconButton
import androidx.compose.material3.FilledTonalIconToggleButton import androidx.compose.material3.FilledTonalIconToggleButton
import androidx.compose.material3.FilterChipDefaults
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.OutlinedCard import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.Slider import androidx.compose.material3.Slider
import androidx.compose.material3.SliderDefaults import androidx.compose.material3.SliderDefaults
@@ -117,7 +117,7 @@ fun EditFavoritesSheet(
} else { } else {
ReorderFavoritesGrid(viewModel, it) ReorderFavoritesGrid(viewModel, it)
if (createShortcutTarget != null) { if (createShortcutTarget != null) {
BottomSheetDialog({viewModel.cancelPickShortcut()}) { BottomSheetDialog({ viewModel.cancelPickShortcut() }) {
ShortcutPicker(viewModel, it) ShortcutPicker(viewModel, it)
} }
} }
@@ -243,23 +243,28 @@ fun ReorderFavoritesGrid(viewModel: EditFavoritesSheetVM, paddingValues: Padding
badge = badge badge = badge
) )
if (contextMenuItemKey == it.item.key) { if (contextMenuItemKey == it.item.key) {
DropdownMenu( DropdownMenuPopup(
expanded = true, expanded = true,
onDismissRequest = { contextMenuItemKey = null }) { onDismissRequest = { contextMenuItemKey = null }) {
DropdownMenuItem( DropdownMenuGroup(
leadingIcon = { shapes = MenuDefaults.groupShapes()
Icon( ) {
painterResource(R.drawable.delete_24px), DropdownMenuItem(
contentDescription = null shape = MenuDefaults.standaloneItemShape,
) leadingIcon = {
}, Icon(
text = { painterResource(R.drawable.delete_24px),
Text(stringResource(R.string.menu_remove)) contentDescription = null
}, onClick = { )
contextMenuItemKey?.let { viewModel.remove(it) } },
contextMenuItemKey = 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 contentDescription = null
) )
} }
DropdownMenu( DropdownMenuPopup(
expanded = showAddMenu, expanded = showAddMenu,
onDismissRequest = { showAddMenu = false }) { 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()) { if (availableTags.isNotEmpty()) {
HorizontalDivider() DropdownMenuGroup(
} shapes = MenuDefaults.groupShape(0, 2),
DropdownMenuItem( ) {
leadingIcon = { for ((i, tag) in availableTags.withIndex()) {
Icon(painterResource(R.drawable.add_24px), null) DropdownMenuItem(
}, shape = if (availableTags.size == 1) MenuDefaults.standaloneItemShape
text = { else when (i) {
Text( 0 -> MenuDefaults.leadingItemShape
stringResource(R.string.edit_favorites_dialog_new_tag), availableTags.lastIndex -> MenuDefaults.trailingItemShape
) else -> MenuDefaults.middleItemShape
}, },
onClick = { leadingIcon = {
createTag = true Icon(
showAddMenu = false 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
}
)
}
} }
} }

View File

@@ -16,11 +16,13 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding 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.DropdownMenuItem
import androidx.compose.material3.DropdownMenuPopup
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -44,10 +46,8 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.repeatOnLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.Quadruple
import de.mm20.launcher2.Quintuple import de.mm20.launcher2.Quintuple
import de.mm20.launcher2.ui.R 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.component.MissingPermissionBanner
import de.mm20.launcher2.ui.launcher.search.common.list.SearchResultList import de.mm20.launcher2.ui.launcher.search.common.list.SearchResultList
import de.mm20.launcher2.widgets.CalendarWidget 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) modifier = Modifier.padding(start = 8.dp, end = 8.dp, top = 8.dp, bottom = 4.dp)
) { ) {
IconButton(onClick = { viewModel.previousDay() }) { 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( Box(
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
@@ -101,26 +104,49 @@ fun CalendarWidget(
tint = MaterialTheme.colorScheme.onSurface, tint = MaterialTheme.colorScheme.onSurface,
) )
} }
DropdownMenu(expanded = showDropdown, onDismissRequest = { showDropdown = false }) { DropdownMenuPopup(
expanded = showDropdown,
onDismissRequest = { showDropdown = false }) {
val availableDates = viewModel.availableDates val availableDates = viewModel.availableDates
for (date in availableDates) { DropdownMenuGroup(
DropdownMenuItem(text = { shapes = MenuDefaults.groupShapes()
Text(formatDay(context, date)) ) {
}, onClick = { for ((i, date) in availableDates.withIndex()) {
viewModel.selectDate(date) DropdownMenuItem(
showDropdown = false 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() }) { 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) }) { 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) }) { 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 val events by viewModel.calendarEvents

View File

@@ -16,13 +16,15 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuGroup
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.DropdownMenuPopup
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.OutlinedCard import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.SegmentedButton import androidx.compose.material3.SegmentedButton
import androidx.compose.material3.SegmentedButtonDefaults 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.ClockWidgetAlignment
import de.mm20.launcher2.preferences.ClockWidgetColors import de.mm20.launcher2.preferences.ClockWidgetColors
import de.mm20.launcher2.preferences.ClockWidgetStyle import de.mm20.launcher2.preferences.ClockWidgetStyle
import de.mm20.launcher2.preferences.TimeFormat
import de.mm20.launcher2.preferences.ui.ClockWidgetSettings import de.mm20.launcher2.preferences.ui.ClockWidgetSettings
import de.mm20.launcher2.ui.R import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.base.LocalTime import de.mm20.launcher2.ui.base.LocalTime
@@ -548,46 +549,74 @@ fun ConfigureClockWidgetSheet(
}, },
enabled = fillHeight == true, enabled = fillHeight == true,
) )
DropdownMenu( DropdownMenuPopup(
expanded = showDropdown, expanded = showDropdown,
onDismissRequest = { showDropdown = false }) { onDismissRequest = { showDropdown = false }) {
DropdownMenuItem( DropdownMenuGroup(
leadingIcon = { shapes = MenuDefaults.groupShapes()
Icon( ) {
painterResource(R.drawable.align_vertical_top_24px), DropdownMenuItem(
null shapes = MenuDefaults.itemShape(0, 3),
) selected = alignment == ClockWidgetAlignment.Top,
}, checkedLeadingIcon = {
text = { Text(stringResource(R.string.preference_clock_widget_alignment_top)) }, Icon(
onClick = { painterResource(R.drawable.check_24px),
viewModel.setAlignment(ClockWidgetAlignment.Top) null
showDropdown = false )
} },
) leadingIcon = {
DropdownMenuItem( Icon(
leadingIcon = { painterResource(R.drawable.align_vertical_top_24px),
Icon( null
painterResource(R.drawable.align_vertical_center_24px), )
null },
) text = { Text(stringResource(R.string.preference_clock_widget_alignment_top)) },
}, onClick = {
text = { Text(stringResource(R.string.preference_clock_widget_alignment_center)) }, viewModel.setAlignment(ClockWidgetAlignment.Top)
onClick = { showDropdown = false
viewModel.setAlignment(ClockWidgetAlignment.Center) }
showDropdown = false )
}) DropdownMenuItem(
DropdownMenuItem( shapes = MenuDefaults.itemShape(1, 3),
leadingIcon = { selected = alignment == ClockWidgetAlignment.Center,
Icon( checkedLeadingIcon = {
painterResource(R.drawable.align_vertical_bottom_24px), Icon(
null painterResource(R.drawable.check_24px),
) null
}, )
text = { Text(stringResource(R.string.preference_clock_widget_alignment_bottom)) }, },
onClick = { leadingIcon = {
viewModel.setAlignment(ClockWidgetAlignment.Bottom) Icon(
showDropdown = false 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
})
}
} }
} }
} }

View File

@@ -28,12 +28,15 @@ import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuGroup
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.DropdownMenuPopup
import androidx.compose.material3.FilledIconButton import androidx.compose.material3.FilledIconButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
@@ -151,108 +154,153 @@ fun WatchFaceSelector(
.padding(4.dp) .padding(4.dp)
) { ) {
Icon(painterResource(R.drawable.tune_24px), null) Icon(painterResource(R.drawable.tune_24px), null)
DropdownMenu( DropdownMenuPopup(
expanded = showStyleSettings, expanded = showStyleSettings,
onDismissRequest = { showStyleSettings = false }) { onDismissRequest = { showStyleSettings = false }) {
if (selected is ClockWidgetStyle.Digital1) { if (selected is ClockWidgetStyle.Digital1) {
DropdownMenuItem( DropdownMenuGroup(
text = { Text(stringResource(R.string.clock_variant_outlined)) }, shapes = MenuDefaults.groupShapes()
leadingIcon = { ) {
Icon( DropdownMenuItem(
painterResource( checked = selected.outlined,
if (selected.outlined) R.drawable.check_circle_24px_filled onCheckedChange = {
else R.drawable.circle_24px, onSelect(selected.copy(outlined = it))
), },
null shapes = MenuDefaults.itemShapes(),
) text = { Text(stringResource(R.string.clock_variant_outlined)) },
}, leadingIcon = {
onClick = { Icon(
onSelect(selected.copy(outlined = !selected.outlined)) painterResource(R.drawable.circle_24px),
} null
) )
},
checkedLeadingIcon = {
Icon(
painterResource(R.drawable.check_circle_24px_filled),
null
)
},
)
}
} }
if (selected is ClockWidgetStyle.Analog) { if (selected is ClockWidgetStyle.Analog) {
DropdownMenuItem( DropdownMenuGroup(
text = { Text(stringResource(R.string.clock_variant_analog_ticks)) }, shapes = MenuDefaults.groupShapes()
leadingIcon = { ) {
Icon( DropdownMenuItem(
painterResource( text = { Text(stringResource(R.string.clock_variant_analog_ticks)) },
if (selected.showTicks) R.drawable.check_circle_24px_filled leadingIcon = {
else R.drawable.circle_24px, Icon(
), painterResource(R.drawable.circle_24px),
null null
) )
}, },
onClick = { checkedLeadingIcon = {
onSelect(selected.copy(showTicks = !selected.showTicks)) 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) { if (selected is ClockWidgetStyle.Custom) {
DropdownMenuItem( DropdownMenuGroup(
text = { Text(stringResource(R.string.widget_pick_widget)) }, shapes = MenuDefaults.groupShapes()
leadingIcon = { ) {
Icon(painterResource(R.drawable.swap_horiz_24px), null) val widget = remember(selected.widgetId) {
}, val id = selected.widgetId ?: return@remember null
onClick = { AppWidgetManager.getInstance(context)
showWidgetPicker = true .getAppWidgetInfo(id)
showStyleSettings = false
} }
)
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( DropdownMenuItem(
text = { Text(stringResource(R.string.widget_config_appwidget_configure)) }, text = { Text(stringResource(R.string.widget_pick_widget)) },
leadingIcon = { leadingIcon = {
Icon(painterResource(R.drawable.settings_24px), null) Icon(
painterResource(R.drawable.swap_horiz_24px),
null
)
}, },
onClick = { onClick = {
appWidgetHost.startAppWidgetConfigureActivityForResult( showWidgetPicker = true
getActivityFromContext(context) ?: return@DropdownMenuItem, showStyleSettings = false
selected.widgetId ?: return@DropdownMenuItem, },
0, shape = MenuDefaults.leadingItemShape,
0, )
if (Build.VERSION.SDK_INT < 34) { 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 null
} else { )
ActivityOptions.makeBasic() },
.setPendingIntentBackgroundActivityStartMode( onClick = {
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED appWidgetHost.startAppWidgetConfigureActivityForResult(
) getActivityFromContext(context)
.toBundle() ?: 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)
} }
) onSelect(
} ClockWidgetStyle.Custom()
) )
} },
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()
)
}
)
} }
} }
} }
@@ -376,27 +424,38 @@ fun WatchFaceSelector(
.padding(ButtonDefaults.IconSpacing) .padding(ButtonDefaults.IconSpacing)
.size(ButtonDefaults.IconSize) .size(ButtonDefaults.IconSize)
) )
DropdownMenu( DropdownMenuPopup(
expanded = showStyleDropdown, expanded = showStyleDropdown,
onDismissRequest = { showStyleDropdown = false } onDismissRequest = { showStyleDropdown = false }
) { ) {
for (style in styles.withIndex()) { DropdownMenuGroup(
DropdownMenuItem( shapes = MenuDefaults.groupShapes()
onClick = { ) {
scope.launch { for (style in styles.withIndex()) {
pagerState.animateScrollToPage( DropdownMenuItem(
style.index, 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),
)
}
)
}
} }
} }

View File

@@ -31,14 +31,16 @@ import androidx.compose.foundation.layout.requiredHeightIn
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.shape.RoundedCornerShape 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.DropdownMenuItem
import androidx.compose.material3.DropdownMenuPopup
import androidx.compose.material3.FilledTonalIconButton import androidx.compose.material3.FilledTonalIconButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.Slider import androidx.compose.material3.Slider
import androidx.compose.material3.SliderDefaults import androidx.compose.material3.SliderDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
@@ -433,27 +435,38 @@ fun CustomActions(
) )
} }
} }
DropdownMenu( DropdownMenuPopup(
expanded = showOverflowMenu, expanded = showOverflowMenu,
onDismissRequest = { showOverflowMenu = false }, onDismissRequest = { showOverflowMenu = false },
) { ) {
for (i in slots - 1 until actions.customActions.size) { DropdownMenuGroup(
val action = actions.customActions[i] shapes = MenuDefaults.groupShapes(),
DropdownMenuItem( ) {
leadingIcon = { for (i in slots - 1 until actions.customActions.size) {
CustomActionIcon(action, playerPackage) val action = actions.customActions[i]
}, DropdownMenuItem(
text = { shape =
Text( if (actions.customActions.size == 1) MenuDefaults.standaloneItemShape
text = action.name.toString(), else when (i) {
maxLines = 1, 0 -> MenuDefaults.leadingItemShape
overflow = TextOverflow.Ellipsis, actions.customActions.lastIndex -> MenuDefaults.trailingItemShape
) else -> MenuDefaults.middleItemShape
}, },
onClick = { leadingIcon = {
onActionSelected(action) CustomActionIcon(action, playerPackage)
} },
) text = {
Text(
text = action.name.toString(),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
},
onClick = {
onActionSelected(action)
}
)
}
} }
} }
} }

View File

@@ -23,11 +23,13 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuGroup
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.DropdownMenuPopup
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.SnackbarDuration import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarResult import androidx.compose.material3.SnackbarResult
@@ -255,103 +257,118 @@ fun NotesWidget(
tooltipText = stringResource(R.string.action_more_actions) tooltipText = stringResource(R.string.action_more_actions)
) { ) {
IconButton(onClick = { showMenu = true }) { 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 }) { DropdownMenuPopup(
DropdownMenuItem( expanded = showMenu,
text = { Text(stringResource(R.string.notes_widget_action_new)) }, onDismissRequest = { showMenu = false }) {
leadingIcon = { DropdownMenuGroup(
Icon(painterResource(R.drawable.add_24px), null) shapes = MenuDefaults.groupShapes(),
}, ) {
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) {
DropdownMenuItem( DropdownMenuItem(
text = { Text(stringResource(R.string.note_widget_link_file)) }, shape = MenuDefaults.leadingItemShape,
text = { Text(stringResource(R.string.notes_widget_action_new)) },
leadingIcon = { leadingIcon = {
Icon(painterResource(R.drawable.link_24px), null) Icon(painterResource(R.drawable.add_24px), null)
}, },
onClick = { onClick = {
linkFileLauncher.launch(getDefaultNoteFileName(context)) val newWidget = NotesWidget(
id = UUID.randomUUID(),
)
onWidgetAdd(newWidget, 1)
showMenu = false showMenu = false
}, },
) )
} else {
DropdownMenuItem( DropdownMenuItem(
text = { Text(stringResource(R.string.note_widget_action_unlink_file)) }, shape = MenuDefaults.middleItemShape,
text = { Text(stringResource(R.string.menu_share)) },
leadingIcon = { leadingIcon = {
Icon(painterResource(R.drawable.link_off_24px), null) Icon(painterResource(R.drawable.share_24px), null)
}, },
onClick = { 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 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, selected = selectedStrategy == LinkedFileConflictStrategy.KeepFile,
onSelect = { selectedStrategy = LinkedFileConflictStrategy.KeepFile }, onSelect = { selectedStrategy = LinkedFileConflictStrategy.KeepFile },
) )
Column ( Column(
modifier = Modifier.padding(top = 8.dp), modifier = Modifier.padding(top = 8.dp),
){ ) {
OutlinedButton ( OutlinedButton(
onClick = { onResolve(LinkedFileConflictStrategy.Unlink) }, onClick = { onResolve(LinkedFileConflictStrategy.Unlink) },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
colors = ButtonDefaults.outlinedButtonColors( colors = ButtonDefaults.outlinedButtonColors(

View File

@@ -10,10 +10,12 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuGroup
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.DropdownMenuPopup
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.SplitButtonDefaults import androidx.compose.material3.SplitButtonDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -40,7 +42,7 @@ import de.mm20.launcher2.ui.component.preferences.TextPreference
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable @Serializable
data object ExportThemeSettingsRoute: NavKey data object ExportThemeSettingsRoute : NavKey
@Composable @Composable
fun ExportThemeSettingsScreen() { fun ExportThemeSettingsScreen() {
@@ -188,22 +190,27 @@ fun ExportThemeSettingsScreen() {
contentDescription = null contentDescription = null
) )
DropdownMenu( DropdownMenuPopup(
expanded = showDropdown, expanded = showDropdown,
onDismissRequest = { showDropdown = false }) { onDismissRequest = { showDropdown = false }) {
DropdownMenuItem( DropdownMenuGroup(
text = { Text(stringResource(R.string.save_as_file)) }, shapes = MenuDefaults.groupShapes()
onClick = { ) {
fileChooserLauncher.launch("${viewModel.themeName}.kvtheme") DropdownMenuItem(
showDropdown = false shape = MenuDefaults.standaloneItemShape,
}, text = { Text(stringResource(R.string.save_as_file)) },
leadingIcon = { onClick = {
Icon( fileChooserLauncher.launch("${viewModel.themeName}.kvtheme")
painterResource(R.drawable.save_24px), showDropdown = false
contentDescription = null },
) leadingIcon = {
} Icon(
) painterResource(R.drawable.save_24px),
contentDescription = null
)
}
)
}
} }
} }
} }

View File

@@ -11,11 +11,13 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuGroup
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.DropdownMenuPopup
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -45,7 +47,7 @@ import de.mm20.launcher2.ui.theme.colorscheme.lightColorSchemeOf
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable @Serializable
data object ColorSchemesSettingsRoute: NavKey data object ColorSchemesSettingsRoute : NavKey
@Composable @Composable
fun ColorSchemesSettingsScreen() { fun ColorSchemesSettingsScreen() {
@@ -85,20 +87,28 @@ fun ColorSchemesSettingsScreen() {
onClick = { showMenu = true }) { onClick = { showMenu = true }) {
Icon(painterResource(R.drawable.more_vert_24px), null) Icon(painterResource(R.drawable.more_vert_24px), null)
} }
DropdownMenu( DropdownMenuPopup(
expanded = showMenu, expanded = showMenu,
onDismissRequest = { showMenu = false } onDismissRequest = { showMenu = false }
) { ) {
DropdownMenuItem( DropdownMenuGroup(
leadingIcon = { shapes = MenuDefaults.groupShapes(),
Icon(painterResource(R.drawable.content_copy_24px), null) ) {
}, DropdownMenuItem(
text = { Text(stringResource(R.string.duplicate)) }, shape = MenuDefaults.standaloneItemShape,
onClick = { leadingIcon = {
viewModel.duplicate(theme) Icon(
showMenu = false 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 }) { onClick = { showMenu = true }) {
Icon(painterResource(R.drawable.more_vert_24px), null) Icon(painterResource(R.drawable.more_vert_24px), null)
} }
DropdownMenu( DropdownMenuPopup(
expanded = showMenu, expanded = showMenu,
onDismissRequest = { showMenu = false } onDismissRequest = { showMenu = false }
) { ) {
DropdownMenuItem( DropdownMenuGroup(
leadingIcon = { shapes = MenuDefaults.groupShapes(),
Icon(painterResource(R.drawable.edit_24px), null) ) {
}, DropdownMenuItem(
text = { Text(stringResource(R.string.edit)) }, shape = MenuDefaults.leadingItemShape,
onClick = { leadingIcon = {
backStack.add(ColorSchemeSettingsRoute(id = theme.id)) Icon(
showMenu = false painterResource(R.drawable.edit_24px),
} null
) )
DropdownMenuItem( },
leadingIcon = { text = { Text(stringResource(R.string.edit)) },
Icon(painterResource(R.drawable.content_copy_24px), null) onClick = {
}, backStack.add(ColorSchemeSettingsRoute(id = theme.id))
text = { Text(stringResource(R.string.duplicate)) }, showMenu = false
onClick = { }
viewModel.duplicate(theme) )
showMenu = false DropdownMenuItem(
} shape = MenuDefaults.middleItemShape,
) leadingIcon = {
DropdownMenuItem( Icon(
leadingIcon = { painterResource(R.drawable.content_copy_24px),
Icon(painterResource(R.drawable.delete_24px), null) null
}, )
text = { Text(stringResource(R.string.menu_delete)) }, },
onClick = { text = { Text(stringResource(R.string.duplicate)) },
deleteColors = theme onClick = {
showMenu = false 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
}
)
}
} }
} }
}, },

View File

@@ -10,9 +10,12 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuGroup
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.DropdownMenuPopup
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
@@ -209,95 +212,96 @@ private fun VisibilityDropdown(
value: VisibilityLevel?, value: VisibilityLevel?,
onValueChanged: (VisibilityLevel) -> Unit, onValueChanged: (VisibilityLevel) -> Unit,
) { ) {
DropdownMenu(expanded = expanded, onDismissRequest = onDismissRequest) { DropdownMenuPopup(
Text( expanded = expanded,
text = stringResource(R.string.customize_item_visibility), onDismissRequest = onDismissRequest,
color = MaterialTheme.colorScheme.secondary, ) {
style = MaterialTheme.typography.labelMedium, DropdownMenuGroup(
modifier = Modifier.padding( shapes = MenuDefaults.groupShapes(),
start = 48.dp, ) {
top = 12.dp, MenuDefaults.Label {
bottom = 8.dp,
end = 12.dp,
)
)
DropdownMenuItem(
leadingIcon = {
Icon(
painterResource(R.drawable.visibility_24px_filled),
contentDescription = null
)
},
text = {
Text( Text(
when (item) { text = stringResource(R.string.customize_item_visibility),
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.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( DropdownMenuItem(
selected = value == VisibilityLevel.Default,
shapes = MenuDefaults.itemShape(0, count),
leadingIcon = { leadingIcon = {
Icon( Icon(
painterResource(R.drawable.visibility_24px), painterResource(R.drawable.visibility_24px_filled),
contentDescription = null
)
},
checkedLeadingIcon = {
Icon(
painterResource(R.drawable.check_24px),
contentDescription = null contentDescription = null
) )
}, },
text = { 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 = { 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( Icon(
painterResource(R.drawable.check_24px), painterResource(R.drawable.visibility_24px),
tint = MaterialTheme.colorScheme.primary,
contentDescription = null contentDescription = null
) )
} },
} checkedLeadingIcon = {
) Icon(
} painterResource(R.drawable.check_24px),
DropdownMenuItem( contentDescription = null
leadingIcon = { )
Icon( },
painterResource(R.drawable.visibility_off_24px), text = {
contentDescription = null Text(stringResource(R.string.item_visibility_search_only))
},
onClick = {
onValueChanged(VisibilityLevel.SearchOnly)
},
) )
}, }
text = { DropdownMenuItem(
Text(stringResource(R.string.item_visibility_hidden)) selected = value == VisibilityLevel.Hidden,
}, shapes = MenuDefaults.itemShape(count - 1, count),
onClick = { leadingIcon = {
onValueChanged(VisibilityLevel.Hidden)
},
trailingIcon = {
if (value == VisibilityLevel.Hidden) {
Icon( Icon(
painterResource(R.drawable.check_24px), painterResource(R.drawable.visibility_off_24px),
tint = MaterialTheme.colorScheme.primary,
contentDescription = null contentDescription = null
) )
} },
} checkedLeadingIcon = {
) Icon(
painterResource(R.drawable.check_24px),
contentDescription = null
)
},
text = {
Text(stringResource(R.string.item_visibility_hidden))
},
onClick = {
onValueChanged(VisibilityLevel.Hidden)
},
)
}
} }
} }

View File

@@ -31,14 +31,16 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuGroup
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.DropdownMenuPopup
import androidx.compose.material3.FilledIconButton import androidx.compose.material3.FilledIconButton
import androidx.compose.material3.FilledTonalIconButton import androidx.compose.material3.FilledTonalIconButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedCard import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
@@ -580,25 +582,36 @@ fun CustomizeAppSearch(viewModel: EditSearchActionSheetVM) {
) )
} }
) )
DropdownMenu( DropdownMenuPopup(
expanded = showAppDropdown, expanded = showAppDropdown,
onDismissRequest = { showAppDropdown = false }) { onDismissRequest = { showAppDropdown = false }) {
for (app in availableSearchApps) { DropdownMenuGroup(
DropdownMenuItem( shapes = MenuDefaults.groupShapes()
text = { Text(app.label) }, ) {
onClick = { for ((i, app) in availableSearchApps.withIndex()) {
viewModel.setComponentName(app.componentName) DropdownMenuItem(
showAppDropdown = false shape =
}, if (availableSearchApps.size == 1) MenuDefaults.standaloneItemShape
leadingIcon = { else when (i) {
SearchActionIcon( 0 -> MenuDefaults.leadingItemShape
size = 24.dp, availableSearchApps.lastIndex -> MenuDefaults.trailingItemShape
componentName = app.componentName, else -> MenuDefaults.middleItemShape
icon = SearchActionIcon.Custom, },
color = 1, 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) }, onClick = { viewModel.removeExtra(key) },
modifier = Modifier.padding(horizontal = 8.dp) 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) { when (newType) {
"bool" -> { "bool" -> {
Icon(painterResource(R.drawable.toggle_on_24px), contentDescription = null) Icon(
painterResource(R.drawable.toggle_on_24px),
contentDescription = null
)
} }
"string" -> { "string" -> {
@@ -1161,76 +1180,91 @@ private fun IntentExtrasEditor(viewModel: EditSearchActionSheetVM) {
Text("1.00", style = MaterialTheme.typography.labelSmall) Text("1.00", style = MaterialTheme.typography.labelSmall)
} }
} }
DropdownMenu( DropdownMenuPopup(
expanded = showTypeDropdown, expanded = showTypeDropdown,
onDismissRequest = { showTypeDropdown = false }) { onDismissRequest = { showTypeDropdown = false }) {
DropdownMenuItem( DropdownMenuGroup(
leadingIcon = { shapes = MenuDefaults.groupShapes()
Text( ) {
"ABC", DropdownMenuItem(
style = MaterialTheme.typography.labelSmall shape = MenuDefaults.leadingItemShape,
) leadingIcon = {
}, Text(
text = { Text("String") }, "ABC",
onClick = { style = MaterialTheme.typography.labelSmall
newType = "string" )
showTypeDropdown = false },
}) text = { Text("String") },
DropdownMenuItem( onClick = {
leadingIcon = { newType = "string"
Text( showTypeDropdown = false
"123", })
style = MaterialTheme.typography.labelSmall DropdownMenuItem(
) shape = MenuDefaults.middleItemShape,
}, leadingIcon = {
text = { Text("Integer") }, Text(
onClick = { "123",
newType = "int" style = MaterialTheme.typography.labelSmall
showTypeDropdown = false )
}) },
DropdownMenuItem( text = { Text("Integer") },
leadingIcon = { onClick = {
Text( newType = "int"
"1234", showTypeDropdown = false
style = MaterialTheme.typography.labelSmall })
) DropdownMenuItem(
}, shape = MenuDefaults.middleItemShape,
text = { Text("Long") }, leadingIcon = {
onClick = { Text(
newType = "long" "1234",
showTypeDropdown = false style = MaterialTheme.typography.labelSmall
}) )
DropdownMenuItem( },
leadingIcon = { text = { Text("Long") },
Text( onClick = {
"1.0", newType = "long"
style = MaterialTheme.typography.labelSmall showTypeDropdown = false
) })
}, DropdownMenuItem(
text = { Text("Float") }, shape = MenuDefaults.middleItemShape,
onClick = { leadingIcon = {
newType = "float" Text(
showTypeDropdown = false "1.0",
}) style = MaterialTheme.typography.labelSmall
DropdownMenuItem( )
leadingIcon = { },
Text( text = { Text("Float") },
"1.00", onClick = {
style = MaterialTheme.typography.labelSmall newType = "float"
) showTypeDropdown = false
}, })
text = { Text("Double") }, DropdownMenuItem(
onClick = { shape = MenuDefaults.middleItemShape,
newType = "double" leadingIcon = {
showTypeDropdown = false Text(
}) "1.00",
DropdownMenuItem( style = MaterialTheme.typography.labelSmall
leadingIcon = { Icon(painterResource(R.drawable.toggle_on_24px), null) }, )
text = { Text("Boolean") }, },
onClick = { text = { Text("Double") },
newType = "bool" onClick = {
showTypeDropdown = false 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( OutlinedTextField(

View File

@@ -16,12 +16,13 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuGroup
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.DropdownMenuPopup
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
@@ -57,7 +58,7 @@ import de.mm20.launcher2.ui.locals.LocalBackStack
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable @Serializable
data object SearchActionsSettingsRoute: NavKey data object SearchActionsSettingsRoute : NavKey
@Composable @Composable
fun SearchActionsSettingsScreen() { fun SearchActionsSettingsScreen() {
@@ -102,14 +103,18 @@ fun SearchActionsSettingsScreen() {
backStack.removeLastOrNull() backStack.removeLastOrNull()
} }
}) { }) {
Icon(painterResource(R.drawable.arrow_back_24px), contentDescription = "Back") Icon(
painterResource(R.drawable.arrow_back_24px),
contentDescription = "Back"
)
} }
}, },
actions = { actions = {
IconButton(onClick = { viewModel.createAction() }) { IconButton(onClick = { viewModel.createAction() }) {
Icon( Icon(
painterResource(R.drawable.add_24px), painterResource(R.drawable.add_24px),
contentDescription = null) contentDescription = null
)
} }
IconButton(onClick = { IconButton(onClick = {
CustomTabsIntent.Builder() CustomTabsIntent.Builder()
@@ -193,41 +198,50 @@ fun SearchActionsSettingsScreen() {
showDropdown = true showDropdown = true
} }
) { ) {
Icon(painterResource(R.drawable.more_vert_24px), stringResource(R.string.edit)) Icon(
DropdownMenu( painterResource(R.drawable.more_vert_24px),
stringResource(R.string.edit)
)
DropdownMenuPopup(
expanded = showDropdown, expanded = showDropdown,
onDismissRequest = { showDropdown = false } onDismissRequest = { showDropdown = false }
) { ) {
DropdownMenuItem( DropdownMenuGroup(
leadingIcon = { shapes = MenuDefaults.groupShapes()
Icon( ) {
painterResource(R.drawable.edit_24px), DropdownMenuItem(
contentDescription = null shape = MenuDefaults.leadingItemShape,
) leadingIcon = {
}, Icon(
text = { painterResource(R.drawable.edit_24px),
Text(stringResource(R.string.edit)) contentDescription = null
}, )
onClick = { },
viewModel.editAction(item) text = {
showDropdown = false Text(stringResource(R.string.edit))
} },
) onClick = {
DropdownMenuItem( viewModel.editAction(item)
leadingIcon = { showDropdown = false
Icon( }
painterResource(R.drawable.delete_24px), )
contentDescription = null DropdownMenuItem(
) shape = MenuDefaults.trailingItemShape,
}, leadingIcon = {
text = { Icon(
Text(stringResource(R.string.menu_delete)) painterResource(R.drawable.delete_24px),
}, contentDescription = null
onClick = { )
viewModel.removeAction(item) },
showDropdown = false text = {
} Text(stringResource(R.string.menu_delete))
) },
onClick = {
viewModel.removeAction(item)
showDropdown = false
}
)
}
} }
} }
} }

View File

@@ -9,10 +9,13 @@ import androidx.compose.foundation.shape.CutCornerShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuGroup
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.DropdownMenuPopup
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -79,20 +82,28 @@ fun ShapeSchemesSettingsScreen() {
onClick = { showMenu = true }) { onClick = { showMenu = true }) {
Icon(painterResource(R.drawable.more_vert_24px), null) Icon(painterResource(R.drawable.more_vert_24px), null)
} }
DropdownMenu( DropdownMenuPopup(
expanded = showMenu, expanded = showMenu,
onDismissRequest = { showMenu = false } onDismissRequest = { showMenu = false }
) { ) {
DropdownMenuItem( DropdownMenuGroup(
leadingIcon = { shapes = MenuDefaults.groupShapes(),
Icon(painterResource(R.drawable.content_copy_24px), null) ) {
}, DropdownMenuItem(
text = { Text(stringResource(R.string.duplicate)) }, shape = MenuDefaults.standaloneItemShape,
onClick = { leadingIcon = {
viewModel.duplicate(theme) Icon(
showMenu = false 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 }) { onClick = { showMenu = true }) {
Icon(painterResource(R.drawable.more_vert_24px), null) Icon(painterResource(R.drawable.more_vert_24px), null)
} }
DropdownMenu( DropdownMenuPopup(
expanded = showMenu, expanded = showMenu,
onDismissRequest = { showMenu = false } onDismissRequest = { showMenu = false }
) { ) {
DropdownMenuItem( DropdownMenuGroup(
leadingIcon = { shapes = MenuDefaults.groupShapes(),
Icon(painterResource(R.drawable.edit_24px), null) ) {
}, DropdownMenuItem(
text = { Text(stringResource(R.string.edit)) }, shape = MenuDefaults.leadingItemShape,
onClick = { leadingIcon = {
backStack.add(ShapeSchemeSettingsRoute(id = theme.id)) Icon(
showMenu = false painterResource(R.drawable.edit_24px),
} null
) )
DropdownMenuItem( },
leadingIcon = { text = { Text(stringResource(R.string.edit)) },
Icon(painterResource(R.drawable.content_copy_24px), null) onClick = {
}, backStack.add(ShapeSchemeSettingsRoute(id = theme.id))
text = { Text(stringResource(R.string.duplicate)) }, showMenu = false
onClick = { }
viewModel.duplicate(theme) )
showMenu = false DropdownMenuItem(
} shape = MenuDefaults.middleItemShape,
) leadingIcon = {
DropdownMenuItem( Icon(
leadingIcon = { painterResource(R.drawable.content_copy_24px),
Icon(painterResource(R.drawable.delete_24px), null) null
}, )
text = { Text(stringResource(R.string.menu_delete)) }, },
onClick = { text = { Text(stringResource(R.string.duplicate)) },
deleteShapes = theme onClick = {
showMenu = false 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
}
)
}
} }
} }
}, },

View File

@@ -1,10 +1,11 @@
package de.mm20.launcher2.ui.settings.tags 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.DropdownMenuItem
import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.DropdownMenuPopup
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
@@ -26,7 +27,7 @@ import de.mm20.launcher2.ui.launcher.sheets.EditTagSheet
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable @Serializable
data object TagsSettingsRoute: NavKey data object TagsSettingsRoute : NavKey
@Composable @Composable
fun TagsSettingsScreen() { fun TagsSettingsScreen() {
@@ -38,7 +39,10 @@ fun TagsSettingsScreen() {
title = stringResource(R.string.preference_screen_tags), title = stringResource(R.string.preference_screen_tags),
topBarActions = { topBarActions = {
IconButton(onClick = { viewModel.createTag.value = true }) { 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" helpUrl = "https://kvaesitso.mm20.de/docs/user-guide/concepts/tags"
@@ -65,25 +69,41 @@ fun TagsSettingsScreen() {
IconButton(onClick = { showMenu = true }) { IconButton(onClick = { showMenu = true }) {
Icon(painterResource(R.drawable.more_vert_24px), null) Icon(painterResource(R.drawable.more_vert_24px), null)
} }
DropdownMenu( DropdownMenuPopup(
expanded = showMenu, expanded = showMenu,
onDismissRequest = { showMenu = false }) { onDismissRequest = { showMenu = false }) {
DropdownMenuItem( DropdownMenuGroup(
text = { Text(stringResource(R.string.duplicate)) }, shapes = MenuDefaults.groupShapes()
leadingIcon = { Icon(painterResource(R.drawable.content_copy_24px), null) }, ) {
onClick = { DropdownMenuItem(
viewModel.duplicateTag(tag) shape = MenuDefaults.leadingItemShape,
showMenu = false text = { Text(stringResource(R.string.duplicate)) },
} leadingIcon = {
) Icon(
DropdownMenuItem( painterResource(R.drawable.content_copy_24px),
text = { Text(stringResource(R.string.menu_delete)) }, null
leadingIcon = { Icon(painterResource(R.drawable.delete_24px), null) }, )
onClick = { },
viewModel.deleteTag(tag) onClick = {
showMenu = false 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
}
)
}
} }
} }
) )

View File

@@ -7,11 +7,13 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuGroup
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.DropdownMenuPopup
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.material3.surfaceColorAtElevation
@@ -43,7 +45,7 @@ import de.mm20.launcher2.ui.theme.wallpaperColorsAsState
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable @Serializable
data object TransparencySchemesSettingsRoute: NavKey data object TransparencySchemesSettingsRoute : NavKey
@Composable @Composable
fun TransparencySchemesSettingsScreen() { fun TransparencySchemesSettingsScreen() {
@@ -85,20 +87,28 @@ fun TransparencySchemesSettingsScreen() {
onClick = { showMenu = true }) { onClick = { showMenu = true }) {
Icon(painterResource(R.drawable.more_vert_24px), null) Icon(painterResource(R.drawable.more_vert_24px), null)
} }
DropdownMenu( DropdownMenuPopup(
expanded = showMenu, expanded = showMenu,
onDismissRequest = { showMenu = false } onDismissRequest = { showMenu = false }
) { ) {
DropdownMenuItem( DropdownMenuGroup(
leadingIcon = { shapes = MenuDefaults.groupShapes(),
Icon(painterResource(R.drawable.content_copy_24px), null) ) {
}, DropdownMenuItem(
text = { Text(stringResource(R.string.duplicate)) }, shape = MenuDefaults.standaloneItemShape,
onClick = { leadingIcon = {
viewModel.duplicate(theme) Icon(
showMenu = false 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 }) { onClick = { showMenu = true }) {
Icon(painterResource(R.drawable.more_vert_24px), null) Icon(painterResource(R.drawable.more_vert_24px), null)
} }
DropdownMenu( DropdownMenuPopup(
expanded = showMenu, expanded = showMenu,
onDismissRequest = { showMenu = false } onDismissRequest = { showMenu = false }
) { ) {
DropdownMenuItem( DropdownMenuGroup(
leadingIcon = { shapes = MenuDefaults.groupShapes(),
Icon(painterResource(R.drawable.edit_24px), null) ) {
}, DropdownMenuItem(
text = { Text(stringResource(R.string.edit)) }, shape = MenuDefaults.leadingItemShape,
onClick = { leadingIcon = {
backStack.add(TransparencySchemeSettingsRoute(theme.id)) Icon(
showMenu = false painterResource(R.drawable.edit_24px),
} null
) )
DropdownMenuItem( },
leadingIcon = { text = { Text(stringResource(R.string.edit)) },
Icon(painterResource(R.drawable.content_copy_24px), null) onClick = {
}, backStack.add(
text = { Text(stringResource(R.string.duplicate)) }, TransparencySchemeSettingsRoute(
onClick = { theme.id
viewModel.duplicate(theme) )
showMenu = false )
} showMenu = false
) }
DropdownMenuItem( )
leadingIcon = { DropdownMenuItem(
Icon(painterResource(R.drawable.delete_24px), null) shape = MenuDefaults.middleItemShape,
}, leadingIcon = {
text = { Text(stringResource(R.string.menu_delete)) }, Icon(
onClick = { painterResource(R.drawable.content_copy_24px),
deleteTransparencies = theme null
showMenu = false )
} },
) 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
}
)
}
} }
} }
}, },

View File

@@ -6,10 +6,13 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuGroup
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.DropdownMenuPopup
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -92,20 +95,28 @@ fun TypographiesSettingsScreen() {
onClick = { showMenu = true }) { onClick = { showMenu = true }) {
Icon(painterResource(R.drawable.more_vert_24px), null) Icon(painterResource(R.drawable.more_vert_24px), null)
} }
DropdownMenu( DropdownMenuPopup(
expanded = showMenu, expanded = showMenu,
onDismissRequest = { showMenu = false } onDismissRequest = { showMenu = false }
) { ) {
DropdownMenuItem( DropdownMenuGroup(
leadingIcon = { shapes = MenuDefaults.groupShapes(),
Icon(painterResource(R.drawable.content_copy_24px), null) ) {
}, DropdownMenuItem(
text = { Text(stringResource(R.string.duplicate)) }, shape = MenuDefaults.standaloneItemShape,
onClick = { leadingIcon = {
viewModel.duplicate(theme) Icon(
showMenu = false 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 }) { onClick = { showMenu = true }) {
Icon(painterResource(R.drawable.more_vert_24px), null) Icon(painterResource(R.drawable.more_vert_24px), null)
} }
DropdownMenu( DropdownMenuPopup(
expanded = showMenu, expanded = showMenu,
onDismissRequest = { showMenu = false } onDismissRequest = { showMenu = false }
) { ) {
DropdownMenuItem( DropdownMenuGroup(
leadingIcon = { shapes = MenuDefaults.groupShapes(),
Icon(painterResource(R.drawable.edit_24px), null) ) {
}, DropdownMenuItem(
text = { Text(stringResource(R.string.edit)) }, shape = MenuDefaults.leadingItemShape,
onClick = { leadingIcon = {
backStack.add(TypographySettingsRoute(theme.id)) Icon(
showMenu = false painterResource(R.drawable.edit_24px),
} null
) )
DropdownMenuItem( },
leadingIcon = { text = { Text(stringResource(R.string.edit)) },
Icon(painterResource(R.drawable.content_copy_24px), null) onClick = {
}, backStack.add(TypographySettingsRoute(theme.id))
text = { Text(stringResource(R.string.duplicate)) }, showMenu = false
onClick = { }
viewModel.duplicate(theme) )
showMenu = false DropdownMenuItem(
} shape = MenuDefaults.middleItemShape,
) leadingIcon = {
DropdownMenuItem( Icon(
leadingIcon = { painterResource(R.drawable.content_copy_24px),
Icon(painterResource(R.drawable.delete_24px), null) null
}, )
text = { Text(stringResource(R.string.menu_delete)) }, },
onClick = { text = { Text(stringResource(R.string.duplicate)) },
deleteTypography = theme onClick = {
showMenu = false 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
}
)
}
} }
} }
}, },

View File

@@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal"
android:autoMirrored="true">
<path
android:fillColor="@android:color/white"
android:pathData="M420,652Q412,652 406,646.5Q400,641 400,632L400,328Q400,319 406,313.5Q412,308 420,308Q422,308 434,314L579,459Q584,464 586,469Q588,474 588,480Q588,486 586,491Q584,496 579,501L434,646Q431,649 427.5,650.5Q424,652 420,652Z"/>
</vector>