Replace tag icon with emoji if tag name starts with an emoji
Close #292
This commit is contained in:
parent
6946175c29
commit
c192b3c1fc
@ -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,
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
17
app/ui/src/main/java/de/mm20/launcher2/ui/ktx/String.kt
Normal file
17
app/ui/src/main/java/de/mm20/launcher2/ui/ktx/String.kt
Normal 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()
|
||||||
|
}
|
||||||
@ -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 = {
|
||||||
|
|||||||
@ -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 = {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user