mirror of
https://github.com/Helium314/HeliBoard.git
synced 2025-05-14 05:52:47 +00:00
add setting for customizing functional key layouts
This commit is contained in:
parent
17aa321fbd
commit
0459971e3a
10 changed files with 150 additions and 61 deletions
|
@ -197,8 +197,8 @@ class KeyboardParser(private val params: KeyboardParams, private val context: Co
|
|||
val functionalKeysBottom = allFunctionalKeys.lastOrNull() ?: return
|
||||
if (!params.mId.isAlphaOrSymbolKeyboard || functionalKeysBottom.isEmpty() || functionalKeysBottom.any { it.isKeyPlaceholder() })
|
||||
return
|
||||
if (true /* Settings.getInstance().current.mSingleFunctionalLayout */) { // todo with the customizable functional layout
|
||||
// remove unwanted keys (emoji, numpad, language switch)
|
||||
if (!Settings.getInstance().current.mHasCustomFunctionalLayout) {
|
||||
// remove keys that should only exist on specific layouts or depend on setting (emoji, numpad, language switch)
|
||||
if (!Settings.getInstance().current.mShowsEmojiKey || !params.mId.isAlphabetKeyboard)
|
||||
functionalKeysBottom.removeFirst { it.label == KeyLabel.EMOJI }
|
||||
if (!Settings.getInstance().current.isLanguageSwitchKeyEnabled || !params.mId.isAlphabetKeyboard)
|
||||
|
@ -314,7 +314,3 @@ const val LAYOUT_NUMPAD_LANDSCAPE = "numpad_landscape"
|
|||
const val LAYOUT_NUMBER = "number"
|
||||
const val LAYOUT_PHONE = "phone"
|
||||
const val LAYOUT_PHONE_SYMBOLS = "phone_symbols"
|
||||
const val FUNCTIONAL_LAYOUT_SYMBOLS_SHIFTED = "functional_keys_symbols_shifted"
|
||||
const val FUNCTIONAL_LAYOUT_SYMBOLS = "functional_keys_symbols"
|
||||
const val FUNCTIONAL_LAYOUT = "functional_keys"
|
||||
const val FUNCTIONAL_LAYOUT_TABLET = "functional_keys_tablet"
|
||||
|
|
|
@ -22,8 +22,9 @@ import helium314.keyboard.latin.settings.Settings
|
|||
import helium314.keyboard.latin.utils.CUSTOM_LAYOUT_PREFIX
|
||||
import helium314.keyboard.latin.utils.ScriptUtils
|
||||
import helium314.keyboard.latin.utils.ScriptUtils.script
|
||||
import helium314.keyboard.latin.utils.getCustomFunctionalLayoutName
|
||||
import helium314.keyboard.latin.utils.getCustomLayoutFile
|
||||
import helium314.keyboard.latin.utils.getCustomLayoutsDir
|
||||
import helium314.keyboard.latin.utils.getCustomLayoutFiles
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.modules.SerializersModule
|
||||
import kotlinx.serialization.modules.polymorphic
|
||||
|
@ -35,13 +36,12 @@ object RawKeyboardParser {
|
|||
val symbolAndNumberLayouts = listOf(LAYOUT_SYMBOLS, LAYOUT_SYMBOLS_SHIFTED, LAYOUT_SYMBOLS_ARABIC,
|
||||
LAYOUT_NUMBER, LAYOUT_NUMPAD, LAYOUT_NUMPAD_LANDSCAPE, LAYOUT_PHONE, LAYOUT_PHONE_SYMBOLS)
|
||||
|
||||
// todo: cache is by layout name, this is inefficient for functional keys by default
|
||||
fun clearCache() = rawLayoutCache.clear()
|
||||
|
||||
fun parseLayout(params: KeyboardParams, context: Context, isFunctional: Boolean = false): MutableList<MutableList<KeyData>> {
|
||||
val layoutName = if (isFunctional) {
|
||||
if (!params.mId.isAlphaOrSymbolKeyboard) return mutableListOf(mutableListOf())
|
||||
else getFunctionalLayoutName(params)
|
||||
else getFunctionalLayoutName(params, context)
|
||||
} else {
|
||||
getLayoutName(params, context)
|
||||
}
|
||||
|
@ -121,43 +121,24 @@ object RawKeyboardParser {
|
|||
else -> params.mId.mSubtype.keyboardLayoutSetName.substringBeforeLast("+")
|
||||
}
|
||||
|
||||
// todo (later, see also keyboardParser): use Settings.getInstance().current.mSingleFunctionalLayout
|
||||
private fun getFunctionalLayoutName(params: KeyboardParams) = when (params.mId.mElementId) {
|
||||
KeyboardId.ELEMENT_SYMBOLS_SHIFTED -> FUNCTIONAL_LAYOUT_SYMBOLS_SHIFTED
|
||||
KeyboardId.ELEMENT_SYMBOLS -> FUNCTIONAL_LAYOUT_SYMBOLS
|
||||
else -> if (Settings.getInstance().isTablet) FUNCTIONAL_LAYOUT_TABLET else FUNCTIONAL_LAYOUT
|
||||
private fun getFunctionalLayoutName(params: KeyboardParams, context: Context): String {
|
||||
if (Settings.getInstance().current.mHasCustomFunctionalLayout) {
|
||||
getCustomFunctionalLayoutName(params.mId.mElementId, params.mId.mSubtype.rawSubtype, context)
|
||||
?.let { return it }
|
||||
}
|
||||
return if (Settings.getInstance().isTablet) "functional_keys_tablet" else "functional_keys"
|
||||
}
|
||||
|
||||
/** returns the file name matching the layout name, making sure the file exists (falling back to qwerty.txt) */
|
||||
private fun getLayoutFileName(layoutName: String, context: Context): String {
|
||||
val customFiles = getCustomLayoutsDir(context).list()
|
||||
val customFiles = getCustomLayoutFiles(context).map { it.name }
|
||||
if (layoutName.startsWith(CUSTOM_LAYOUT_PREFIX)) {
|
||||
return if (customFiles?.contains(layoutName) == true) layoutName
|
||||
else "qwerty.txt" // fallback
|
||||
return customFiles.firstOrNull { it.startsWith(layoutName)}
|
||||
?: if (layoutName.contains("functional")) "functional_keys.json" else "qwerty.txt" // fallback to defaults
|
||||
}
|
||||
val assetsFiles by lazy { context.assets.list("layouts")!! }
|
||||
if (layoutName.startsWith("functional")) {
|
||||
// return custom match if we have one
|
||||
val customMatch = customFiles?.firstOrNull { it.startsWith("$CUSTOM_LAYOUT_PREFIX$layoutName.") }
|
||||
if (customMatch != null) return customMatch
|
||||
if (layoutName == FUNCTIONAL_LAYOUT_SYMBOLS_SHIFTED) {
|
||||
// no custom symbols shifted layout, try custom symbols layout
|
||||
val customSymbols = customFiles?.firstOrNull { it.startsWith("$CUSTOM_LAYOUT_PREFIX$FUNCTIONAL_LAYOUT_SYMBOLS.") }
|
||||
if (customSymbols != null) return customSymbols
|
||||
}
|
||||
// no custom symbols layout, try custom functional layout
|
||||
if (Settings.getInstance().isTablet) {
|
||||
val customTablet = customFiles?.firstOrNull { it.startsWith("$CUSTOM_LAYOUT_PREFIX$FUNCTIONAL_LAYOUT_TABLET.") }
|
||||
if (customTablet != null) return customTablet
|
||||
}
|
||||
val customFunctional = customFiles?.firstOrNull { it.startsWith("$CUSTOM_LAYOUT_PREFIX$FUNCTIONAL_LAYOUT.") }
|
||||
if (customFunctional != null) return customFunctional
|
||||
// no custom functional layout, use the default functional layout
|
||||
return if (Settings.getInstance().isTablet) "$FUNCTIONAL_LAYOUT_TABLET.json"
|
||||
else "$FUNCTIONAL_LAYOUT.json"
|
||||
}
|
||||
return if (layoutName in symbolAndNumberLayouts) {
|
||||
customFiles?.firstOrNull { it.startsWith("$CUSTOM_LAYOUT_PREFIX$layoutName.")}
|
||||
customFiles.firstOrNull { it.startsWith("$CUSTOM_LAYOUT_PREFIX$layoutName.")}
|
||||
?: assetsFiles.first { it.startsWith(layoutName) }
|
||||
} else {
|
||||
// can't be custom layout, so it must be in assets
|
||||
|
|
|
@ -11,7 +11,8 @@ 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.getCustomLayoutsDir
|
||||
import helium314.keyboard.latin.utils.getCustomLayoutFile
|
||||
import helium314.keyboard.latin.utils.onCustomLayoutFileListChanged
|
||||
import helium314.keyboard.latin.utils.upgradeToolbarPrefs
|
||||
import java.io.File
|
||||
|
||||
|
@ -51,10 +52,9 @@ fun checkVersionUpgrade(context: Context) {
|
|||
if (oldVersion == 0) // new install or restoring settings from old app name
|
||||
upgradesWhenComingFromOldAppName(context)
|
||||
if (oldVersion <= 1000) { // upgrade old custom layouts name
|
||||
val layoutsDir = getCustomLayoutsDir(context)
|
||||
val oldShiftSymbolsFile = File(layoutsDir, "${CUSTOM_LAYOUT_PREFIX}shift_symbols")
|
||||
val oldShiftSymbolsFile = getCustomLayoutFile("${CUSTOM_LAYOUT_PREFIX}shift_symbols", context)
|
||||
if (oldShiftSymbolsFile.exists()) {
|
||||
oldShiftSymbolsFile.renameTo(File(layoutsDir, "${CUSTOM_LAYOUT_PREFIX}symbols_shifted"))
|
||||
oldShiftSymbolsFile.renameTo(getCustomLayoutFile("${CUSTOM_LAYOUT_PREFIX}symbols_shifted", context))
|
||||
}
|
||||
|
||||
// rename subtype setting, and clean old subtypes that might remain in some cases
|
||||
|
@ -73,6 +73,7 @@ fun checkVersionUpgrade(context: Context) {
|
|||
putString(Settings.PREF_SELECTED_SUBTYPE, selectedSubtype)
|
||||
}
|
||||
}
|
||||
onCustomLayoutFileListChanged() // just to be sure
|
||||
prefs.edit { putInt(Settings.PREF_VERSION_CODE, BuildConfig.VERSION_CODE) }
|
||||
}
|
||||
|
||||
|
@ -80,9 +81,8 @@ fun checkVersionUpgrade(context: Context) {
|
|||
private fun upgradesWhenComingFromOldAppName(context: Context) {
|
||||
// move layout files
|
||||
try {
|
||||
val layoutsDir = getCustomLayoutsDir(context)
|
||||
File(context.filesDir, "layouts").listFiles()?.forEach {
|
||||
it.copyTo(File(layoutsDir, it.name), true)
|
||||
it.copyTo(getCustomLayoutFile(it.name, context), true)
|
||||
it.delete()
|
||||
}
|
||||
} catch (_: Exception) {}
|
||||
|
|
|
@ -41,12 +41,15 @@ import helium314.keyboard.latin.common.FileUtils
|
|||
import helium314.keyboard.latin.common.LocaleUtils.constructLocale
|
||||
import helium314.keyboard.latin.settings.SeekBarDialogPreference.ValueProxy
|
||||
import helium314.keyboard.latin.utils.AdditionalSubtypeUtils
|
||||
import helium314.keyboard.latin.utils.CUSTOM_FUNCTIONAL_LAYOUT_NORMAL
|
||||
import helium314.keyboard.latin.utils.CUSTOM_FUNCTIONAL_LAYOUT_SYMBOLS
|
||||
import helium314.keyboard.latin.utils.CUSTOM_FUNCTIONAL_LAYOUT_SYMBOLS_SHIFTED
|
||||
import helium314.keyboard.latin.utils.CUSTOM_LAYOUT_PREFIX
|
||||
import helium314.keyboard.latin.utils.DeviceProtectedUtils
|
||||
import helium314.keyboard.latin.utils.ExecutorUtils
|
||||
import helium314.keyboard.latin.utils.JniUtils
|
||||
import helium314.keyboard.latin.utils.editCustomLayout
|
||||
import helium314.keyboard.latin.utils.getCustomLayoutsDir
|
||||
import helium314.keyboard.latin.utils.getCustomLayoutFiles
|
||||
import helium314.keyboard.latin.utils.getStringResourceOrName
|
||||
import helium314.keyboard.latin.utils.infoDialog
|
||||
import helium314.keyboard.latin.utils.reloadEnabledSubtypes
|
||||
|
@ -127,7 +130,11 @@ class AdvancedSettingsFragment : SubScreenFragment() {
|
|||
findPreference<Preference>("backup_restore")?.setOnPreferenceClickListener { showBackupRestoreDialog() }
|
||||
|
||||
findPreference<Preference>("custom_symbols_number_layouts")?.setOnPreferenceClickListener {
|
||||
showCustomizeLayoutsDialog()
|
||||
showCustomizeSymbolNumberLayoutsDialog()
|
||||
true
|
||||
}
|
||||
findPreference<Preference>("custom_functional_key_layouts")?.setOnPreferenceClickListener {
|
||||
showCustomizeFunctionalKeyLayoutsDialog()
|
||||
true
|
||||
}
|
||||
}
|
||||
|
@ -145,7 +152,7 @@ class AdvancedSettingsFragment : SubScreenFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun showCustomizeLayoutsDialog() {
|
||||
private fun showCustomizeSymbolNumberLayoutsDialog() {
|
||||
val layoutNames = RawKeyboardParser.symbolAndNumberLayouts.map { it.getStringResourceOrName("layout_", requireContext()) }.toTypedArray()
|
||||
AlertDialog.Builder(requireContext())
|
||||
.setTitle(R.string.customize_symbols_number_layouts)
|
||||
|
@ -158,8 +165,8 @@ class AdvancedSettingsFragment : SubScreenFragment() {
|
|||
}
|
||||
|
||||
private fun customizeSymbolNumberLayout(layoutName: String) {
|
||||
val customLayoutName = getCustomLayoutsDir(requireContext()).list()
|
||||
?.firstOrNull { it.startsWith("$CUSTOM_LAYOUT_PREFIX$layoutName.") }
|
||||
val customLayoutName = getCustomLayoutFiles(requireContext()).map { it.name }
|
||||
.firstOrNull { it.startsWith("$CUSTOM_LAYOUT_PREFIX$layoutName.") }
|
||||
val originalLayout = if (customLayoutName != null) null
|
||||
else {
|
||||
requireContext().assets.list("layouts")?.firstOrNull { it.startsWith("$layoutName.") }
|
||||
|
@ -169,6 +176,32 @@ class AdvancedSettingsFragment : SubScreenFragment() {
|
|||
editCustomLayout(customLayoutName ?: "$CUSTOM_LAYOUT_PREFIX$layoutName.txt", requireContext(), originalLayout, displayName)
|
||||
}
|
||||
|
||||
private fun showCustomizeFunctionalKeyLayoutsDialog() {
|
||||
val list = listOf(CUSTOM_FUNCTIONAL_LAYOUT_NORMAL, CUSTOM_FUNCTIONAL_LAYOUT_SYMBOLS, CUSTOM_FUNCTIONAL_LAYOUT_SYMBOLS_SHIFTED)
|
||||
.map { it.substringBeforeLast(".") }
|
||||
val layoutNames = list.map { it.substringAfter(CUSTOM_LAYOUT_PREFIX).getStringResourceOrName("layout_", requireContext()) }.toTypedArray()
|
||||
AlertDialog.Builder(requireContext())
|
||||
.setTitle(R.string.customize_functional_key_layouts)
|
||||
.setItems(layoutNames) { di, i ->
|
||||
di.dismiss()
|
||||
customizeFunctionalKeysLayout(list[i])
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun customizeFunctionalKeysLayout(layoutName: String) {
|
||||
val customLayoutName = getCustomLayoutFiles(requireContext()).map { it.name }
|
||||
.firstOrNull { it.startsWith("$layoutName.") }
|
||||
val originalLayout = if (customLayoutName != null) null
|
||||
else {
|
||||
val defaultLayoutName = if (Settings.getInstance().isTablet) "functional_keys_tablet.json" else "functional_keys.json"
|
||||
requireContext().assets.open("layouts" + File.separator + defaultLayoutName).reader().readText()
|
||||
}
|
||||
val displayName = layoutName.substringAfter(CUSTOM_LAYOUT_PREFIX).getStringResourceOrName("layout_", requireContext())
|
||||
editCustomLayout(customLayoutName ?: "$layoutName.json", requireContext(), originalLayout, displayName)
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
private fun onClickLoadLibrary(): Boolean {
|
||||
// get architecture for telling user which file to use
|
||||
|
|
|
@ -25,6 +25,7 @@ import helium314.keyboard.latin.R;
|
|||
import helium314.keyboard.latin.RichInputMethodManager;
|
||||
import helium314.keyboard.latin.common.Colors;
|
||||
import helium314.keyboard.latin.permissions.PermissionsUtil;
|
||||
import helium314.keyboard.latin.utils.CustomLayoutUtilsKt;
|
||||
import helium314.keyboard.latin.utils.InputTypeUtils;
|
||||
import helium314.keyboard.latin.utils.Log;
|
||||
import helium314.keyboard.latin.utils.PopupKeysUtilsKt;
|
||||
|
@ -122,6 +123,7 @@ public class SettingsValues {
|
|||
public final SettingsValuesForSuggestion mSettingsValuesForSuggestion;
|
||||
public final boolean mIncognitoModeEnabled;
|
||||
public final boolean mLongPressSymbolsForNumpad;
|
||||
public final boolean mHasCustomFunctionalLayout;
|
||||
|
||||
// User-defined colors
|
||||
public final Colors mColors;
|
||||
|
@ -237,6 +239,7 @@ public class SettingsValues {
|
|||
mSpacingAndPunctuations = new SpacingAndPunctuations(res, mUrlDetectionEnabled);
|
||||
mBottomPaddingScale = prefs.getFloat(Settings.PREF_BOTTOM_PADDING_SCALE, DEFAULT_SIZE_SCALE);
|
||||
mLongPressSymbolsForNumpad = prefs.getBoolean(Settings.PREFS_LONG_PRESS_SYMBOLS_FOR_NUMPAD, false);
|
||||
mHasCustomFunctionalLayout = CustomLayoutUtilsKt.hasCustomFunctionalLayout(selectedSubtype, context);
|
||||
}
|
||||
|
||||
public boolean isApplicationSpecifiedCompletionsOn() {
|
||||
|
|
|
@ -5,6 +5,7 @@ import android.content.Context
|
|||
import android.net.Uri
|
||||
import android.provider.OpenableColumns
|
||||
import android.text.InputType
|
||||
import android.view.inputmethod.InputMethodSubtype
|
||||
import android.widget.EditText
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.widget.doAfterTextChanged
|
||||
|
@ -17,6 +18,7 @@ import helium314.keyboard.keyboard.internal.keyboard_parser.POPUP_KEYS_NORMAL
|
|||
import helium314.keyboard.keyboard.internal.keyboard_parser.RawKeyboardParser
|
||||
import helium314.keyboard.keyboard.internal.keyboard_parser.addLocaleKeyTextsToParams
|
||||
import helium314.keyboard.latin.R
|
||||
import helium314.keyboard.latin.common.Constants
|
||||
import helium314.keyboard.latin.common.FileUtils
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
@ -112,7 +114,7 @@ private fun checkKeys(keys: List<List<Key.KeyParams>>): Boolean {
|
|||
Log.w(TAG, "too many keys in one row")
|
||||
return false
|
||||
}
|
||||
if (keys.any { row -> row.any { ((it.mLabel?.length ?: 0) > 6) } }) {
|
||||
if (keys.any { row -> row.any { ((it.mLabel?.length ?: 0) > 20) } }) {
|
||||
Log.w(TAG, "too long text on key")
|
||||
return false
|
||||
}
|
||||
|
@ -127,10 +129,24 @@ private fun checkKeys(keys: List<List<Key.KeyParams>>): Boolean {
|
|||
return true
|
||||
}
|
||||
|
||||
/** don't rename or delete the file without calling [onCustomLayoutFileListChanged] */
|
||||
fun getCustomLayoutFile(layoutName: String, context: Context) =
|
||||
File(getCustomLayoutsDir(context), layoutName)
|
||||
|
||||
fun getCustomLayoutsDir(context: Context) = File(DeviceProtectedUtils.getFilesDir(context), "layouts")
|
||||
// cache to avoid frequently listing files
|
||||
/** don't rename or delete files without calling [onCustomLayoutFileListChanged] */
|
||||
fun getCustomLayoutFiles(context: Context): List<File> {
|
||||
customLayouts?.let { return it }
|
||||
val layouts = getCustomLayoutsDir(context).listFiles()?.toList() ?: emptyList()
|
||||
customLayouts = layouts
|
||||
return layouts
|
||||
}
|
||||
|
||||
fun onCustomLayoutFileListChanged() {
|
||||
customLayouts = null
|
||||
}
|
||||
|
||||
private fun getCustomLayoutsDir(context: Context) = File(DeviceProtectedUtils.getFilesDir(context), "layouts")
|
||||
|
||||
// undo the name changes in loadCustomLayout when clicking ok
|
||||
fun getLayoutDisplayName(layoutName: String) =
|
||||
|
@ -164,6 +180,7 @@ fun editCustomLayout(layoutName: String, context: Context, startContent: String?
|
|||
file.writeText(content)
|
||||
if (isJson != wasJson) // unlikely to be needed, but better be safe
|
||||
file.renameTo(File(file.absolutePath.substringBeforeLast(".") + "." + if (isJson) "json" else "txt"))
|
||||
onCustomLayoutFileListChanged()
|
||||
KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(context)
|
||||
}
|
||||
}
|
||||
|
@ -173,6 +190,7 @@ fun editCustomLayout(layoutName: String, context: Context, startContent: String?
|
|||
builder.setNeutralButton(R.string.delete) { _, _ ->
|
||||
confirmDialog(context, context.getString(R.string.delete_layout, displayName), context.getString(R.string.delete)) {
|
||||
file.delete()
|
||||
onCustomLayoutFileListChanged()
|
||||
KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(context)
|
||||
}
|
||||
}
|
||||
|
@ -182,6 +200,45 @@ fun editCustomLayout(layoutName: String, context: Context, startContent: String?
|
|||
builder.show()
|
||||
}
|
||||
|
||||
fun hasCustomFunctionalLayout(subtype: InputMethodSubtype, context: Context): Boolean {
|
||||
val anyCustomFunctionalLayout = getCustomFunctionalLayoutName(KeyboardId.ELEMENT_ALPHABET, subtype, context)
|
||||
?: getCustomFunctionalLayoutName(KeyboardId.ELEMENT_SYMBOLS, subtype, context)
|
||||
?: getCustomFunctionalLayoutName(KeyboardId.ELEMENT_SYMBOLS_SHIFTED, subtype, context)
|
||||
return anyCustomFunctionalLayout != null
|
||||
}
|
||||
|
||||
fun getCustomFunctionalLayoutName(elementId: Int, subtype: InputMethodSubtype, context: Context): String? {
|
||||
val customFunctionalLayoutNames = getCustomLayoutFiles(context).filter { it.name.contains("functional") }.map { it.name.substringBeforeLast(".") + "." }
|
||||
if (customFunctionalLayoutNames.isEmpty()) return null
|
||||
val languageTag = subtype.locale().toLanguageTag()
|
||||
val mainLayoutName = subtype.getExtraValueOf(Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET) ?: "qwerty"
|
||||
|
||||
if (elementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED) {
|
||||
findMatchingLayout(customFunctionalLayoutNames.filter { it.startsWith(CUSTOM_FUNCTIONAL_LAYOUT_SYMBOLS_SHIFTED) }, mainLayoutName, languageTag)
|
||||
?.let { return it }
|
||||
}
|
||||
if (elementId == KeyboardId.ELEMENT_SYMBOLS) {
|
||||
findMatchingLayout(customFunctionalLayoutNames.filter { it.startsWith(CUSTOM_FUNCTIONAL_LAYOUT_SYMBOLS) }, mainLayoutName, languageTag)
|
||||
?.let { return it }
|
||||
}
|
||||
return findMatchingLayout(customFunctionalLayoutNames.filter { it.startsWith(CUSTOM_FUNCTIONAL_LAYOUT_NORMAL) }, mainLayoutName, languageTag)
|
||||
}
|
||||
|
||||
// todo (when adding custom layouts per locale or main layout): adjust mainLayoutName for custom layouts?
|
||||
// remove language tag and file ending (currently name is e.g. custom.en-US.abcdfdsg3.json, and we could use abcdfdsg3 only)
|
||||
// this way, custom layouts with same name could use same custom functional layouts
|
||||
// currently there is no way to set the language tag or main layout name, so changes don't break backwards compatibility
|
||||
private fun findMatchingLayout(layoutNames: List<String>, mainLayoutName: String, languageTag: String): String? {
|
||||
// first find layout with matching locale and main layout
|
||||
return layoutNames.firstOrNull { it.endsWith(".$languageTag.$mainLayoutName.") }
|
||||
// then find matching main layout
|
||||
?: layoutNames.firstOrNull { it.endsWith(".$mainLayoutName.") }
|
||||
// then find matching language
|
||||
?: layoutNames.firstOrNull { it.endsWith(".$languageTag.") }
|
||||
// then find "normal" functional layout (make use of the '.' separator
|
||||
?: layoutNames.firstOrNull { it.count { it == '.' } == 2 }
|
||||
}
|
||||
|
||||
private fun encodeBase36(string: String): String = BigInteger(string.toByteArray()).toString(36)
|
||||
|
||||
private fun decodeBase36(string: String) = BigInteger(string, 36).toByteArray().decodeToString()
|
||||
|
@ -189,3 +246,8 @@ private fun decodeBase36(string: String) = BigInteger(string, 36).toByteArray().
|
|||
// this goes into prefs and file names, so do not change!
|
||||
const val CUSTOM_LAYOUT_PREFIX = "custom."
|
||||
private const val TAG = "CustomLayoutUtils"
|
||||
private var customLayouts: List<File>? = null
|
||||
|
||||
const val CUSTOM_FUNCTIONAL_LAYOUT_SYMBOLS_SHIFTED = "${CUSTOM_LAYOUT_PREFIX}functional_keys_symbols_shifted."
|
||||
const val CUSTOM_FUNCTIONAL_LAYOUT_SYMBOLS = "${CUSTOM_LAYOUT_PREFIX}functional_keys_symbols."
|
||||
const val CUSTOM_FUNCTIONAL_LAYOUT_NORMAL = "${CUSTOM_LAYOUT_PREFIX}functional_keys."
|
||||
|
|
|
@ -245,12 +245,12 @@ private fun loadResourceSubtypes(resources: Resources) {
|
|||
private fun removeInvalidCustomSubtypes(context: Context) {
|
||||
val prefs = DeviceProtectedUtils.getSharedPreferences(context)
|
||||
val additionalSubtypes = Settings.readPrefAdditionalSubtypes(prefs, context.resources).split(";")
|
||||
val customSubtypeFiles by lazy { getCustomLayoutsDir(context).list() }
|
||||
val customSubtypeFiles by lazy { getCustomLayoutFiles(context).map { it.name } }
|
||||
val subtypesToRemove = mutableListOf<String>()
|
||||
additionalSubtypes.forEach {
|
||||
val name = it.substringAfter(":").substringBefore(":")
|
||||
if (!name.startsWith(CUSTOM_LAYOUT_PREFIX)) return@forEach
|
||||
if (customSubtypeFiles?.contains(name) != true)
|
||||
if (name !in customSubtypeFiles)
|
||||
subtypesToRemove.add(it)
|
||||
}
|
||||
if (subtypesToRemove.isEmpty()) return
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue