From 322f8f971263d2500b5a64fe7345e55d02664ac0 Mon Sep 17 00:00:00 2001 From: Helium314 Date: Sat, 26 Apr 2025 13:24:10 +0200 Subject: [PATCH] also consider default layouts when removing custom layouts without file was missing in d15a97ccbaa3a75a62b597ad13f7816c8bca9775 also rearrange the code a little fixes GH-1490 --- .../main/java/helium314/keyboard/latin/App.kt | 1 + .../keyboard/latin/utils/LayoutUtilsCustom.kt | 46 ++++++++++++++----- .../keyboard/latin/utils/SubtypeSettings.kt | 29 +----------- .../preferences/BackupRestorePreference.kt | 1 + 4 files changed, 37 insertions(+), 40 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/latin/App.kt b/app/src/main/java/helium314/keyboard/latin/App.kt index 9e40e23e7..904cc028b 100644 --- a/app/src/main/java/helium314/keyboard/latin/App.kt +++ b/app/src/main/java/helium314/keyboard/latin/App.kt @@ -51,6 +51,7 @@ class App : Application() { checkVersionUpgrade(this) app = this Defaults.initDynamicDefaults(this) + LayoutUtilsCustom.removeMissingLayouts(this) // only after version upgrade val packageInfo = packageManager.getPackageInfo(packageName, 0) @Suppress("DEPRECATION") diff --git a/app/src/main/java/helium314/keyboard/latin/utils/LayoutUtilsCustom.kt b/app/src/main/java/helium314/keyboard/latin/utils/LayoutUtilsCustom.kt index 33ea1f28a..19b44f739 100644 --- a/app/src/main/java/helium314/keyboard/latin/utils/LayoutUtilsCustom.kt +++ b/app/src/main/java/helium314/keyboard/latin/utils/LayoutUtilsCustom.kt @@ -2,6 +2,7 @@ package helium314.keyboard.latin.utils import android.content.Context +import android.widget.Toast import helium314.keyboard.keyboard.Key import helium314.keyboard.keyboard.KeyboardId import helium314.keyboard.keyboard.KeyboardLayoutSet @@ -10,9 +11,14 @@ import helium314.keyboard.keyboard.internal.KeyboardParams import helium314.keyboard.keyboard.internal.keyboard_parser.LayoutParser import helium314.keyboard.keyboard.internal.keyboard_parser.POPUP_KEYS_NORMAL import helium314.keyboard.keyboard.internal.keyboard_parser.addLocaleKeyTextsToParams +import helium314.keyboard.latin.common.Constants.Separators +import helium314.keyboard.latin.common.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET import helium314.keyboard.latin.common.decodeBase36 import helium314.keyboard.latin.common.encodeBase36 +import helium314.keyboard.latin.define.DebugFlags +import helium314.keyboard.latin.settings.Defaults import helium314.keyboard.latin.settings.Settings +import helium314.keyboard.latin.settings.SettingsSubtype.Companion.toSettingsSubtype import helium314.keyboard.latin.utils.LayoutType.Companion.folder import helium314.keyboard.latin.utils.ScriptUtils.script import kotlinx.serialization.SerializationException @@ -124,7 +130,6 @@ object LayoutUtilsCustom { layoutName } - /** @return layoutName for given [displayName]. If [layoutType ]is MAIN, non-null [locale] must be supplied */ fun getLayoutName(displayName: String, layoutType: LayoutType, locale: Locale? = null): String { if (layoutType != LayoutType.MAIN) @@ -143,18 +148,35 @@ object LayoutUtilsCustom { return file } - /** @return whether a layout has no file and was removed from [layouts] */ - fun removeMissingLayouts(layouts: EnumMap, context: Context): Boolean { - var removed = false - LayoutType.entries.forEach { type -> - val name = layouts[type] ?: return@forEach - if (!isCustomLayout(name) || getLayoutFiles(type, context).any { it.name == name }) - return@forEach - // no file for custom layout - layouts.remove(type) - removed = true + // remove layouts without a layout file from custom subtypes and settings + // should not be necessary, but better fall back to default instead of crashing when encountering a bug + fun removeMissingLayouts(context: Context) { + val prefs = context.prefs() + fun remove(type: LayoutType, name: String) { + val message = "removing custom layout ${getDisplayName(name)} / $name without file" + if (DebugFlags.DEBUG_ENABLED) + Toast.makeText(context, message, Toast.LENGTH_LONG).show() + Log.w(TAG, message) + SubtypeSettings.onRenameLayout(type, name, null, context) } - return removed + LayoutType.entries.forEach { type -> + val name = Settings.readDefaultLayoutName(type, prefs) + if (!isCustomLayout(name) || getLayoutFiles(type, context).any { it.name.startsWith(name) }) + return@forEach + remove(type, name) + } + prefs.getString(Settings.PREF_ADDITIONAL_SUBTYPES, Defaults.PREF_ADDITIONAL_SUBTYPES)!! + .split(Separators.SETS).forEach outer@{ + val subtype = it.toSettingsSubtype() + LayoutType.getLayoutMap(subtype.getExtraValueOf(KEYBOARD_LAYOUT_SET) ?: "").forEach { (type, name) -> + if (!isCustomLayout(name) || getLayoutFiles(type, context).any { it.name.startsWith(name) }) + return@forEach + remove(type, name) + // recursive call: additional subtypes must have changed, so we repeat until nothing needs to be deleted + removeMissingLayouts(context) + return + } + } } // this goes into prefs and file names, so do not change! diff --git a/app/src/main/java/helium314/keyboard/latin/utils/SubtypeSettings.kt b/app/src/main/java/helium314/keyboard/latin/utils/SubtypeSettings.kt index 2566cf703..86486adb9 100644 --- a/app/src/main/java/helium314/keyboard/latin/utils/SubtypeSettings.kt +++ b/app/src/main/java/helium314/keyboard/latin/utils/SubtypeSettings.kt @@ -13,14 +13,12 @@ import helium314.keyboard.compat.locale import helium314.keyboard.keyboard.KeyboardSwitcher import helium314.keyboard.latin.RichInputMethodManager import helium314.keyboard.latin.common.Constants.Separators -import helium314.keyboard.latin.common.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET import helium314.keyboard.latin.common.LocaleUtils import helium314.keyboard.latin.define.DebugFlags import helium314.keyboard.latin.settings.Defaults import helium314.keyboard.latin.settings.Settings import helium314.keyboard.latin.settings.SettingsSubtype import helium314.keyboard.latin.settings.SettingsSubtype.Companion.toSettingsSubtype -import helium314.keyboard.latin.utils.LayoutType.Companion.toExtraValue import helium314.keyboard.latin.utils.ScriptUtils.script import java.util.Locale @@ -156,7 +154,7 @@ object SubtypeSettings { } else subtype.toPref() }.joinToString(Separators.SETS) - prefs.edit().putString(key, new).apply() + editor.putString(key, new) } editor.apply() if (Settings.readDefaultLayoutName(type, prefs) == from) @@ -166,7 +164,6 @@ object SubtypeSettings { fun reloadEnabledSubtypes(context: Context) { enabledSubtypes.clear() - removeMissingCustomLayouts(context) loadAdditionalSubtypes(context.prefs()) loadEnabledSubtypes(context) if (RichInputMethodManager.isInitialized()) @@ -190,7 +187,6 @@ object SubtypeSettings { reloadSystemLocales(context) loadResourceSubtypes(context.resources) - removeMissingCustomLayouts(context) loadAdditionalSubtypes(context.prefs()) loadEnabledSubtypes(context) } @@ -218,29 +214,6 @@ object SubtypeSettings { } } - // remove layouts without a layout file from custom subtypes - // should not be necessary, but better fall back to default instead of crashing when encountering a bug - private fun removeMissingCustomLayouts(context: Context) { - val prefs = context.prefs() - val additionalSubtypes = prefs.getString(Settings.PREF_ADDITIONAL_SUBTYPES, Defaults.PREF_ADDITIONAL_SUBTYPES)!! - .split(Separators.SETS).map { it.toSettingsSubtype() } - additionalSubtypes.forEach { subtype -> - val layouts = LayoutType.getLayoutMap(subtype.getExtraValueOf(KEYBOARD_LAYOUT_SET) ?: "") - if (LayoutUtilsCustom.removeMissingLayouts(layouts, context)) { - // layout file is missing -> adjust the subtype to use the modified layout map - val newSubtype = if (layouts.isEmpty()) subtype.without(KEYBOARD_LAYOUT_SET) - else subtype.with(KEYBOARD_LAYOUT_SET, layouts.toExtraValue()) - SubtypeUtilsAdditional.changeAdditionalSubtype(subtype, newSubtype, context) - val message = "removing custom layouts without file from subtype $subtype" - if (DebugFlags.DEBUG_ENABLED) - Toast.makeText(context, message, Toast.LENGTH_LONG).show() - Log.w(TAG, message) - // we return here, because changeAdditionalSubtype calls reloadEnabledSubtypes, which calls this method - return - } - } - } - private fun loadAdditionalSubtypes(prefs: SharedPreferences) { additionalSubtypes.clear() val additionalSubtypeString = prefs.getString(Settings.PREF_ADDITIONAL_SUBTYPES, Defaults.PREF_ADDITIONAL_SUBTYPES)!! diff --git a/app/src/main/java/helium314/keyboard/settings/preferences/BackupRestorePreference.kt b/app/src/main/java/helium314/keyboard/settings/preferences/BackupRestorePreference.kt index a736014b8..40bfa4a38 100644 --- a/app/src/main/java/helium314/keyboard/settings/preferences/BackupRestorePreference.kt +++ b/app/src/main/java/helium314/keyboard/settings/preferences/BackupRestorePreference.kt @@ -164,6 +164,7 @@ fun BackupRestorePreference(setting: Setting) { val newDictBroadcast = Intent(DictionaryPackConstants.NEW_DICTIONARY_INTENT_ACTION) ctx.getActivity()?.sendBroadcast(newDictBroadcast) LayoutUtilsCustom.onLayoutFileChanged() + LayoutUtilsCustom.removeMissingLayouts(ctx) (ctx.getActivity() as? SettingsActivity)?.prefChanged() KeyboardSwitcher.getInstance().setThemeNeedsReload() }