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) { public void switchToSubtype(InputMethodSubtype subtype) {
Log.i("test1", "switch to "+subtype.getLocale());
mLatinIME.switchToSubtype(subtype); 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.clear()
sortedSubtypes.addAll(list) sortedSubtypes.addAll(list)
adapter.disableSwitches = disableSwitches adapter.onlySystemLocales = onlySystemLocales
adapter.list = sortedSubtypes adapter.list = sortedSubtypes
} }
@ -60,7 +60,7 @@ class LanguageFilterListPreference(context: Context, attrs: AttributeSet) : Pref
@Suppress("Deprecation") @Suppress("Deprecation")
class LanguageAdapter(list: List<MutableList<SubtypeInfo>> = listOf(), context: Context) : class LanguageAdapter(list: List<MutableList<SubtypeInfo>> = listOf(), context: Context) :
RecyclerView.Adapter<LanguageAdapter.ViewHolder>() { RecyclerView.Adapter<LanguageAdapter.ViewHolder>() {
var disableSwitches = false var onlySystemLocales = false
private val prefs = DeviceProtectedUtils.getSharedPreferences(context) private val prefs = DeviceProtectedUtils.getSharedPreferences(context)
var fragment: LanguageSettingsFragment? = null var fragment: LanguageSettingsFragment? = null
@ -105,31 +105,31 @@ class LanguageAdapter(list: List<MutableList<SubtypeInfo>> = listOf(), context:
}) })
} }
text = sb.toString() text = sb.toString()
if (text.isBlank()) isGone = true if (onlySystemLocales || text.isBlank()) isGone = true
else isVisible = true else isVisible = true
} }
view.findViewById<Switch>(R.id.language_switch).apply { 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! // 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 // disable the change listener when setting the checked status on scroll
// so it's only triggered on user interactions // so it's only triggered on user interactions
setOnCheckedChangeListener(null) setOnCheckedChangeListener(null)
isChecked = disableSwitches || infos.any { it.isEnabled } isChecked = onlySystemLocales || infos.any { it.isEnabled }
setOnCheckedChangeListener { _, b -> setOnCheckedChangeListener { _, b ->
if (b) { if (b) {
if (infos.size == 1) { if (infos.size == 1) {
addEnabledSubtype(prefs, infos.first().subtype) addEnabledSubtype(prefs, infos.first().subtype)
infos.single().isEnabled = true infos.single().isEnabled = true
} else { } else {
LanguageSettingsDialog(view.context, infos, fragment, disableSwitches, { setupDetailsTextAndSwitch() }).show() LanguageSettingsDialog(view.context, infos, fragment, onlySystemLocales, { setupDetailsTextAndSwitch() }).show()
} }
} else { } else {
if (infos.size == 1) { if (infos.size == 1) {
removeEnabledSubtype(prefs, infos.first().subtype) removeEnabledSubtype(prefs, infos.first().subtype)
infos.single().isEnabled = false infos.single().isEnabled = false
} else { } 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<TextView>(R.id.language_name).text = infos.first().displayName
view.findViewById<LinearLayout>(R.id.language_text).setOnClickListener { 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() setupDetailsTextAndSwitch()
} }
} }
} }

View file

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

View file

@ -2,6 +2,7 @@ package org.dslul.openboard.inputmethod.latin.settings
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences
import android.content.res.Resources import android.content.res.Resources
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
@ -29,12 +30,13 @@ class LanguageSettingsFragment : SubScreenFragment() {
enabledSubtypes.addAll(getExplicitlyEnabledSubtypes()) enabledSubtypes.addAll(getExplicitlyEnabledSubtypes())
systemLocales.addAll(getSystemLocales()) systemLocales.addAll(getSystemLocales())
val systemLocalesSwitch = findPreference(Settings.PREF_USE_SYSTEM_LOCALES) as TwoStatePreference loadSubtypes()
systemLocalesSwitch.setOnPreferenceChangeListener { _, b ->
loadSubtypes(b as Boolean)
true
} }
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() { override fun onResume() {
@ -47,7 +49,8 @@ class LanguageSettingsFragment : SubScreenFragment() {
languageFilterListPreference.setSettingsFragment(null) languageFilterListPreference.setSettingsFragment(null)
} }
private fun loadSubtypes(systemOnly: Boolean) { private fun loadSubtypes() {
val systemOnly = (findPreference(Settings.PREF_USE_SYSTEM_LOCALES) as TwoStatePreference).isChecked
sortedSubtypes.clear() sortedSubtypes.clear()
val allSubtypes = getAllAvailableSubtypes().toMutableList() val allSubtypes = getAllAvailableSubtypes().toMutableList()
// maybe make use of the map used by SubtypeSettings for performance reasons? // 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() 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 { fun getSelectedSubtype(prefs: SharedPreferences): InputMethodSubtype {
require(initialized) require(initialized)
val subtypeString = prefs.getString(Settings.PREF_SELECTED_INPUT_STYLE, "")!!.split(LOCALE_LAYOUT_SEPARATOR) 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) } val subtypes = if (prefs.getBoolean(Settings.PREF_USE_SYSTEM_LOCALES, true)) getDefaultEnabledSubtypes()
?: enabledSubtypes.firstOrNull() else enabledSubtypes
val subtype = subtypes.firstOrNull { subtypeString.first() == it.locale && subtypeString.last() == SubtypeLocaleUtils.getKeyboardLayoutSetName(it) }
?: subtypes.firstOrNull()
if (subtype == null) { if (subtype == null) {
val defaultSubtypes = getDefaultEnabledSubtypes() val defaultSubtypes = getDefaultEnabledSubtypes()
return defaultSubtypes.firstOrNull { subtypeString.first() == it.locale && subtypeString.last() == SubtypeLocaleUtils.getKeyboardLayoutSetName(it) } return defaultSubtypes.firstOrNull { subtypeString.first() == it.locale && subtypeString.last() == SubtypeLocaleUtils.getKeyboardLayoutSetName(it) }
@ -113,6 +130,7 @@ fun reloadSystemLocales(context: Context) {
val locale = localeList[it] val locale = localeList[it]
if (locale != null) systemLocales.add(locale) if (locale != null) systemLocales.add(locale)
} }
systemSubtypes.clear()
} }
fun getSystemLocales(): List<Locale> { fun getSystemLocales(): List<Locale> {
@ -135,16 +153,20 @@ fun init(context: Context) {
} }
private fun getDefaultEnabledSubtypes(): List<InputMethodSubtype> { 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 localeString = locale.toString()
val subtypes = resourceSubtypesByLocale[localeString] val subtypesOfLocale = resourceSubtypesByLocale[localeString]
?: resourceSubtypesByLocale[localeString.substringBefore("_")] // fall back to language match ?: 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 // hardcoded fallback for weird cases
return listOf(resourceSubtypesByLocale["en_US"]!!.first()) systemSubtypes.add(resourceSubtypesByLocale["en_US"]!!.first())
return inputMethodSubtypes } else {
systemSubtypes.addAll(subtypes)
}
return systemSubtypes
} }
private fun InputMethodSubtype.prefString() = private fun InputMethodSubtype.prefString() =
@ -219,6 +241,7 @@ private val enabledSubtypes = mutableListOf<InputMethodSubtype>()
private val resourceSubtypesByLocale = LinkedHashMap<String, MutableList<InputMethodSubtype>>(100) private val resourceSubtypesByLocale = LinkedHashMap<String, MutableList<InputMethodSubtype>>(100)
private val additionalSubtypes = mutableListOf<InputMethodSubtype>() private val additionalSubtypes = mutableListOf<InputMethodSubtype>()
private val systemLocales = mutableListOf<Locale>() private val systemLocales = mutableListOf<Locale>()
private val systemSubtypes = mutableListOf<InputMethodSubtype>()
private const val SUBTYPE_SEPARATOR = ";" private const val SUBTYPE_SEPARATOR = ";"
private const val LOCALE_LAYOUT_SEPARATOR = ":" private const val LOCALE_LAYOUT_SEPARATOR = ":"