make language settings work nicely again

now actually it's not part of preferences any more, but looks the same
This commit is contained in:
Helium314 2023-09-01 19:49:37 +02:00
parent 71187f4b32
commit 50e175509b
10 changed files with 83 additions and 75 deletions

View file

@ -16,7 +16,7 @@
package org.dslul.openboard.inputmethod.latin; package org.dslul.openboard.inputmethod.latin;
import static org.dslul.openboard.inputmethod.latin.settings.LanguageSettingsFragmentKt.USER_DICTIONARY_SUFFIX; import static org.dslul.openboard.inputmethod.latin.settings.LanguageFakeSettingsFragmentKt.USER_DICTIONARY_SUFFIX;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;

View file

@ -6,51 +6,76 @@ import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodSubtype import android.view.inputmethod.InputMethodSubtype
import androidx.preference.SwitchPreferenceCompat import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SwitchCompat
import androidx.core.content.edit
import androidx.fragment.app.Fragment
import org.dslul.openboard.inputmethod.latin.R import org.dslul.openboard.inputmethod.latin.R
import org.dslul.openboard.inputmethod.latin.common.LocaleUtils import org.dslul.openboard.inputmethod.latin.common.LocaleUtils
import org.dslul.openboard.inputmethod.latin.utils.DeviceProtectedUtils
import org.dslul.openboard.inputmethod.latin.utils.DictionaryInfoUtils import org.dslul.openboard.inputmethod.latin.utils.DictionaryInfoUtils
import org.dslul.openboard.inputmethod.latin.utils.SubtypeLocaleUtils import org.dslul.openboard.inputmethod.latin.utils.SubtypeLocaleUtils
import org.dslul.openboard.inputmethod.latin.utils.getDictionaryLocales import org.dslul.openboard.inputmethod.latin.utils.getDictionaryLocales
import java.util.Locale import java.util.*
class LanguageSettingsFragment : SubScreenFragment() {
// not a SettingsFragment, because with androidx.preferences it's very complicated or
// impossible to have the languages RecyclerView scrollable (this way it works nicely out of the box)
class LanguageFakeSettingsFragment : Fragment(R.layout.language_fake_settings) {
private val sortedSubtypes = LinkedHashMap<String, MutableList<SubtypeInfo>>() private val sortedSubtypes = LinkedHashMap<String, MutableList<SubtypeInfo>>()
private val enabledSubtypes = mutableListOf<InputMethodSubtype>() private val enabledSubtypes = mutableListOf<InputMethodSubtype>()
private val systemLocales = mutableListOf<Locale>() private val systemLocales = mutableListOf<Locale>()
private val languageFilterListPreference by lazy { findPreference<LanguageFilterListPreference>("pref_language_filter")!! } private lateinit var languageFilterList: LanguageFilterListFakePreference
private lateinit var sharedPreferences: SharedPreferences
private lateinit var systemOnlySwitch: SwitchCompat
private val dictionaryLocales by lazy { getDictionaryLocales(requireContext()).mapTo(HashSet()) { it.languageConsideringZZ() } } private val dictionaryLocales by lazy { getDictionaryLocales(requireContext()).mapTo(HashSet()) { it.languageConsideringZZ() } }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
addPreferencesFromResource(R.xml.prefs_screen_languages) sharedPreferences = DeviceProtectedUtils.getSharedPreferences(requireContext())
SubtypeLocaleUtils.init(requireContext()) SubtypeLocaleUtils.init(requireContext())
enabledSubtypes.addAll(getEnabledSubtypes(sharedPreferences)) enabledSubtypes.addAll(getEnabledSubtypes(sharedPreferences))
systemLocales.addAll(getSystemLocales()) systemLocales.addAll(getSystemLocales())
loadSubtypes()
} }
override fun onSharedPreferenceChanged(prefs: SharedPreferences, key: String) { override fun onCreateView(
super.onSharedPreferenceChanged(prefs, key) inflater: LayoutInflater,
if (key == Settings.PREF_USE_SYSTEM_LOCALES) container: ViewGroup?,
loadSubtypes() savedInstanceState: Bundle?
): View? {
val view = super.onCreateView(inflater, container, savedInstanceState) ?: return null
systemOnlySwitch = view.findViewById(R.id.language_switch)
systemOnlySwitch.isChecked = sharedPreferences.getBoolean(Settings.PREF_USE_SYSTEM_LOCALES, true)
systemOnlySwitch.setOnCheckedChangeListener { _, b ->
sharedPreferences.edit { putBoolean(Settings.PREF_USE_SYSTEM_LOCALES, b) }
loadSubtypes(b)
}
languageFilterList = LanguageFilterListFakePreference(view.findViewById(R.id.search_field), view.findViewById(R.id.language_list))
loadSubtypes(systemOnlySwitch.isChecked)
return view
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
languageFilterListPreference.setSettingsFragment(this) languageFilterList.setSettingsFragment(this)
val activity: Activity? = activity
if (activity is AppCompatActivity) {
val actionBar = activity.supportActionBar ?: return
actionBar.setTitle(R.string.language_selection_title)
}
} }
override fun onPause() { override fun onPause() {
super.onPause() super.onPause()
languageFilterListPreference.setSettingsFragment(null) languageFilterList.setSettingsFragment(null)
} }
private fun loadSubtypes() { private fun loadSubtypes(systemOnly: Boolean) {
val systemOnly = findPreference<SwitchPreferenceCompat>(Settings.PREF_USE_SYSTEM_LOCALES)!!.isChecked
sortedSubtypes.clear() sortedSubtypes.clear()
// list of all subtypes, any subtype added to sortedSubtypes will be removed to avoid duplicates // list of all subtypes, any subtype added to sortedSubtypes will be removed to avoid duplicates
val allSubtypes = getAllAvailableSubtypes().toMutableList() val allSubtypes = getAllAvailableSubtypes().toMutableList()
@ -108,7 +133,7 @@ class LanguageSettingsFragment : SubScreenFragment() {
allSubtypes.removeAll(enabledSubtypes) allSubtypes.removeAll(enabledSubtypes)
if (systemOnly) { // don't add anything else if (systemOnly) { // don't add anything else
languageFilterListPreference.setLanguages(sortedSubtypes.values, systemOnly) languageFilterList.setLanguages(sortedSubtypes.values, systemOnly)
return return
} }
@ -133,7 +158,7 @@ class LanguageSettingsFragment : SubScreenFragment() {
}.addToSortedSubtypes() }.addToSortedSubtypes()
// set languages // set languages
languageFilterListPreference.setLanguages(sortedSubtypes.values, systemOnly) languageFilterList.setLanguages(sortedSubtypes.values, systemOnly)
} }
private fun InputMethodSubtype.toSubtypeInfo(locale: Locale, isEnabled: Boolean = false) = private fun InputMethodSubtype.toSubtypeInfo(locale: Locale, isEnabled: Boolean = false) =

View file

@ -1,80 +1,40 @@
package org.dslul.openboard.inputmethod.latin.settings package org.dslul.openboard.inputmethod.latin.settings
import android.content.Context import android.content.Context
import android.graphics.Rect
import android.graphics.Typeface import android.graphics.Typeface
import android.os.Build
import android.text.Spannable import android.text.Spannable
import android.text.SpannableString import android.text.SpannableString
import android.text.SpannableStringBuilder import android.text.SpannableStringBuilder
import android.text.style.StyleSpan import android.text.style.StyleSpan
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.* import android.widget.*
import androidx.core.view.doOnLayout
import androidx.core.view.isGone import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.widget.doAfterTextChanged import androidx.core.widget.doAfterTextChanged
import androidx.preference.Preference
import androidx.preference.PreferenceGroupAdapter
import androidx.preference.PreferenceViewHolder
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import org.dslul.openboard.inputmethod.latin.R import org.dslul.openboard.inputmethod.latin.R
import org.dslul.openboard.inputmethod.latin.common.LocaleUtils import org.dslul.openboard.inputmethod.latin.common.LocaleUtils
import org.dslul.openboard.inputmethod.latin.utils.* import org.dslul.openboard.inputmethod.latin.utils.DeviceProtectedUtils
import org.dslul.openboard.inputmethod.latin.utils.SubtypeLocaleUtils
import org.dslul.openboard.inputmethod.latin.utils.showMissingDictionaryDialog
import org.dslul.openboard.inputmethod.latin.utils.toLocale
class LanguageFilterListPreference(context: Context, attrs: AttributeSet) : Preference(context, attrs) { class LanguageFilterListFakePreference(searchField: EditText, recyclerView: RecyclerView) {
private lateinit var preferenceView: View private val adapter = LanguageAdapter(emptyList(), recyclerView.context)
private val adapter = LanguageAdapter(emptyList(), context)
private val sortedSubtypes = mutableListOf<MutableList<SubtypeInfo>>() private val sortedSubtypes = mutableListOf<MutableList<SubtypeInfo>>()
fun setSettingsFragment(newFragment: LanguageSettingsFragment?) { fun setSettingsFragment(newFragment: LanguageFakeSettingsFragment?) {
adapter.fragment = newFragment adapter.fragment = newFragment
} }
override fun onBindViewHolder(holder: PreferenceViewHolder) { init {
super.onBindViewHolder(holder) recyclerView.adapter = adapter
preferenceView = holder.itemView
/* val a = holder.bindingAdapter as PreferenceGroupAdapter
preferenceManager.preferenceScreen
*/
preferenceView.findViewById<RecyclerView>(R.id.language_list)?.adapter = adapter
val searchField = preferenceView.findViewById<EditText>(R.id.search_field)!!
searchField.doAfterTextChanged { text -> searchField.doAfterTextChanged { text ->
adapter.list = sortedSubtypes.filter { it.first().displayName.startsWith(text.toString(), ignoreCase = true) } adapter.list = sortedSubtypes.filter { it.first().displayName.startsWith(text.toString(), ignoreCase = true) }
} }
// todo: why the fuck isn't the recyclerview scrolling after switching to androidx?
// looks like nothing can scroll inside!
// maybe just make it a list and add a note to the changelog with request for help
// first play around with weirdly nested (Nested)ScrollViews and layouts
val recycler = preferenceView.findViewById<RecyclerView>(R.id.language_list)
// recycler.isScrollContainer = true
// recycler.isNestedScrollingEnabled = true
// preferenceView.isScrollContainer = true
/* val windowFrame = Rect()
preferenceView.getWindowVisibleDisplayFrame(windowFrame) // rect the app has, we want the bottom (above screen bottom/navbar/keyboard)
val globalRect = Rect()
preferenceView.getGlobalVisibleRect(globalRect) // rect the view takes, we want the top (below the system language preference)
val newHeight = windowFrame.bottom - globalRect.top - preferenceView.findViewById<View>(R.id.search_container).height
preferenceView.layoutParams = preferenceView.layoutParams.apply { height = newHeight -250 }*/
/* preferenceView.doOnLayout {
// set correct height for recycler view, so there is no scrolling of the outside view happening
// not sure how, but probably this can also be achieved in xml...
val windowFrame = Rect()
it.getWindowVisibleDisplayFrame(windowFrame) // rect the app has, we want the bottom (above screen bottom/navbar/keyboard)
val globalRect = Rect()
it.getGlobalVisibleRect(globalRect) // rect the view takes, we want the top (below the system language preference)
val recycler = it.findViewById<RecyclerView>(R.id.language_list)
val newHeight = windowFrame.bottom - globalRect.top - it.findViewById<View>(R.id.search_container).height
if (newHeight != recycler.layoutParams.height)
recycler.layoutParams = recycler.layoutParams.apply { height = newHeight }
}*/
} }
fun setLanguages(list: Collection<MutableList<SubtypeInfo>>, onlySystemLocales: Boolean) { fun setLanguages(list: Collection<MutableList<SubtypeInfo>>, onlySystemLocales: Boolean) {
@ -90,7 +50,7 @@ class LanguageAdapter(list: List<MutableList<SubtypeInfo>> = listOf(), context:
RecyclerView.Adapter<LanguageAdapter.ViewHolder>() { RecyclerView.Adapter<LanguageAdapter.ViewHolder>() {
var onlySystemLocales = false var onlySystemLocales = false
private val prefs = DeviceProtectedUtils.getSharedPreferences(context) private val prefs = DeviceProtectedUtils.getSharedPreferences(context)
var fragment: LanguageSettingsFragment? = null var fragment: LanguageFakeSettingsFragment? = null
var list: List<MutableList<SubtypeInfo>> = list var list: List<MutableList<SubtypeInfo>> = list
set(value) { set(value) {

View file

@ -23,10 +23,10 @@ import java.util.*
class LanguageSettingsDialog( class LanguageSettingsDialog(
context: Context, context: Context,
private val infos: MutableList<SubtypeInfo>, private val infos: MutableList<SubtypeInfo>,
private val fragment: LanguageSettingsFragment?, private val fragment: LanguageFakeSettingsFragment?,
private val onlySystemLocales: Boolean, private val onlySystemLocales: Boolean,
private val onSubtypesChanged: () -> Unit private val onSubtypesChanged: () -> Unit
) : AlertDialog(context), LanguageSettingsFragment.Listener { ) : AlertDialog(context), LanguageFakeSettingsFragment.Listener {
private val prefs = DeviceProtectedUtils.getSharedPreferences(context)!! private val prefs = DeviceProtectedUtils.getSharedPreferences(context)!!
private val view = LayoutInflater.from(context).inflate(R.layout.locale_settings_dialog, null) private val view = LayoutInflater.from(context).inflate(R.layout.locale_settings_dialog, null)
private val mainLocaleString = infos.first().subtype.locale private val mainLocaleString = infos.first().subtype.locale

View file

@ -52,6 +52,7 @@ public final class SettingsActivity extends AppCompatActivity
final Intent i = getIntent(); final Intent i = getIntent();
if (Intent.ACTION_VIEW.equals(i.getAction()) && i.getData() != null) { if (Intent.ACTION_VIEW.equals(i.getAction()) && i.getData() != null) {
new NewDictionaryAdder(this, null).addDictionary(i.getData(), null); new NewDictionaryAdder(this, null).addDictionary(i.getData(), null);
setIntent(new Intent()); // avoid opening again
} }
getSupportFragmentManager().beginTransaction() getSupportFragmentManager().beginTransaction()
.replace(android.R.id.content, new SettingsFragment()) .replace(android.R.id.content, new SettingsFragment())

View file

@ -140,7 +140,9 @@ public abstract class SubScreenFragment extends PreferenceFragmentCompat
final Activity activity = getActivity(); final Activity activity = getActivity();
if (activity instanceof AppCompatActivity) { if (activity instanceof AppCompatActivity) {
final ActionBar actionBar = ((AppCompatActivity) activity).getSupportActionBar(); final ActionBar actionBar = ((AppCompatActivity) activity).getSupportActionBar();
final CharSequence screenTitle = getPreferenceScreen().getTitle(); final PreferenceScreen ps = getPreferenceScreen();
if (ps == null) return;
final CharSequence screenTitle = ps.getTitle();
if (actionBar != null && screenTitle != null) { if (actionBar != null && screenTitle != null) {
actionBar.setTitle(screenTitle); actionBar.setTitle(screenTitle);
} }

View file

@ -21,7 +21,7 @@ import org.dslul.openboard.inputmethod.latin.settings.AppearanceSettingsFragment
import org.dslul.openboard.inputmethod.latin.settings.CorrectionSettingsFragment; import org.dslul.openboard.inputmethod.latin.settings.CorrectionSettingsFragment;
import org.dslul.openboard.inputmethod.latin.settings.DebugSettingsFragment; import org.dslul.openboard.inputmethod.latin.settings.DebugSettingsFragment;
import org.dslul.openboard.inputmethod.latin.settings.GestureSettingsFragment; import org.dslul.openboard.inputmethod.latin.settings.GestureSettingsFragment;
import org.dslul.openboard.inputmethod.latin.settings.LanguageSettingsFragment; import org.dslul.openboard.inputmethod.latin.settings.LanguageFakeSettingsFragment;
import org.dslul.openboard.inputmethod.latin.settings.PreferencesSettingsFragment; import org.dslul.openboard.inputmethod.latin.settings.PreferencesSettingsFragment;
import org.dslul.openboard.inputmethod.latin.settings.SettingsFragment; import org.dslul.openboard.inputmethod.latin.settings.SettingsFragment;
import org.dslul.openboard.inputmethod.latin.settings.AboutFragment; import org.dslul.openboard.inputmethod.latin.settings.AboutFragment;
@ -49,7 +49,7 @@ public class FragmentUtils {
sLatinImeFragments.add(UserDictionaryList.class.getName()); sLatinImeFragments.add(UserDictionaryList.class.getName());
sLatinImeFragments.add(UserDictionaryLocalePicker.class.getName()); sLatinImeFragments.add(UserDictionaryLocalePicker.class.getName());
sLatinImeFragments.add(UserDictionarySettings.class.getName()); sLatinImeFragments.add(UserDictionarySettings.class.getName());
sLatinImeFragments.add(LanguageSettingsFragment.class.getName()); sLatinImeFragments.add(LanguageFakeSettingsFragment.class.getName());
} }
public static boolean isValidFragment(String fragmentName) { public static boolean isValidFragment(String fragmentName) {

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:paddingTop="6dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/language_switch"
android:text="@string/use_system_language_to_select_input_method_subtypes"
style="@style/PreferenceTitleText"
android:paddingHorizontal="16dp"
android:paddingVertical="4dp"
android:minHeight="48dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<include
layout="@layout/language_search_filter"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

View file

@ -4,7 +4,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="match_parent">
<LinearLayout <LinearLayout
android:id="@+id/search_container" android:id="@+id/search_container"
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -17,7 +17,7 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:key="english_ime_settings"> android:key="english_ime_settings">
<PreferenceScreen <PreferenceScreen
android:fragment="org.dslul.openboard.inputmethod.latin.settings.LanguageSettingsFragment" android:fragment="org.dslul.openboard.inputmethod.latin.settings.LanguageFakeSettingsFragment"
android:title="@string/language_selection_title" android:title="@string/language_selection_title"
android:key="screen_languages" android:key="screen_languages"
android:icon="@drawable/ic_settings_languages"/> android:icon="@drawable/ic_settings_languages"/>