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.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,

View File

@ -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

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.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 = {

View File

@ -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 = {