From ac805a9286eb58fee173b9efd2be5934873c38cc Mon Sep 17 00:00:00 2001 From: Helium314 Date: Sun, 30 Mar 2025 12:03:21 +0200 Subject: [PATCH] fix some issues with renaming color schemes fixes GH-1449 and some more unreported bugs --- .../keyboard/keyboard/KeyboardTheme.kt | 22 +++----- .../keyboard/settings/screens/ColorsScreen.kt | 56 ++++++++++--------- 2 files changed, 38 insertions(+), 40 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/KeyboardTheme.kt b/app/src/main/java/helium314/keyboard/keyboard/KeyboardTheme.kt index 9a51bafa..73d03ef0 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/KeyboardTheme.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/KeyboardTheme.kt @@ -405,14 +405,7 @@ private constructor(val themeId: Int, @JvmField val mStyleId: Int) { } fun getUnusedThemeName(initialName: String, prefs: SharedPreferences): String { - 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() + val existingNames = getExistingThemeNames(prefs) if (initialName !in existingNames) return initialName var i = 1 while ("$initialName$i" in existingNames) @@ -420,11 +413,8 @@ private constructor(val themeId: Int, @JvmField val mStyleId: Int) { return "$initialName$i" } - // 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 { + private fun getExistingThemeNames(prefs: SharedPreferences) = + 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) @@ -432,6 +422,12 @@ private constructor(val themeId: Int, @JvmField val mStyleId: Int) { else -> null } }.toSortedSet() + + // 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 = getExistingThemeNames(prefs) if (to in existingNames) return false // all good, now rename prefs.edit { diff --git a/app/src/main/java/helium314/keyboard/settings/screens/ColorsScreen.kt b/app/src/main/java/helium314/keyboard/settings/screens/ColorsScreen.kt index 7f14843a..976a1780 100644 --- a/app/src/main/java/helium314/keyboard/settings/screens/ColorsScreen.kt +++ b/app/src/main/java/helium314/keyboard/settings/screens/ColorsScreen.kt @@ -71,6 +71,14 @@ fun ColorsScreen( onClickBack: () -> Unit ) { val ctx = LocalContext.current + val prefs = ctx.prefs() + val b = (ctx.getActivity() as? SettingsActivity)?.prefChanged?.collectAsState() + if ((b?.value ?: 0) < 0) + Log.v("irrelevant", "stupid way to trigger recomposition on preference change") + + val themeName = theme ?: if (isNight) prefs.getString(Settings.PREF_THEME_COLORS_NIGHT, Defaults.PREF_THEME_COLORS_NIGHT)!! + else prefs.getString(Settings.PREF_THEME_COLORS, Defaults.PREF_THEME_COLORS)!! + var newThemeName by rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue(themeName)) } // is there really no better way of only setting forceOpposite while the screen is shown (and not paused)? // lifecycle stuff is weird, there is no pause and similar when activity is paused @@ -83,21 +91,14 @@ fun ColorsScreen( val lifecycleState by lifecycleOwner.lifecycle.currentStateFlow.collectAsState() LaunchedEffect(lifecycleState) { if (lifecycleState == Lifecycle.State.RESUMED) { - (ctx.getActivity() as? SettingsActivity)?.setForceTheme(theme, isNight) + (ctx.getActivity() as? SettingsActivity)?.setForceTheme(newThemeName.text, isNight) } } - val prefs = ctx.prefs() - val b = (ctx.getActivity() as? SettingsActivity)?.prefChanged?.collectAsState() - if ((b?.value ?: 0) < 0) - Log.v("irrelevant", "stupid way to trigger recomposition on preference change") - - val themeName = theme ?: if (isNight) prefs.getString(Settings.PREF_THEME_COLORS_NIGHT, Defaults.PREF_THEME_COLORS_NIGHT)!! - else prefs.getString(Settings.PREF_THEME_COLORS, Defaults.PREF_THEME_COLORS)!! - val moreColors = KeyboardTheme.readUserMoreColors(prefs, themeName) - val userColors = KeyboardTheme.readUserColors(prefs, themeName) + val moreColors = KeyboardTheme.readUserMoreColors(prefs, newThemeName.text) + val userColors = KeyboardTheme.readUserColors(prefs, newThemeName.text) val shownColors = if (moreColors == 2) { - val allColors = KeyboardTheme.readUserAllColors(prefs, themeName) + val allColors = KeyboardTheme.readUserAllColors(prefs, newThemeName.text) ColorType.entries.map { ColorSetting(it.name, null, allColors[it] ?: it.default()) } @@ -114,12 +115,11 @@ fun ColorsScreen( fun ColorSetting.displayColor() = if (auto == true) 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 chosenColorString: String by rememberSaveable { mutableStateOf("") } val chosenColor = runCatching { Json.decodeFromString(chosenColorString) }.getOrNull() - val saveLauncher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode != Activity.RESULT_OK) return@rememberLauncherForActivityResult - val uri = it.data?.data ?: return@rememberLauncherForActivityResult + val saveLauncher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode != Activity.RESULT_OK) return@rememberLauncherForActivityResult + val uri = result.data?.data ?: return@rememberLauncherForActivityResult ctx.getActivity()?.contentResolver?.openOutputStream(uri)?.writer()?.use { it.write(getColorString(prefs, newThemeName.text)) } } SearchScreen( @@ -130,8 +130,10 @@ fun ColorsScreen( value = nameField, onValueChange = { nameValid = KeyboardTheme.renameUserColors(newThemeName.text, it.text, prefs) - if (nameValid) + if (nameValid) { newThemeName = it + SettingsActivity.forceTheme = newThemeName.text + } nameField = it }, isError = !nameValid, @@ -195,11 +197,11 @@ fun ColorsScreen( } } if (colorSetting.auto != null) - Switch(colorSetting.auto, onCheckedChange = { - val oldUserColors = KeyboardTheme.readUserColors(prefs, themeName) - val newUserColors = (oldUserColors + ColorSetting(colorSetting.name, it, colorSetting.color)) + Switch(colorSetting.auto, onCheckedChange = { checked -> + val oldUserColors = KeyboardTheme.readUserColors(prefs, newThemeName.text) + val newUserColors = (oldUserColors + ColorSetting(colorSetting.name, checked, colorSetting.color)) .reversed().distinctBy { it.displayName } - KeyboardTheme.writeUserColors(prefs, themeName, newUserColors) + KeyboardTheme.writeUserColors(prefs, newThemeName.text, newUserColors) }) } } @@ -209,16 +211,16 @@ fun ColorsScreen( onDismissRequest = { chosenColorString = "" }, initialColor = chosenColor.displayColor(), title = chosenColor.displayName, - ) { + ) { color -> if (moreColors == 2) { - val oldColors = KeyboardTheme.readUserAllColors(prefs, themeName) - oldColors[ColorType.valueOf(chosenColor.name)] = it - KeyboardTheme.writeUserAllColors(prefs, themeName, oldColors) + val oldColors = KeyboardTheme.readUserAllColors(prefs, newThemeName.text) + oldColors[ColorType.valueOf(chosenColor.name)] = color + KeyboardTheme.writeUserAllColors(prefs, newThemeName.text, oldColors) } else { - val oldUserColors = KeyboardTheme.readUserColors(prefs, themeName) - val newUserColors = (oldUserColors + ColorSetting(chosenColor.name, false, it)) + val oldUserColors = KeyboardTheme.readUserColors(prefs, newThemeName.text) + val newUserColors = (oldUserColors + ColorSetting(chosenColor.name, false, color)) .reversed().distinctBy { it.displayName } - KeyboardTheme.writeUserColors(prefs, themeName, newUserColors) + KeyboardTheme.writeUserColors(prefs, newThemeName.text, newUserColors) } } }