also consider default layouts when removing custom layouts without file

was missing in d15a97ccba
also rearrange the code a little
fixes GH-1490
This commit is contained in:
Helium314 2025-04-26 13:24:10 +02:00
parent 6d9f69a4b6
commit 322f8f9712
4 changed files with 37 additions and 40 deletions

View file

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

View file

@ -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<LayoutType, String>, 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!

View file

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

View file

@ -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()
}