diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/latin/DictionaryFacilitatorImpl.java b/app/src/main/java/org/dslul/openboard/inputmethod/latin/DictionaryFacilitatorImpl.java index 3f7f38de4..fa7c30835 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/latin/DictionaryFacilitatorImpl.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/latin/DictionaryFacilitatorImpl.java @@ -31,8 +31,10 @@ import org.dslul.openboard.inputmethod.latin.common.Constants; import org.dslul.openboard.inputmethod.latin.common.StringUtils; import org.dslul.openboard.inputmethod.latin.permissions.PermissionsUtil; import org.dslul.openboard.inputmethod.latin.personalization.UserHistoryDictionary; +import org.dslul.openboard.inputmethod.latin.settings.Settings; import org.dslul.openboard.inputmethod.latin.settings.SettingsValuesForSuggestion; import org.dslul.openboard.inputmethod.latin.utils.ExecutorUtils; +import org.dslul.openboard.inputmethod.latin.utils.ScriptUtils; import org.dslul.openboard.inputmethod.latin.utils.SuggestionResults; import java.io.File; @@ -70,7 +72,6 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { private DictionaryGroup mDictionaryGroup = new DictionaryGroup(); private DictionaryGroup mSecondaryDictionaryGroup = new DictionaryGroup(); - private Locale mSecondaryLocale = Locale.GERMAN; private volatile CountDownLatch mLatchForWaitingLoadingMainDictionaries = new CountDownLatch(0); // To synchronize assigning mDictionaryGroup to ensure closing dictionaries. private final Object mLock = new Object(); @@ -152,17 +153,17 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { // typing in. For now, this is simply the number of times a word from this language // has been committed in a row, with an exception when typing a single word not contained // in this language. - private int mConfidence = 0; + private int mConfidence = 1; // allow to go above max confidence for better determination of current preferred language // but when decreasing confidence or getting weight factor, limit to maximum public void increaseConfidence() { - mConfidence += 1; + mConfidence += 1; } public void decreaseConfidence() { if (mConfidence > MAX_CONFIDENCE) - mConfidence = MAX_CONFIDENCE - 1; + mConfidence = MAX_CONFIDENCE; else if (mConfidence > MIN_CONFIDENCE) mConfidence -= 1; } @@ -392,14 +393,9 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { dictTypesToCleanupForLocale.remove(subDictType); } subDicts.put(subDictType, subDict); - // what is dictNamePrefix? apparently empty string... - secondarySubDicts.put(subDictType, getSubDict(subDictType, context, mSecondaryLocale, null, dictNamePrefix, account)); } DictionaryGroup newDictionaryGroup = new DictionaryGroup(newLocale, mainDict, account, subDicts); - // TODO: get secondary locale from prefs or whatever (context!) - mSecondaryDictionaryGroup = new DictionaryGroup(mSecondaryLocale, null, account, secondarySubDicts); - mSecondaryDictionaryGroup.setMainDict(DictionaryFactory.createMainDictionaryFromManager(context, mSecondaryLocale)); // Replace Dictionaries. final DictionaryGroup oldDictionaryGroup; @@ -414,6 +410,21 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { listener.onUpdateMainDictionaryAvailability(hasAtLeastOneInitializedMainDictionary()); } + // create / load secondary dictionary + final Locale secondaryLocale = Settings.getInstance().getCurrent().mSecondaryLocale; + if (secondaryLocale != null && mainDict != null && + ScriptUtils.getScriptFromSpellCheckerLocale(secondaryLocale) == ScriptUtils.getScriptFromSpellCheckerLocale(mainDict.mLocale)) { + for (final String subDictType : subDictTypesToUse) { + final ExpandableBinaryDictionary subDict = + getSubDict(subDictType, context, newLocale, null, dictNamePrefix, account); + secondarySubDicts.put(subDictType, subDict); + } + mSecondaryDictionaryGroup = new DictionaryGroup(secondaryLocale, null, account, secondarySubDicts); + mSecondaryDictionaryGroup.setMainDict(DictionaryFactory.createMainDictionaryFromManager(context, secondaryLocale)); + } else { + mSecondaryDictionaryGroup = null; + } + // Clean up old dictionaries. for (final Locale localeToCleanUp : existingDictionariesToCleanup.keySet()) { final ArrayList dictTypesToCleanUp = diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/AdvancedSettingsFragment.java b/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/AdvancedSettingsFragment.java index 7338b3e0e..0836eef4e 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/AdvancedSettingsFragment.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/AdvancedSettingsFragment.java @@ -16,14 +16,35 @@ package org.dslul.openboard.inputmethod.latin.settings; +import android.app.AlertDialog; import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Resources; import android.os.Bundle; +import android.os.LocaleList; +import android.preference.Preference; +import android.util.ArraySet; +import android.util.Log; +import androidx.core.os.LocaleListCompat; + +import org.dslul.openboard.inputmethod.dictionarypack.DictionaryPackConstants; import org.dslul.openboard.inputmethod.latin.AudioAndHapticFeedbackManager; import org.dslul.openboard.inputmethod.latin.R; import org.dslul.openboard.inputmethod.latin.SystemBroadcastReceiver; +import org.dslul.openboard.inputmethod.latin.common.LocaleUtils; +import org.dslul.openboard.inputmethod.latin.utils.DialogUtils; +import org.dslul.openboard.inputmethod.latin.utils.DictionaryInfoUtils; +import org.dslul.openboard.inputmethod.latin.utils.ScriptUtils; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Set; /** * "Advanced" settings sub screen. @@ -57,6 +78,16 @@ public final class AdvancedSettingsFragment extends SubScreenFragment { } setupKeyLongpressTimeoutSettings(); + + final Preference setSecondaryLocale = findPreference("pref_secondary_locale"); + if (setSecondaryLocale != null) + setSecondaryLocale.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + showSecondaryLocaleDialog(); + return true; + } + }); } @@ -105,4 +136,57 @@ public final class AdvancedSettingsFragment extends SubScreenFragment { SystemBroadcastReceiver.toggleAppIcon(getActivity()); } } + + private void showSecondaryLocaleDialog() { + // only latin for now + final List locales = new ArrayList(getAvailableDictionaryLocalesForScript(ScriptUtils.SCRIPT_LATIN)); + final AlertDialog.Builder builder = new AlertDialog.Builder( + DialogUtils.getPlatformDialogThemeContext(getActivity())) + .setTitle(R.string.select_language) + .setPositiveButton(android.R.string.ok, null); + if (locales.isEmpty()) { + builder.setMessage(R.string.no_secondary_locales) + .show(); + return; + } + locales.add(getResources().getString(R.string.secondary_locale_none)); + final CharSequence[] titles = locales.toArray(new CharSequence[0]); + for (int i = 0; i < titles.length -1 ; i++) { + titles[i] = LocaleUtils.constructLocaleFromString(titles[i].toString()).getDisplayLanguage(); + } + Locale currentSecondaryLocale = Settings.getInstance().getCurrent().mSecondaryLocale; + int checkedItem; + if (currentSecondaryLocale == null) + checkedItem = locales.size() - 1; + else + checkedItem = locales.indexOf(currentSecondaryLocale.toString()); + + builder.setSingleChoiceItems(titles, checkedItem, (dialogInterface, i) -> { + String locale = locales.get(i); + if (locale.equals(getResources().getString(R.string.secondary_locale_none))) + locale = ""; + getSharedPreferences().edit().putString(Settings.PREF_SECONDARY_LOCALE, locale).apply(); + final Intent newDictBroadcast = new Intent(DictionaryPackConstants.NEW_DICTIONARY_INTENT_ACTION); + getActivity().sendBroadcast(newDictBroadcast); + }); + + builder.show(); + } + + private Set getAvailableDictionaryLocalesForScript(int script) { + final Set locales = new HashSet<>(); + // TODO: get from assets + // need merged "compress" PR + // filter by script! + final File[] directoryList = DictionaryInfoUtils.getCachedDirectoryList(getActivity()); + for (File directory : directoryList) { + if (!directory.isDirectory()) continue; + final String dirLocale = + DictionaryInfoUtils.getWordListIdFromFileName(directory.getName()); + final Locale locale = LocaleUtils.constructLocaleFromString(dirLocale); + if (ScriptUtils.getScriptFromSpellCheckerLocale(locale) != script) continue; + locales.add(locale.toString()); + } + return locales; + } } diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/Settings.java b/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/Settings.java index 24990a334..65c1bc5b3 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/Settings.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/Settings.java @@ -29,6 +29,7 @@ import android.view.Gravity; import org.dslul.openboard.inputmethod.latin.AudioAndHapticFeedbackManager; import org.dslul.openboard.inputmethod.latin.InputAttributes; import org.dslul.openboard.inputmethod.latin.R; +import org.dslul.openboard.inputmethod.latin.common.LocaleUtils; import org.dslul.openboard.inputmethod.latin.common.StringUtils; import org.dslul.openboard.inputmethod.latin.utils.AdditionalSubtypeUtils; import org.dslul.openboard.inputmethod.latin.utils.DeviceProtectedUtils; @@ -126,6 +127,8 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static final String PREF_ENABLE_CLIPBOARD_HISTORY = "pref_enable_clipboard_history"; public static final String PREF_CLIPBOARD_HISTORY_RETENTION_TIME = "pref_clipboard_history_retention_time"; + public static final String PREF_SECONDARY_LOCALE = "pref_secondary_locale"; + // This preference key is deprecated. Use {@link #PREF_SHOW_LANGUAGE_SWITCH_KEY} instead. // This is being used only for the backward compatibility. private static final String PREF_SUPPRESS_LANGUAGE_SWITCH_KEY = @@ -509,6 +512,13 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang return prefs.getInt(PREF_LAST_SHOWN_EMOJI_CATEGORY_PAGE_ID, defValue); } + public static Locale readSecondaryLocale(final SharedPreferences prefs) { + final String localeString = prefs.getString(PREF_SECONDARY_LOCALE, ""); + if (localeString.isEmpty()) + return null; + return LocaleUtils.constructLocaleFromString(localeString); + } + private void upgradeAutocorrectionSettings(final SharedPreferences prefs, final Resources res) { final String thresholdSetting = prefs.getString(PREF_AUTO_CORRECTION_THRESHOLD_OBSOLETE, null); diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/SettingsValues.java b/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/SettingsValues.java index 009018892..c22ff3a7f 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/SettingsValues.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/SettingsValues.java @@ -84,6 +84,7 @@ public class SettingsValues { public final long mClipboardHistoryRetentionTime; public final boolean mOneHandedModeEnabled; public final int mOneHandedModeGravity; + public final Locale mSecondaryLocale; // Use bigrams to predict the next word when there is no input for it yet public final boolean mBigramPredictionEnabled; public final boolean mGestureInputEnabled; @@ -241,6 +242,7 @@ public class SettingsValues { mClipboardHistoryRetentionTime = Settings.readClipboardHistoryRetentionTime(prefs, res); mOneHandedModeEnabled = Settings.readOneHandedModeEnabled(prefs); mOneHandedModeGravity = Settings.readOneHandedModeGravity(prefs); + mSecondaryLocale = Settings.readSecondaryLocale(prefs); } public boolean isMetricsLoggingEnabled() { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2e0ccc187..ad0281455 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -184,6 +184,14 @@ Perform a swipe from the delete key to select and remove bigger portions of text at once Space bar trackpad + + Multilingual typing + + Select a secondary dictionary to use alongside main language + + None + + No secondary locales available Swipe on the spacebar to move the cursor diff --git a/app/src/main/res/xml/prefs_screen_advanced.xml b/app/src/main/res/xml/prefs_screen_advanced.xml index 778671bc6..79244ce1e 100644 --- a/app/src/main/res/xml/prefs_screen_advanced.xml +++ b/app/src/main/res/xml/prefs_screen_advanced.xml @@ -76,6 +76,11 @@ android:summary="@string/delete_swipe_summary" android:defaultValue="true" /> + +