mirror of
https://github.com/Helium314/HeliBoard.git
synced 2025-05-27 04:07:10 +00:00
245 lines
12 KiB
Kotlin
245 lines
12 KiB
Kotlin
// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only
|
|
package helium314.keyboard.latin
|
|
|
|
import android.app.Application
|
|
import android.content.Context
|
|
import androidx.core.content.edit
|
|
import androidx.preference.PreferenceManager
|
|
import helium314.keyboard.latin.common.LocaleUtils.constructLocale
|
|
import helium314.keyboard.latin.settings.Settings
|
|
import helium314.keyboard.latin.settings.USER_DICTIONARY_SUFFIX
|
|
import helium314.keyboard.latin.utils.CUSTOM_LAYOUT_PREFIX
|
|
import helium314.keyboard.latin.utils.DeviceProtectedUtils
|
|
import helium314.keyboard.latin.utils.DictionaryInfoUtils
|
|
import helium314.keyboard.latin.utils.Log
|
|
import helium314.keyboard.latin.utils.ToolbarKey
|
|
import helium314.keyboard.latin.utils.defaultPinnedToolbarPref
|
|
import helium314.keyboard.latin.utils.getCustomLayoutFile
|
|
import helium314.keyboard.latin.utils.getCustomLayoutFiles
|
|
import helium314.keyboard.latin.utils.onCustomLayoutFileListChanged
|
|
import helium314.keyboard.latin.utils.upgradeToolbarPrefs
|
|
import java.io.File
|
|
|
|
class App : Application() {
|
|
override fun onCreate() {
|
|
super.onCreate()
|
|
checkVersionUpgrade(this)
|
|
app = this
|
|
}
|
|
|
|
companion object {
|
|
// used so JniUtils can access application once
|
|
private var app: App? = null
|
|
fun getApp(): App? {
|
|
val application = app
|
|
app = null
|
|
return application
|
|
}
|
|
}
|
|
}
|
|
|
|
fun checkVersionUpgrade(context: Context) {
|
|
val prefs = DeviceProtectedUtils.getSharedPreferences(context)
|
|
val oldVersion = prefs.getInt(Settings.PREF_VERSION_CODE, 0)
|
|
if (oldVersion == BuildConfig.VERSION_CODE)
|
|
return
|
|
// clear extracted dictionaries, in case updated version contains newer ones
|
|
DictionaryInfoUtils.getCachedDirectoryList(context)?.forEach {
|
|
if (!it.isDirectory) return@forEach
|
|
val files = it.listFiles() ?: return@forEach
|
|
for (file in files) {
|
|
if (!file.name.endsWith(USER_DICTIONARY_SUFFIX))
|
|
file.delete()
|
|
}
|
|
}
|
|
if (oldVersion == 0) // new install or restoring settings from old app name
|
|
upgradesWhenComingFromOldAppName(context)
|
|
if (oldVersion <= 1000) { // upgrade old custom layouts name
|
|
val oldShiftSymbolsFile = getCustomLayoutFile("${CUSTOM_LAYOUT_PREFIX}shift_symbols", context)
|
|
if (oldShiftSymbolsFile.exists()) {
|
|
oldShiftSymbolsFile.renameTo(getCustomLayoutFile("${CUSTOM_LAYOUT_PREFIX}symbols_shifted", context))
|
|
}
|
|
|
|
// rename subtype setting, and clean old subtypes that might remain in some cases
|
|
val subtypesPref = prefs.getString("enabled_input_styles", "")!!
|
|
.split(";").filter { it.isNotEmpty() }
|
|
.map {
|
|
val localeAndLayout = it.split(":").toMutableList()
|
|
localeAndLayout[0] = localeAndLayout[0].constructLocale().toLanguageTag()
|
|
localeAndLayout.joinToString(":")
|
|
}.toSet().joinToString(";")
|
|
val selectedSubtype = prefs.getString("selected_input_style", "")
|
|
prefs.edit {
|
|
remove("enabled_input_styles")
|
|
putString(Settings.PREF_ENABLED_SUBTYPES, subtypesPref)
|
|
remove("selected_input_style")
|
|
putString(Settings.PREF_SELECTED_SUBTYPE, selectedSubtype)
|
|
}
|
|
}
|
|
if (oldVersion <= 2000) {
|
|
// upgrade pinned toolbar keys pref
|
|
val oldPinnedKeysPref = prefs.getString(Settings.PREF_PINNED_TOOLBAR_KEYS, "")!!
|
|
val pinnedKeys = oldPinnedKeysPref.split(";").mapNotNull {
|
|
try {
|
|
ToolbarKey.valueOf(it)
|
|
} catch (_: IllegalArgumentException) {
|
|
null
|
|
}
|
|
}
|
|
val newPinnedKeysPref = (pinnedKeys.map { "${it.name},true" } + defaultPinnedToolbarPref.split(";"))
|
|
.distinctBy { it.split(",").first() }
|
|
.joinToString(";")
|
|
prefs.edit { putString(Settings.PREF_PINNED_TOOLBAR_KEYS, newPinnedKeysPref) }
|
|
|
|
// enable language switch key if it was enabled previously
|
|
if (prefs.contains(Settings.PREF_LANGUAGE_SWITCH_KEY) && prefs.getString(Settings.PREF_LANGUAGE_SWITCH_KEY, "") != "off")
|
|
prefs.edit { putBoolean(Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY, true) }
|
|
}
|
|
if (oldVersion <= 2100) {
|
|
if (prefs.contains(Settings.PREF_SHOW_MORE_COLORS)) {
|
|
val moreColors = prefs.getInt(Settings.PREF_SHOW_MORE_COLORS, 0)
|
|
prefs.edit {
|
|
putInt(Settings.getColorPref(Settings.PREF_SHOW_MORE_COLORS, false), moreColors)
|
|
if (prefs.getBoolean(Settings.PREF_THEME_DAY_NIGHT, false))
|
|
putInt(Settings.getColorPref(Settings.PREF_SHOW_MORE_COLORS, true), moreColors)
|
|
remove(Settings.PREF_SHOW_MORE_COLORS)
|
|
}
|
|
}
|
|
}
|
|
if (oldVersion <= 2201) {
|
|
val additionalSubtypeString = Settings.readPrefAdditionalSubtypes(prefs, context.resources)
|
|
if (additionalSubtypeString.contains(".")) { // means there are custom layouts
|
|
val subtypeStrings = additionalSubtypeString.split(";")
|
|
val newSubtypeStrings = subtypeStrings.mapNotNull {
|
|
val split = it.split(":").toMutableList()
|
|
Log.i("test", "0: $it")
|
|
if (split.size < 2) return@mapNotNull null // should never happen
|
|
val oldName = split[1]
|
|
val newName = oldName.substringBeforeLast(".") + "."
|
|
if (oldName == newName) return@mapNotNull split.joinToString(":") // should never happen
|
|
val oldFile = getCustomLayoutFile(oldName, context)
|
|
val newFile = getCustomLayoutFile(newName, context)
|
|
Log.i("test", "1")
|
|
if (!oldFile.exists()) return@mapNotNull null // should never happen
|
|
Log.i("test", "2")
|
|
if (newFile.exists()) newFile.delete() // should never happen
|
|
Log.i("test", "3")
|
|
oldFile.renameTo(newFile)
|
|
val enabledSubtypes = prefs.getString(Settings.PREF_ENABLED_SUBTYPES, "")!!
|
|
if (enabledSubtypes.contains(oldName))
|
|
prefs.edit { putString(Settings.PREF_ENABLED_SUBTYPES, enabledSubtypes.replace(oldName, newName)) }
|
|
val selectedSubtype = prefs.getString(Settings.PREF_SELECTED_SUBTYPE, "")!!
|
|
if (selectedSubtype.contains(oldName))
|
|
prefs.edit { putString(Settings.PREF_SELECTED_SUBTYPE, selectedSubtype.replace(oldName, newName)) }
|
|
split[1] = newName
|
|
split.joinToString(":")
|
|
}
|
|
Settings.writePrefAdditionalSubtypes(prefs, newSubtypeStrings.joinToString(";"))
|
|
}
|
|
// rename other custom layouts
|
|
onCustomLayoutFileListChanged()
|
|
getCustomLayoutFiles(context).forEach {
|
|
val newFile = getCustomLayoutFile(it.name.substringBeforeLast(".") + ".", context)
|
|
if (newFile.name == it.name) return@forEach
|
|
if (newFile.exists()) newFile.delete() // should never happen
|
|
it.renameTo(newFile)
|
|
}
|
|
}
|
|
upgradeToolbarPrefs(prefs)
|
|
onCustomLayoutFileListChanged() // just to be sure
|
|
prefs.edit { putInt(Settings.PREF_VERSION_CODE, BuildConfig.VERSION_CODE) }
|
|
}
|
|
|
|
// todo (later): remove it when most users probably have upgraded
|
|
private fun upgradesWhenComingFromOldAppName(context: Context) {
|
|
// move layout files
|
|
try {
|
|
File(context.filesDir, "layouts").listFiles()?.forEach {
|
|
it.copyTo(getCustomLayoutFile(it.name, context), true)
|
|
it.delete()
|
|
}
|
|
} catch (_: Exception) {}
|
|
// move background images
|
|
try {
|
|
val bgDay = File(context.filesDir, "custom_background_image")
|
|
if (bgDay.isFile) {
|
|
bgDay.copyTo(Settings.getCustomBackgroundFile(context, false, false), true)
|
|
bgDay.delete()
|
|
}
|
|
val bgNight = File(context.filesDir, "custom_background_image_night")
|
|
if (bgNight.isFile) {
|
|
bgNight.copyTo(Settings.getCustomBackgroundFile(context, true, false), true)
|
|
bgNight.delete()
|
|
}
|
|
} catch (_: Exception) {}
|
|
// upgrade prefs
|
|
val prefs = DeviceProtectedUtils.getSharedPreferences(context)
|
|
if (prefs.all.containsKey("theme_variant")) {
|
|
prefs.edit().putString(Settings.PREF_THEME_COLORS, prefs.getString("theme_variant", "")).apply()
|
|
prefs.edit().remove("theme_variant").apply()
|
|
}
|
|
if (prefs.all.containsKey("theme_variant_night")) {
|
|
prefs.edit().putString(Settings.PREF_THEME_COLORS_NIGHT, prefs.getString("theme_variant_night", "")).apply()
|
|
prefs.edit().remove("theme_variant_night").apply()
|
|
}
|
|
prefs.all.toMap().forEach {
|
|
if (it.key.startsWith("pref_key_") && it.key != "pref_key_longpress_timeout") {
|
|
var remove = true
|
|
when (val value = it.value) {
|
|
is Boolean -> prefs.edit().putBoolean(it.key.substringAfter("pref_key_"), value).apply()
|
|
is Int -> prefs.edit().putInt(it.key.substringAfter("pref_key_"), value).apply()
|
|
is Long -> prefs.edit().putLong(it.key.substringAfter("pref_key_"), value).apply()
|
|
is String -> prefs.edit().putString(it.key.substringAfter("pref_key_"), value).apply()
|
|
is Float -> prefs.edit().putFloat(it.key.substringAfter("pref_key_"), value).apply()
|
|
else -> remove = false
|
|
}
|
|
if (remove)
|
|
prefs.edit().remove(it.key).apply()
|
|
} else if (it.key.startsWith("pref_")) {
|
|
var remove = true
|
|
when (val value = it.value) {
|
|
is Boolean -> prefs.edit().putBoolean(it.key.substringAfter("pref_"), value).apply()
|
|
is Int -> prefs.edit().putInt(it.key.substringAfter("pref_"), value).apply()
|
|
is Long -> prefs.edit().putLong(it.key.substringAfter("pref_"), value).apply()
|
|
is String -> prefs.edit().putString(it.key.substringAfter("pref_"), value).apply()
|
|
is Float -> prefs.edit().putFloat(it.key.substringAfter("pref_"), value).apply()
|
|
else -> remove = false
|
|
}
|
|
if (remove)
|
|
prefs.edit().remove(it.key).apply()
|
|
}
|
|
}
|
|
// change more_keys to popup_keys
|
|
if (prefs.contains("more_keys_order")) {
|
|
prefs.edit().putString(Settings.PREF_POPUP_KEYS_ORDER, prefs.getString("more_keys_order", "")?.replace("more_", "popup_")).apply()
|
|
prefs.edit().remove("more_keys_order").apply()
|
|
}
|
|
if (prefs.contains("more_keys_labels_order")) {
|
|
prefs.edit().putString(Settings.PREF_POPUP_KEYS_LABELS_ORDER, prefs.getString("more_keys_labels_order", "")?.replace("more_", "popup_")).apply()
|
|
prefs.edit().remove("more_keys_labels_order").apply()
|
|
}
|
|
if (prefs.contains("more_more_keys")) {
|
|
prefs.edit().putString(Settings.PREF_MORE_POPUP_KEYS, prefs.getString("more_more_keys", "")).apply()
|
|
prefs.edit().remove("more_more_keys").apply()
|
|
}
|
|
if (prefs.contains("spellcheck_use_contacts")) {
|
|
prefs.edit().putBoolean(Settings.PREF_USE_CONTACTS, prefs.getBoolean("spellcheck_use_contacts", false)).apply()
|
|
prefs.edit().remove("spellcheck_use_contacts").apply()
|
|
}
|
|
// upgrade additional subtype locale strings
|
|
val additionalSubtypes = mutableListOf<String>()
|
|
Settings.readPrefAdditionalSubtypes(prefs, context.resources).split(";").forEach {
|
|
val localeString = it.substringBefore(":")
|
|
additionalSubtypes.add(it.replace(localeString, localeString.constructLocale().toLanguageTag()))
|
|
}
|
|
Settings.writePrefAdditionalSubtypes(prefs, additionalSubtypes.joinToString(";"))
|
|
// move pinned clips to credential protected storage if device is not locked (should never happen)
|
|
if (!prefs.contains(Settings.PREF_PINNED_CLIPS)) return
|
|
try {
|
|
val defaultPrefs = PreferenceManager.getDefaultSharedPreferences(context)
|
|
defaultPrefs.edit { putString(Settings.PREF_PINNED_CLIPS, prefs.getString(Settings.PREF_PINNED_CLIPS, "")) }
|
|
prefs.edit { remove(Settings.PREF_PINNED_CLIPS) }
|
|
} catch (_: IllegalStateException) {
|
|
// SharedPreferences in credential encrypted storage are not available until after user is unlocked
|
|
}
|
|
}
|