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;
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.SharedPreferences;

View file

@ -6,51 +6,76 @@ import android.content.Intent
import android.content.SharedPreferences
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
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.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.SubtypeLocaleUtils
import org.dslul.openboard.inputmethod.latin.utils.getDictionaryLocales
import java.util.Locale
class LanguageSettingsFragment : SubScreenFragment() {
import java.util.*
// 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 enabledSubtypes = mutableListOf<InputMethodSubtype>()
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() } }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
addPreferencesFromResource(R.xml.prefs_screen_languages)
sharedPreferences = DeviceProtectedUtils.getSharedPreferences(requireContext())
SubtypeLocaleUtils.init(requireContext())
enabledSubtypes.addAll(getEnabledSubtypes(sharedPreferences))
systemLocales.addAll(getSystemLocales())
loadSubtypes()
}
override fun onSharedPreferenceChanged(prefs: SharedPreferences, key: String) {
super.onSharedPreferenceChanged(prefs, key)
if (key == Settings.PREF_USE_SYSTEM_LOCALES)
loadSubtypes()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
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() {
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() {
super.onPause()
languageFilterListPreference.setSettingsFragment(null)
languageFilterList.setSettingsFragment(null)
}
private fun loadSubtypes() {
val systemOnly = findPreference<SwitchPreferenceCompat>(Settings.PREF_USE_SYSTEM_LOCALES)!!.isChecked
private fun loadSubtypes(systemOnly: Boolean) {
sortedSubtypes.clear()
// list of all subtypes, any subtype added to sortedSubtypes will be removed to avoid duplicates
val allSubtypes = getAllAvailableSubtypes().toMutableList()
@ -108,7 +133,7 @@ class LanguageSettingsFragment : SubScreenFragment() {
allSubtypes.removeAll(enabledSubtypes)
if (systemOnly) { // don't add anything else
languageFilterListPreference.setLanguages(sortedSubtypes.values, systemOnly)
languageFilterList.setLanguages(sortedSubtypes.values, systemOnly)
return
}
@ -133,7 +158,7 @@ class LanguageSettingsFragment : SubScreenFragment() {
}.addToSortedSubtypes()
// set languages
languageFilterListPreference.setLanguages(sortedSubtypes.values, systemOnly)
languageFilterList.setLanguages(sortedSubtypes.values, systemOnly)
}
private fun InputMethodSubtype.toSubtypeInfo(locale: Locale, isEnabled: Boolean = false) =

View file

@ -1,80 +1,40 @@
package org.dslul.openboard.inputmethod.latin.settings
import android.content.Context
import android.graphics.Rect
import android.graphics.Typeface
import android.os.Build
import android.text.Spannable
import android.text.SpannableString
import android.text.SpannableStringBuilder
import android.text.style.StyleSpan
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.core.view.doOnLayout
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.core.widget.doAfterTextChanged
import androidx.preference.Preference
import androidx.preference.PreferenceGroupAdapter
import androidx.preference.PreferenceViewHolder
import androidx.recyclerview.widget.RecyclerView
import org.dslul.openboard.inputmethod.latin.R
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(), context)
private val adapter = LanguageAdapter(emptyList(), recyclerView.context)
private val sortedSubtypes = mutableListOf<MutableList<SubtypeInfo>>()
fun setSettingsFragment(newFragment: LanguageSettingsFragment?) {
fun setSettingsFragment(newFragment: LanguageFakeSettingsFragment?) {
adapter.fragment = newFragment
}
override fun onBindViewHolder(holder: PreferenceViewHolder) {
super.onBindViewHolder(holder)
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)!!
init {
recyclerView.adapter = adapter
searchField.doAfterTextChanged { text ->
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) {
@ -90,7 +50,7 @@ class LanguageAdapter(list: List<MutableList<SubtypeInfo>> = listOf(), context:
RecyclerView.Adapter<LanguageAdapter.ViewHolder>() {
var onlySystemLocales = false
private val prefs = DeviceProtectedUtils.getSharedPreferences(context)
var fragment: LanguageSettingsFragment? = null
var fragment: LanguageFakeSettingsFragment? = null
var list: List<MutableList<SubtypeInfo>> = list
set(value) {

View file

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

View file

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

View file

@ -140,7 +140,9 @@ public abstract class SubScreenFragment extends PreferenceFragmentCompat
final Activity activity = getActivity();
if (activity instanceof AppCompatActivity) {
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) {
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.DebugSettingsFragment;
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.SettingsFragment;
import org.dslul.openboard.inputmethod.latin.settings.AboutFragment;
@ -49,7 +49,7 @@ public class FragmentUtils {
sLatinImeFragments.add(UserDictionaryList.class.getName());
sLatinImeFragments.add(UserDictionaryLocalePicker.class.getName());
sLatinImeFragments.add(UserDictionarySettings.class.getName());
sLatinImeFragments.add(LanguageSettingsFragment.class.getName());
sLatinImeFragments.add(LanguageFakeSettingsFragment.class.getName());
}
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"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/search_container"
android:layout_width="match_parent"

View file

@ -17,7 +17,7 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:key="english_ime_settings">
<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:key="screen_languages"
android:icon="@drawable/ic_settings_languages"/>