Replace tag icon with emoji if tag name starts with an emoji

Close #292
This commit is contained in:
MM20 2023-08-26 23:55:13 +02:00
parent 6946175c29
commit c192b3c1fc
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
5 changed files with 94 additions and 21 deletions

View File

@ -2,6 +2,7 @@ package de.mm20.launcher2.ui.common
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Close import androidx.compose.material.icons.rounded.Close
import androidx.compose.material.icons.rounded.Tag import androidx.compose.material.icons.rounded.Tag
@ -12,8 +13,11 @@ import androidx.compose.material3.SelectableChipColors
import androidx.compose.material3.SelectableChipElevation import androidx.compose.material3.SelectableChipElevation
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import de.mm20.launcher2.search.data.Tag import de.mm20.launcher2.search.data.Tag
import de.mm20.launcher2.ui.ktx.splitLeadingEmoji
@Composable @Composable
fun TagChip( fun TagChip(
@ -26,20 +30,32 @@ fun TagChip(
colors: SelectableChipColors = FilterChipDefaults.filterChipColors(), colors: SelectableChipColors = FilterChipDefaults.filterChipColors(),
elevation: SelectableChipElevation? = FilterChipDefaults.filterChipElevation(), elevation: SelectableChipElevation? = FilterChipDefaults.filterChipElevation(),
) { ) {
val (emoji, tagName) = remember(tag.tag) {
tag.tag.splitLeadingEmoji()
}
FilterChip( FilterChip(
modifier = modifier, modifier = modifier,
selected = selected, selected = selected,
onClick = onClick, onClick = onClick,
leadingIcon = { leadingIcon = {
Icon( if (emoji != null && tagName != null) {
modifier = Modifier.size(FilterChipDefaults.IconSize), Text(
imageVector = Icons.Rounded.Tag, emoji,
contentDescription = null modifier = Modifier.width(FilterChipDefaults.IconSize),
) textAlign = TextAlign.Center,
)
} else if (tagName != null) {
Icon(
modifier = Modifier.size(FilterChipDefaults.IconSize),
imageVector = Icons.Rounded.Tag,
contentDescription = null
)
}
}, },
label = { label = {
Text( Text(
tag.label tagName ?: emoji ?: "",
) )
}, },
colors = colors, colors = colors,

View File

@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
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.foundation.layout.width
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
@ -18,12 +19,14 @@ import androidx.compose.material.icons.rounded.Clear
import androidx.compose.material.icons.rounded.Tag import androidx.compose.material.icons.rounded.Tag
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.FilterChipDefaults
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.OutlinedTextFieldDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -43,8 +46,10 @@ import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.onKeyEvent import androidx.compose.ui.input.key.onKeyEvent
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.PopupProperties import androidx.compose.ui.window.PopupProperties
import de.mm20.launcher2.ui.ktx.splitLeadingEmoji
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -121,7 +126,7 @@ fun OutlinedTagsInputField(
} }
}), }),
decorationBox = { innerTextField -> decorationBox = { innerTextField ->
TextFieldDefaults.OutlinedTextFieldDecorationBox( OutlinedTextFieldDefaults.DecorationBox(
contentPadding = PaddingValues(0.dp), contentPadding = PaddingValues(0.dp),
value = value, value = value,
innerTextField = { innerTextField = {
@ -133,19 +138,30 @@ fun OutlinedTagsInputField(
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
for ((i, tag) in tags.withIndex()) { for ((i, tag) in tags.withIndex()) {
val (emoji, tagName) = remember(tag) {
tag.splitLeadingEmoji()
}
InputChip( InputChip(
selected = i == tags.lastIndex && lastTagFocused, selected = i == tags.lastIndex && lastTagFocused,
modifier = Modifier.padding(end = 12.dp), modifier = Modifier.padding(end = 12.dp),
onClick = { }, onClick = { },
leadingIcon = { leadingIcon = {
Icon( if (emoji != null && tagName != null) {
modifier = Modifier Text(
.size(InputChipDefaults.IconSize), emoji,
imageVector = Icons.Rounded.Tag, modifier = Modifier.width(FilterChipDefaults.IconSize),
contentDescription = null textAlign = TextAlign.Center,
) )
} else if (tagName != null) {
Icon(
modifier = Modifier
.size(InputChipDefaults.IconSize),
imageVector = Icons.Rounded.Tag,
contentDescription = null
)
}
}, },
label = { Text(tag) }, label = { Text(tagName ?: emoji ?: "") },
trailingIcon = { trailingIcon = {
Icon( Icon(
modifier = Modifier modifier = Modifier

View File

@ -0,0 +1,17 @@
package de.mm20.launcher2.ui.ktx
import com.sigpwned.emoji4j.core.Grapheme
import com.sigpwned.emoji4j.core.GraphemeMatcher
fun String.splitLeadingEmoji(): Pair<String?, String?> {
val matcher = GraphemeMatcher(this)
if (!matcher.find()) return null to this.trim()
val grapheme = matcher.grapheme()
if (grapheme?.type == Grapheme.Type.EMOJI && matcher.start() == 0) {
val end = matcher.end()
val emoji = this.substring(0, end)
val tagName = this.substring(end)
return emoji to tagName.takeIf { it.isNotBlank() }
}
return null to this.trim()
}

View File

@ -38,6 +38,7 @@ import androidx.compose.material3.DropdownMenuItem
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.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.OutlinedButton import androidx.compose.material3.OutlinedButton
@ -86,6 +87,7 @@ import de.mm20.launcher2.ui.component.dragndrop.LazyDragAndDropRow
import de.mm20.launcher2.ui.component.dragndrop.LazyVerticalDragAndDropGrid import de.mm20.launcher2.ui.component.dragndrop.LazyVerticalDragAndDropGrid
import de.mm20.launcher2.ui.component.dragndrop.rememberLazyDragAndDropGridState import de.mm20.launcher2.ui.component.dragndrop.rememberLazyDragAndDropGridState
import de.mm20.launcher2.ui.component.dragndrop.rememberLazyDragAndDropListState import de.mm20.launcher2.ui.component.dragndrop.rememberLazyDragAndDropListState
import de.mm20.launcher2.ui.ktx.splitLeadingEmoji
import de.mm20.launcher2.ui.ktx.toPixels import de.mm20.launcher2.ui.ktx.toPixels
import de.mm20.launcher2.ui.locals.LocalGridSettings import de.mm20.launcher2.ui.locals.LocalGridSettings
import de.mm20.launcher2.ui.settings.tags.EditTagSheet import de.mm20.launcher2.ui.settings.tags.EditTagSheet
@ -493,18 +495,29 @@ fun ReorderFavoritesGrid(viewModel: EditFavoritesSheetVM, paddingValues: Padding
expanded = showAddMenu, expanded = showAddMenu,
onDismissRequest = { showAddMenu = false }) { onDismissRequest = { showAddMenu = false }) {
for (tag in availableTags) { for (tag in availableTags) {
val (emoji, tagName) = remember(tag.tag) {
tag.tag.splitLeadingEmoji()
}
DropdownMenuItem( DropdownMenuItem(
leadingIcon = { leadingIcon = {
Icon(Icons.Rounded.Tag, null) if (emoji != null) {
Text(
emoji,
modifier = Modifier.width(FilterChipDefaults.IconSize),
textAlign = TextAlign.Center,
)
} else {
Icon(Icons.Rounded.Tag, null)
}
}, },
text = { Text(tag.label) }, text = { Text(tagName ?: "") },
onClick = { onClick = {
viewModel.pinTag(tag) viewModel.pinTag(tag)
showAddMenu = false showAddMenu = false
}) })
} }
if (availableTags.isNotEmpty()) { if (availableTags.isNotEmpty()) {
Divider() HorizontalDivider()
} }
DropdownMenuItem( DropdownMenuItem(
leadingIcon = { leadingIcon = {

View File

@ -13,7 +13,6 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@ -25,6 +24,7 @@ import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.preferences.Preference import de.mm20.launcher2.ui.component.preferences.Preference
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
import de.mm20.launcher2.ui.ktx.splitLeadingEmoji
@Composable @Composable
fun TagsSettingsScreen() { fun TagsSettingsScreen() {
@ -45,9 +45,20 @@ fun TagsSettingsScreen() {
PreferenceCategory { PreferenceCategory {
for (tag in tags) { for (tag in tags) {
var showMenu by remember { mutableStateOf(false) } var showMenu by remember { mutableStateOf(false) }
val (emoji, tagName) = remember(tag) {
tag.splitLeadingEmoji()
}
Preference( Preference(
icon = Icons.Rounded.Tag, icon = {
title = tag, if (emoji != null) {
Text(emoji)
} else {
Icon(Icons.Rounded.Tag, null)
}
},
title = { Text(tagName ?: "") },
onClick = { onClick = {
viewModel.editTag.value = tag viewModel.editTag.value = tag
}, },
@ -89,7 +100,7 @@ fun TagsSettingsScreen() {
viewModel.createTag.value = false viewModel.createTag.value = false
} }
) )
} else if(viewModel.createTag.value) { } else if (viewModel.createTag.value) {
EditTagSheet( EditTagSheet(
tag = null, tag = null,
onDismiss = { onDismiss = {