From c192b3c1fcfd455570deeaaf1dee23bad93e5d1b Mon Sep 17 00:00:00 2001 From: MM20 <15646950+MM2-0@users.noreply.github.com> Date: Sat, 26 Aug 2023 23:55:13 +0200 Subject: [PATCH] Replace tag icon with emoji if tag name starts with an emoji Close #292 --- .../de/mm20/launcher2/ui/common/TagChip.kt | 28 ++++++++++++---- .../ui/component/OutlinedTagsInputField.kt | 32 ++++++++++++++----- .../java/de/mm20/launcher2/ui/ktx/String.kt | 17 ++++++++++ .../ui/launcher/sheets/EditFavoritesSheet.kt | 19 +++++++++-- .../ui/settings/tags/TagsSettingsScreen.kt | 19 ++++++++--- 5 files changed, 94 insertions(+), 21 deletions(-) create mode 100644 app/ui/src/main/java/de/mm20/launcher2/ui/ktx/String.kt diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/common/TagChip.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/common/TagChip.kt index e735720b..cc02b6bc 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/common/TagChip.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/common/TagChip.kt @@ -2,6 +2,7 @@ package de.mm20.launcher2.ui.common import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Close 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.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign import de.mm20.launcher2.search.data.Tag +import de.mm20.launcher2.ui.ktx.splitLeadingEmoji @Composable fun TagChip( @@ -26,20 +30,32 @@ fun TagChip( colors: SelectableChipColors = FilterChipDefaults.filterChipColors(), elevation: SelectableChipElevation? = FilterChipDefaults.filterChipElevation(), ) { + val (emoji, tagName) = remember(tag.tag) { + tag.tag.splitLeadingEmoji() + } + FilterChip( modifier = modifier, selected = selected, onClick = onClick, leadingIcon = { - Icon( - modifier = Modifier.size(FilterChipDefaults.IconSize), - imageVector = Icons.Rounded.Tag, - contentDescription = null - ) + if (emoji != null && tagName != null) { + Text( + emoji, + 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 = { Text( - tag.label + tagName ?: emoji ?: "", ) }, colors = colors, diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/component/OutlinedTagsInputField.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/component/OutlinedTagsInputField.kt index b9909970..5d8224a3 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/component/OutlinedTagsInputField.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/component/OutlinedTagsInputField.kt @@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.BasicTextField 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.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.FilterChipDefaults import androidx.compose.material3.Icon import androidx.compose.material3.InputChip import androidx.compose.material3.InputChipDefaults import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.Text import androidx.compose.material3.TextFieldDefaults 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.text.TextStyle import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.window.PopupProperties +import de.mm20.launcher2.ui.ktx.splitLeadingEmoji import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.launch @@ -121,7 +126,7 @@ fun OutlinedTagsInputField( } }), decorationBox = { innerTextField -> - TextFieldDefaults.OutlinedTextFieldDecorationBox( + OutlinedTextFieldDefaults.DecorationBox( contentPadding = PaddingValues(0.dp), value = value, innerTextField = { @@ -133,19 +138,30 @@ fun OutlinedTagsInputField( verticalAlignment = Alignment.CenterVertically ) { for ((i, tag) in tags.withIndex()) { + val (emoji, tagName) = remember(tag) { + tag.splitLeadingEmoji() + } InputChip( selected = i == tags.lastIndex && lastTagFocused, modifier = Modifier.padding(end = 12.dp), onClick = { }, leadingIcon = { - Icon( - modifier = Modifier - .size(InputChipDefaults.IconSize), - imageVector = Icons.Rounded.Tag, - contentDescription = null - ) + if (emoji != null && tagName != null) { + Text( + emoji, + modifier = Modifier.width(FilterChipDefaults.IconSize), + 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 = { Icon( modifier = Modifier diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/ktx/String.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/ktx/String.kt new file mode 100644 index 00000000..49e40ec3 --- /dev/null +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/ktx/String.kt @@ -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 { + 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() +} \ No newline at end of file diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/EditFavoritesSheet.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/EditFavoritesSheet.kt index 158e178a..bcee46f0 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/EditFavoritesSheet.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/EditFavoritesSheet.kt @@ -38,6 +38,7 @@ import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.FilledTonalIconButton import androidx.compose.material3.FilledTonalIconToggleButton import androidx.compose.material3.FilterChipDefaults +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.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.rememberLazyDragAndDropGridState 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.locals.LocalGridSettings import de.mm20.launcher2.ui.settings.tags.EditTagSheet @@ -493,18 +495,29 @@ fun ReorderFavoritesGrid(viewModel: EditFavoritesSheetVM, paddingValues: Padding expanded = showAddMenu, onDismissRequest = { showAddMenu = false }) { for (tag in availableTags) { + val (emoji, tagName) = remember(tag.tag) { + tag.tag.splitLeadingEmoji() + } DropdownMenuItem( 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 = { viewModel.pinTag(tag) showAddMenu = false }) } if (availableTags.isNotEmpty()) { - Divider() + HorizontalDivider() } DropdownMenuItem( leadingIcon = { diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/tags/TagsSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/tags/TagsSettingsScreen.kt index 45aa8a08..fd0b9276 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/tags/TagsSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/tags/TagsSettingsScreen.kt @@ -13,7 +13,6 @@ import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue 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.PreferenceCategory import de.mm20.launcher2.ui.component.preferences.PreferenceScreen +import de.mm20.launcher2.ui.ktx.splitLeadingEmoji @Composable fun TagsSettingsScreen() { @@ -45,9 +45,20 @@ fun TagsSettingsScreen() { PreferenceCategory { for (tag in tags) { var showMenu by remember { mutableStateOf(false) } + + val (emoji, tagName) = remember(tag) { + tag.splitLeadingEmoji() + } + Preference( - icon = Icons.Rounded.Tag, - title = tag, + icon = { + if (emoji != null) { + Text(emoji) + } else { + Icon(Icons.Rounded.Tag, null) + } + }, + title = { Text(tagName ?: "") }, onClick = { viewModel.editTag.value = tag }, @@ -89,7 +100,7 @@ fun TagsSettingsScreen() { viewModel.createTag.value = false } ) - } else if(viewModel.createTag.value) { + } else if (viewModel.createTag.value) { EditTagSheet( tag = null, onDismiss = {