fix issues with language settings

don't show subtypes when using system locales
  this may not be ideal, but avoids dealing with many edge cases and is consistent with old behavior
don't return a selected subtype when it's not enabled
This commit is contained in:
Helium314 2023-08-27 09:41:23 +02:00
parent 82a5e11fd0
commit 0dc4ef8805
5 changed files with 59 additions and 39 deletions

View file

@ -604,7 +604,6 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
}
public void switchToSubtype(InputMethodSubtype subtype) {
Log.i("test1", "switch to "+subtype.getLocale());
mLatinIME.switchToSubtype(subtype);
}
}

View file

@ -48,10 +48,10 @@ class LanguageFilterListPreference(context: Context, attrs: AttributeSet) : Pref
}
}
fun setLanguages(list: Collection<MutableList<SubtypeInfo>>, disableSwitches: Boolean) {
fun setLanguages(list: Collection<MutableList<SubtypeInfo>>, onlySystemLocales: Boolean) {
sortedSubtypes.clear()
sortedSubtypes.addAll(list)
adapter.disableSwitches = disableSwitches
adapter.onlySystemLocales = onlySystemLocales
adapter.list = sortedSubtypes
}
@ -60,7 +60,7 @@ class LanguageFilterListPreference(context: Context, attrs: AttributeSet) : Pref
@Suppress("Deprecation")
class LanguageAdapter(list: List<MutableList<SubtypeInfo>> = listOf(), context: Context) :
RecyclerView.Adapter<LanguageAdapter.ViewHolder>() {
var disableSwitches = false
var onlySystemLocales = false
private val prefs = DeviceProtectedUtils.getSharedPreferences(context)
var fragment: LanguageSettingsFragment? = null
@ -105,31 +105,31 @@ class LanguageAdapter(list: List<MutableList<SubtypeInfo>> = listOf(), context:
})
}
text = sb.toString()
if (text.isBlank()) isGone = true
if (onlySystemLocales || text.isBlank()) isGone = true
else isVisible = true
}
view.findViewById<Switch>(R.id.language_switch).apply {
isEnabled = !disableSwitches && infos.size == 1
isEnabled = !onlySystemLocales && infos.size == 1
// take care: isChecked changes if the language is scrolled out of view and comes back!
// disable the change listener when setting the checked status on scroll
// so it's only triggered on user interactions
setOnCheckedChangeListener(null)
isChecked = disableSwitches || infos.any { it.isEnabled }
isChecked = onlySystemLocales || infos.any { it.isEnabled }
setOnCheckedChangeListener { _, b ->
if (b) {
if (infos.size == 1) {
addEnabledSubtype(prefs, infos.first().subtype)
infos.single().isEnabled = true
} else {
LanguageSettingsDialog(view.context, infos, fragment, disableSwitches, { setupDetailsTextAndSwitch() }).show()
LanguageSettingsDialog(view.context, infos, fragment, onlySystemLocales, { setupDetailsTextAndSwitch() }).show()
}
} else {
if (infos.size == 1) {
removeEnabledSubtype(prefs, infos.first().subtype)
infos.single().isEnabled = false
} else {
LanguageSettingsDialog(view.context, infos, fragment, disableSwitches, { setupDetailsTextAndSwitch() }).show()
LanguageSettingsDialog(view.context, infos, fragment, onlySystemLocales, { setupDetailsTextAndSwitch() }).show()
}
}
}
@ -138,10 +138,9 @@ class LanguageAdapter(list: List<MutableList<SubtypeInfo>> = listOf(), context:
view.findViewById<TextView>(R.id.language_name).text = infos.first().displayName
view.findViewById<LinearLayout>(R.id.language_text).setOnClickListener {
LanguageSettingsDialog(view.context, infos, fragment, disableSwitches, { setupDetailsTextAndSwitch() }).show()
LanguageSettingsDialog(view.context, infos, fragment, onlySystemLocales, { setupDetailsTextAndSwitch() }).show()
}
setupDetailsTextAndSwitch()
}
}
}

View file

@ -29,7 +29,7 @@ class LanguageSettingsDialog(
context: Context,
private val subtypes: MutableList<SubtypeInfo>,
private val fragment: LanguageSettingsFragment?,
private val disableSwitches: Boolean,
private val onlySystemLocales: Boolean,
private val onSubtypesChanged: () -> Unit
) : AlertDialog(ContextThemeWrapper(context, R.style.platformDialogTheme)), LanguageSettingsFragment.Listener {
private val context = ContextThemeWrapper(context, R.style.platformDialogTheme)
@ -46,6 +46,9 @@ class LanguageSettingsDialog(
dismiss()
}
if (onlySystemLocales)
view.findViewById<View>(R.id.subtypes).isGone = true
else
fillSubtypesView(view.findViewById(R.id.subtypes))
fillSecondaryLocaleView(view.findViewById(R.id.secondary_languages))
fillDictionariesView(view.findViewById(R.id.dictionaries))
@ -73,12 +76,9 @@ class LanguageSettingsDialog(
di.dismiss()
val newSubtype = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(mainLocaleString, layouts[i])
val newSubtypeInfo = newSubtype.toSubtypeInfo(mainLocale, context.resources, true) // enabled by default, because why else add them
addSubtypeToView(newSubtypeInfo, subtypesView)
val oldAdditionalSubtypesString = Settings.readPrefAdditionalSubtypes(prefs, context.resources)
val oldAdditionalSubtypes = AdditionalSubtypeUtils.createAdditionalSubtypesArray(oldAdditionalSubtypesString).toHashSet()
val newAdditionalSubtypesString = AdditionalSubtypeUtils.createPrefSubtypes((oldAdditionalSubtypes + newSubtype).toTypedArray())
Settings.writePrefAdditionalSubtypes(prefs, newAdditionalSubtypesString)
addAdditionalSubtype(prefs, context.resources, newSubtype)
addEnabledSubtype(prefs, newSubtype)
addSubtypeToView(newSubtypeInfo, subtypesView)
subtypes.add(newSubtypeInfo)
onSubtypesChanged()
}
@ -102,7 +102,7 @@ class LanguageSettingsDialog(
row.findViewById<View>(R.id.language_details).isGone = true
row.findViewById<Switch>(R.id.language_switch).apply {
isChecked = subtype.isEnabled
isEnabled = !disableSwitches
isEnabled = !onlySystemLocales
setOnCheckedChangeListener { _, b ->
if (b)
addEnabledSubtype(prefs, subtype.subtype)
@ -121,11 +121,7 @@ class LanguageSettingsDialog(
subtypesView.removeView(row)
subtypes.remove(subtype)
val oldAdditionalSubtypesString = Settings.readPrefAdditionalSubtypes(prefs, context.resources)
val oldAdditionalSubtypes = AdditionalSubtypeUtils.createAdditionalSubtypesArray(oldAdditionalSubtypesString)
val newAdditionalSubtypes = oldAdditionalSubtypes.filter { it != subtype.subtype }
val newAdditionalSubtypesString = AdditionalSubtypeUtils.createPrefSubtypes(newAdditionalSubtypes.toTypedArray())
Settings.writePrefAdditionalSubtypes(prefs, newAdditionalSubtypesString)
removeAdditionalSubtype(prefs, context.resources, subtype.subtype)
removeEnabledSubtype(prefs, subtype.subtype)
onSubtypesChanged()
}

View file

@ -2,6 +2,7 @@ package org.dslul.openboard.inputmethod.latin.settings
import android.app.Activity
import android.content.Intent
import android.content.SharedPreferences
import android.content.res.Resources
import android.net.Uri
import android.os.Bundle
@ -29,12 +30,13 @@ class LanguageSettingsFragment : SubScreenFragment() {
enabledSubtypes.addAll(getExplicitlyEnabledSubtypes())
systemLocales.addAll(getSystemLocales())
val systemLocalesSwitch = findPreference(Settings.PREF_USE_SYSTEM_LOCALES) as TwoStatePreference
systemLocalesSwitch.setOnPreferenceChangeListener { _, b ->
loadSubtypes(b as Boolean)
true
loadSubtypes()
}
loadSubtypes(systemLocalesSwitch.isChecked)
override fun onSharedPreferenceChanged(prefs: SharedPreferences, key: String) {
super.onSharedPreferenceChanged(prefs, key)
if (key == Settings.PREF_USE_SYSTEM_LOCALES)
loadSubtypes()
}
override fun onResume() {
@ -47,7 +49,8 @@ class LanguageSettingsFragment : SubScreenFragment() {
languageFilterListPreference.setSettingsFragment(null)
}
private fun loadSubtypes(systemOnly: Boolean) {
private fun loadSubtypes() {
val systemOnly = (findPreference(Settings.PREF_USE_SYSTEM_LOCALES) as TwoStatePreference).isChecked
sortedSubtypes.clear()
val allSubtypes = getAllAvailableSubtypes().toMutableList()
// maybe make use of the map used by SubtypeSettings for performance reasons?

View file

@ -75,11 +75,28 @@ fun removeEnabledSubtype(prefs: SharedPreferences, subtype: InputMethodSubtype)
RichInputMethodManager.getInstance().refreshSubtypeCaches()
}
fun addAdditionalSubtype(prefs: SharedPreferences, resources: Resources, subtype: InputMethodSubtype) {
val oldAdditionalSubtypesString = Settings.readPrefAdditionalSubtypes(prefs, resources)
val oldAdditionalSubtypes = AdditionalSubtypeUtils.createAdditionalSubtypesArray(oldAdditionalSubtypesString).toSet()
val newAdditionalSubtypesString = AdditionalSubtypeUtils.createPrefSubtypes((oldAdditionalSubtypes + subtype).toTypedArray())
Settings.writePrefAdditionalSubtypes(prefs, newAdditionalSubtypesString)
}
fun removeAdditionalSubtype(prefs: SharedPreferences, resources: Resources, subtype: InputMethodSubtype) {
val oldAdditionalSubtypesString = Settings.readPrefAdditionalSubtypes(prefs, resources)
val oldAdditionalSubtypes = AdditionalSubtypeUtils.createAdditionalSubtypesArray(oldAdditionalSubtypesString)
val newAdditionalSubtypes = oldAdditionalSubtypes.filter { it != subtype }
val newAdditionalSubtypesString = AdditionalSubtypeUtils.createPrefSubtypes(newAdditionalSubtypes.toTypedArray())
Settings.writePrefAdditionalSubtypes(prefs, newAdditionalSubtypesString)
}
fun getSelectedSubtype(prefs: SharedPreferences): InputMethodSubtype {
require(initialized)
val subtypeString = prefs.getString(Settings.PREF_SELECTED_INPUT_STYLE, "")!!.split(LOCALE_LAYOUT_SEPARATOR)
val subtype = enabledSubtypes.firstOrNull { subtypeString.first() == it.locale && subtypeString.last() == SubtypeLocaleUtils.getKeyboardLayoutSetName(it) }
?: enabledSubtypes.firstOrNull()
val subtypes = if (prefs.getBoolean(Settings.PREF_USE_SYSTEM_LOCALES, true)) getDefaultEnabledSubtypes()
else enabledSubtypes
val subtype = subtypes.firstOrNull { subtypeString.first() == it.locale && subtypeString.last() == SubtypeLocaleUtils.getKeyboardLayoutSetName(it) }
?: subtypes.firstOrNull()
if (subtype == null) {
val defaultSubtypes = getDefaultEnabledSubtypes()
return defaultSubtypes.firstOrNull { subtypeString.first() == it.locale && subtypeString.last() == SubtypeLocaleUtils.getKeyboardLayoutSetName(it) }
@ -113,6 +130,7 @@ fun reloadSystemLocales(context: Context) {
val locale = localeList[it]
if (locale != null) systemLocales.add(locale)
}
systemSubtypes.clear()
}
fun getSystemLocales(): List<Locale> {
@ -135,16 +153,20 @@ fun init(context: Context) {
}
private fun getDefaultEnabledSubtypes(): List<InputMethodSubtype> {
val inputMethodSubtypes = systemLocales.mapNotNull { locale ->
if (systemSubtypes.isNotEmpty()) return systemSubtypes
val subtypes = systemLocales.mapNotNull { locale ->
val localeString = locale.toString()
val subtypes = resourceSubtypesByLocale[localeString]
val subtypesOfLocale = resourceSubtypesByLocale[localeString]
?: resourceSubtypesByLocale[localeString.substringBefore("_")] // fall back to language match
subtypes?.firstOrNull() // todo: maybe set default for some languages with multiple resource subtypes?
subtypesOfLocale?.firstOrNull()
}
if (inputMethodSubtypes.isEmpty())
if (subtypes.isEmpty()) {
// hardcoded fallback for weird cases
return listOf(resourceSubtypesByLocale["en_US"]!!.first())
return inputMethodSubtypes
systemSubtypes.add(resourceSubtypesByLocale["en_US"]!!.first())
} else {
systemSubtypes.addAll(subtypes)
}
return systemSubtypes
}
private fun InputMethodSubtype.prefString() =
@ -219,6 +241,7 @@ private val enabledSubtypes = mutableListOf<InputMethodSubtype>()
private val resourceSubtypesByLocale = LinkedHashMap<String, MutableList<InputMethodSubtype>>(100)
private val additionalSubtypes = mutableListOf<InputMethodSubtype>()
private val systemLocales = mutableListOf<Locale>()
private val systemSubtypes = mutableListOf<InputMethodSubtype>()
private const val SUBTYPE_SEPARATOR = ";"
private const val LOCALE_LAYOUT_SEPARATOR = ":"