allow renaming user themes

This commit is contained in:
Helium314 2025-02-11 19:20:15 +01:00
parent bd7e92bcf8
commit 1484d7021e
5 changed files with 77 additions and 5 deletions

View file

@ -12,6 +12,7 @@ import android.os.Build
import android.util.TypedValue import android.util.TypedValue
import android.view.ContextThemeWrapper import android.view.ContextThemeWrapper
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.edit
import helium314.keyboard.latin.R import helium314.keyboard.latin.R
import helium314.keyboard.latin.common.AllColors import helium314.keyboard.latin.common.AllColors
import helium314.keyboard.latin.common.ColorType import helium314.keyboard.latin.common.ColorType
@ -373,6 +374,41 @@ private constructor(val themeId: Int, @JvmField val mStyleId: Int) {
return colorMap return colorMap
} }
// returns false if not renamed due to invalid name or collision
fun renameUserColors(from: String, to: String, prefs: SharedPreferences): Boolean {
if (to.isBlank()) return false // don't want that
if (to == from) return true // nothing to do
val existingNames = prefs.all.keys.mapNotNull {
when {
it.startsWith(Settings.PREF_USER_COLORS_PREFIX) -> it.substringAfter(Settings.PREF_USER_COLORS_PREFIX)
it.startsWith(Settings.PREF_USER_ALL_COLORS_PREFIX) -> it.substringAfter(Settings.PREF_USER_ALL_COLORS_PREFIX)
it.startsWith(Settings.PREF_USER_MORE_COLORS_PREFIX) -> it.substringAfter(Settings.PREF_USER_MORE_COLORS_PREFIX)
else -> null
}
}.toSortedSet()
if (to in existingNames) return false
// all good, now rename
prefs.edit {
if (prefs.contains(Settings.PREF_USER_COLORS_PREFIX + from)) {
putString(Settings.PREF_USER_COLORS_PREFIX + to, prefs.getString(Settings.PREF_USER_COLORS_PREFIX + from, ""))
remove(Settings.PREF_USER_COLORS_PREFIX + from)
}
if (prefs.contains(Settings.PREF_USER_ALL_COLORS_PREFIX + from)) {
putString(Settings.PREF_USER_ALL_COLORS_PREFIX + to, prefs.getString(Settings.PREF_USER_ALL_COLORS_PREFIX + from, ""))
remove(Settings.PREF_USER_ALL_COLORS_PREFIX + from)
}
if (prefs.contains(Settings.PREF_USER_MORE_COLORS_PREFIX + from)) {
putInt(Settings.PREF_USER_MORE_COLORS_PREFIX + to, prefs.getInt(Settings.PREF_USER_MORE_COLORS_PREFIX + from, 0))
remove(Settings.PREF_USER_MORE_COLORS_PREFIX + from)
}
if (prefs.getString(Settings.PREF_THEME_COLORS, Defaults.PREF_THEME_COLORS) == from)
putString(Settings.PREF_THEME_COLORS, to)
if (prefs.getString(Settings.PREF_THEME_COLORS_NIGHT, Defaults.PREF_THEME_COLORS_NIGHT) == from)
putString(Settings.PREF_THEME_COLORS_NIGHT, to)
}
return true
}
fun determineUserColor(colors: List<ColorSetting>, context: Context, colorName: String, isNight: Boolean): Int { fun determineUserColor(colors: List<ColorSetting>, context: Context, colorName: String, isNight: Boolean): Int {
val c = colors.firstOrNull { it.name == colorName } val c = colors.firstOrNull { it.name == colorName }
val color = c?.color val color = c?.color

View file

@ -56,7 +56,7 @@ fun SearchSettingsScreen(
) { ) {
SearchScreen( SearchScreen(
onClickBack = onClickBack, onClickBack = onClickBack,
title = title, title = { Text(title) },
content = { content = {
if (content != null) content() if (content != null) content()
else { else {
@ -101,7 +101,7 @@ fun SearchSettingsScreen(
@Composable @Composable
fun <T: Any> SearchScreen( fun <T: Any> SearchScreen(
onClickBack: () -> Unit, onClickBack: () -> Unit,
title: String, title: @Composable () -> Unit,
filteredItems: (String) -> List<T>, filteredItems: (String) -> List<T>,
itemContent: @Composable (T) -> Unit, itemContent: @Composable (T) -> Unit,
content: @Composable (ColumnScope.() -> Unit)? = null, content: @Composable (ColumnScope.() -> Unit)? = null,
@ -123,7 +123,7 @@ fun <T: Any> SearchScreen(
) { ) {
Column { Column {
TopAppBar( TopAppBar(
title = { Text(title) }, title = title,
windowInsets = TopAppBarDefaults.windowInsets, windowInsets = TopAppBarDefaults.windowInsets,
navigationIcon = { navigationIcon = {
IconButton(onClick = { IconButton(onClick = {

View file

@ -30,6 +30,7 @@ import com.github.skydoves.colorpicker.compose.BrightnessSlider
import com.github.skydoves.colorpicker.compose.HsvColorPicker import com.github.skydoves.colorpicker.compose.HsvColorPicker
import com.github.skydoves.colorpicker.compose.rememberColorPickerController import com.github.skydoves.colorpicker.compose.rememberColorPickerController
// todo: needs different layout in landscape (bars on the side or something like that)
@Composable @Composable
fun ColorPickerDialog( fun ColorPickerDialog(
onDismissRequest: () -> Unit, onDismissRequest: () -> Unit,

View file

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-3.0-only
package helium314.keyboard.settings.dialogs package helium314.keyboard.settings.dialogs
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
@ -56,6 +57,7 @@ fun ColorThemePickerDialog(
when { when {
it.startsWith(Settings.PREF_USER_COLORS_PREFIX) -> it.substringAfter(Settings.PREF_USER_COLORS_PREFIX) it.startsWith(Settings.PREF_USER_COLORS_PREFIX) -> it.substringAfter(Settings.PREF_USER_COLORS_PREFIX)
it.startsWith(Settings.PREF_USER_ALL_COLORS_PREFIX) -> it.substringAfter(Settings.PREF_USER_ALL_COLORS_PREFIX) it.startsWith(Settings.PREF_USER_ALL_COLORS_PREFIX) -> it.substringAfter(Settings.PREF_USER_ALL_COLORS_PREFIX)
it.startsWith(Settings.PREF_USER_MORE_COLORS_PREFIX) -> it.substringAfter(Settings.PREF_USER_MORE_COLORS_PREFIX)
else -> null else -> null
} }
}.toSortedSet() // we don't want duplicates, and we want a consistent order }.toSortedSet() // we don't want duplicates, and we want a consistent order

View file

@ -8,25 +8,31 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
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.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.Icon
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.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Switch import androidx.compose.material3.Switch
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
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
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import helium314.keyboard.keyboard.ColorSetting import helium314.keyboard.keyboard.ColorSetting
@ -88,9 +94,34 @@ fun ColorsScreen(
fun ColorSetting.displayColor() = if (auto == true) KeyboardTheme.determineUserColor(userColors, ctx, name, isNight) fun ColorSetting.displayColor() = if (auto == true) KeyboardTheme.determineUserColor(userColors, ctx, name, isNight)
else color ?: KeyboardTheme.determineUserColor(userColors, ctx, name, isNight) else color ?: KeyboardTheme.determineUserColor(userColors, ctx, name, isNight)
var newThemeName by rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue(themeName)) }
var chosenColor: ColorSetting? by remember { mutableStateOf(null) } var chosenColor: ColorSetting? by remember { mutableStateOf(null) }
SearchScreen( SearchScreen(
title = themeName, title = {
var nameValid by rememberSaveable { mutableStateOf(true) }
var nameField by rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(newThemeName) }
Row(verticalAlignment = Alignment.CenterVertically) {
TextField(
value = nameField,
onValueChange = {
nameValid = KeyboardTheme.renameUserColors(newThemeName.text, it.text, prefs)
if (nameValid)
newThemeName = it
nameField = it
},
// modifier = Modifier.weight(1f)
)
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.secondary) {
// todo: this should indicate whether name is saved, but looks like a button
// either make it flash and then disappear, or use a better indicator
Icon(
painterResource(if (nameValid) R.drawable.ic_setup_check else R.drawable.ic_close),
null,
Modifier.width(24.dp)
)
}
}
},
onClickBack = onClickBack, onClickBack = onClickBack,
filteredItems = { search -> shownColors.filter { filteredItems = { search -> shownColors.filter {
it.displayName.split(" ", "_").any { it.startsWith(search, true) } it.displayName.split(" ", "_").any { it.startsWith(search, true) }
@ -107,7 +138,9 @@ fun ColorsScreen(
.background(Color(colorSetting.displayColor()), shape = CircleShape) .background(Color(colorSetting.displayColor()), shape = CircleShape)
.size(50.dp) .size(50.dp)
) )
Column(Modifier.weight(1f).padding(horizontal = 16.dp)) { Column(Modifier
.weight(1f)
.padding(horizontal = 16.dp)) {
Text(colorSetting.displayName) Text(colorSetting.displayName)
if (colorSetting.auto == true) if (colorSetting.auto == true)
CompositionLocalProvider( CompositionLocalProvider(