diff --git a/java/res/drawable/empty.xml b/java/res/drawable/empty.xml
new file mode 100644
index 000000000..2bce7ee46
--- /dev/null
+++ b/java/res/drawable/empty.xml
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index e7b51e048..d1b6216ce 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -573,4 +573,43 @@ Tip: You can download and remove dictionaries by going to <b>Languages &
This resource is copied from packages/apps/Settings/res/values/strings.xml -->
\u0020ABCDEFGHIJKLMNOPQRSTUVWXYZ
+
+ Arabic
+ Armenian (Phonetic)
+ AZERTY
+ Bengali
+ Bengali (Akkhor)
+ BÉPO
+ Bulgarian
+ Bulgarian (BDS)
+ Colemak
+ Dvorak
+ East Slavic
+ Farsi
+ Georgian
+ Greek
+ Hebrew
+ Hindi
+ Hindi (Compact)
+ Kannada
+ Khmer
+ Lao
+ Malayalam
+ Marathi
+ Mongolian
+ Nepali (Romanized)
+ Nepali (Traditional)
+ Nordic
+ PC QWERTY
+ QWERTY
+ QWERTZ
+ Serbian (QWERTZ)
+ Sinhala
+ South Slavic
+ Spanish
+ Swiss
+ Tamil
+ Telugu
+ Thai
+ Uzbek
diff --git a/java/res/xml/kbd_bepo.xml b/java/res/xml/kbd_bepo.xml
new file mode 100644
index 000000000..d0226991e
--- /dev/null
+++ b/java/res/xml/kbd_bepo.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
diff --git a/java/res/xml/keyboard_layout_set_bepo.xml b/java/res/xml/keyboard_layout_set_bepo.xml
new file mode 100644
index 000000000..d9d248d29
--- /dev/null
+++ b/java/res/xml/keyboard_layout_set_bepo.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml
index 1f02f3b40..c97b77ac4 100644
--- a/java/res/xml/method.xml
+++ b/java/res/xml/method.xml
@@ -1,812 +1,13 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:settingsActivity="org.futo.inputmethod.latin.uix.settings.SettingsActivity"
+ android:isDefault="true"
+ android:supportsSwitchingToNextInputMethod="true"
+ android:supportsInlineSuggestions="true">
+
diff --git a/java/res/xml/rowkeys_bepo1.xml b/java/res/xml/rowkeys_bepo1.xml
new file mode 100644
index 000000000..9d4decbfa
--- /dev/null
+++ b/java/res/xml/rowkeys_bepo1.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/java/res/xml/rowkeys_bepo2.xml b/java/res/xml/rowkeys_bepo2.xml
new file mode 100644
index 000000000..360a0c8b1
--- /dev/null
+++ b/java/res/xml/rowkeys_bepo2.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/java/res/xml/rowkeys_bepo3.xml b/java/res/xml/rowkeys_bepo3.xml
new file mode 100644
index 000000000..a449c62e0
--- /dev/null
+++ b/java/res/xml/rowkeys_bepo3.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/java/res/xml/rows_bepo.xml b/java/res/xml/rows_bepo.xml
new file mode 100644
index 000000000..6e97fea37
--- /dev/null
+++ b/java/res/xml/rows_bepo.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/java/src/org/futo/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/org/futo/inputmethod/keyboard/KeyboardSwitcher.java
index 148fe03bb..0d7f7fbd3 100644
--- a/java/src/org/futo/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/org/futo/inputmethod/keyboard/KeyboardSwitcher.java
@@ -28,7 +28,6 @@ import androidx.annotation.NonNull;
import org.futo.inputmethod.event.Event;
import org.futo.inputmethod.keyboard.KeyboardLayoutSet.KeyboardLayoutSetException;
-import org.futo.inputmethod.keyboard.emoji.EmojiPalettesView;
import org.futo.inputmethod.keyboard.internal.KeyboardState;
import org.futo.inputmethod.keyboard.internal.KeyboardTextsSet;
import org.futo.inputmethod.latin.InputView;
@@ -36,6 +35,7 @@ import org.futo.inputmethod.latin.LatinIME;
import org.futo.inputmethod.latin.LatinIMELegacy;
import org.futo.inputmethod.latin.R;
import org.futo.inputmethod.latin.RichInputMethodManager;
+import org.futo.inputmethod.latin.Subtypes;
import org.futo.inputmethod.latin.WordComposer;
import org.futo.inputmethod.latin.define.ProductionFlags;
import org.futo.inputmethod.latin.settings.Settings;
@@ -181,8 +181,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
|| !newKeyboard.mId.mSubtype.equals(oldKeyboard.mId.mSubtype);
final int languageOnSpacebarFormatType = LanguageOnSpacebarUtils
.getLanguageOnSpacebarFormatType(newKeyboard.mId.mSubtype);
- final boolean hasMultipleEnabledIMEsOrSubtypes = mRichImm
- .hasMultipleEnabledIMEsOrSubtypes(true /* shouldIncludeAuxiliarySubtypes */);
+ final boolean hasMultipleEnabledIMEsOrSubtypes = Subtypes.INSTANCE.hasMultipleEnabledSubtypes(mThemeContext);
keyboardView.startDisplayLanguageOnSpacebar(subtypeChanged, languageOnSpacebarFormatType,
hasMultipleEnabledIMEsOrSubtypes);
}
diff --git a/java/src/org/futo/inputmethod/latin/LatinIME.kt b/java/src/org/futo/inputmethod/latin/LatinIME.kt
index 76ca689cd..183b136ce 100644
--- a/java/src/org/futo/inputmethod/latin/LatinIME.kt
+++ b/java/src/org/futo/inputmethod/latin/LatinIME.kt
@@ -63,6 +63,7 @@ import org.futo.inputmethod.latin.uix.deferGetSetting
import org.futo.inputmethod.latin.uix.deferSetSetting
import org.futo.inputmethod.latin.uix.differsFrom
import org.futo.inputmethod.latin.uix.getSetting
+import org.futo.inputmethod.latin.uix.getSettingBlocking
import org.futo.inputmethod.latin.uix.getSettingFlow
import org.futo.inputmethod.latin.uix.setSetting
import org.futo.inputmethod.latin.uix.theme.DarkColorScheme
@@ -275,7 +276,21 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
}
lifecycleScope.launch {
- saveSubtypes()
+ val onNewSubtype: (String) -> Unit = {
+ val activeSubtype = it.ifEmpty {
+ getSettingBlocking(SubtypesSetting).firstOrNull()
+ }
+
+ if(activeSubtype != null) {
+ changeInputMethodSubtype(Subtypes.convertToSubtype(activeSubtype))
+ }
+ }
+
+ onNewSubtype(getSetting(ActiveSubtype))
+
+ dataStore.data.collect {
+ onNewSubtype(it[ActiveSubtype.key] ?: ActiveSubtype.default)
+ }
}
}
@@ -411,8 +426,7 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
languageModelFacilitator.saveHistoryLog()
}
- override fun onCurrentInputMethodSubtypeChanged(newSubtype: InputMethodSubtype?) {
- super.onCurrentInputMethodSubtypeChanged(newSubtype)
+ private fun changeInputMethodSubtype(newSubtype: InputMethodSubtype?) {
latinIMELegacy.onCurrentInputMethodSubtypeChanged(newSubtype)
}
diff --git a/java/src/org/futo/inputmethod/latin/LatinIMELegacy.java b/java/src/org/futo/inputmethod/latin/LatinIMELegacy.java
index 01384e574..8b3cfbc41 100644
--- a/java/src/org/futo/inputmethod/latin/LatinIMELegacy.java
+++ b/java/src/org/futo/inputmethod/latin/LatinIMELegacy.java
@@ -32,7 +32,6 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.graphics.Color;
import android.inputmethodservice.InputMethodService;
import android.media.AudioManager;
import android.os.Build;
@@ -61,8 +60,6 @@ import androidx.core.content.ContextCompat;
import org.futo.inputmethod.accessibility.AccessibilityUtils;
import org.futo.inputmethod.annotations.UsedForTesting;
-import org.futo.inputmethod.compat.BuildCompatUtils;
-import org.futo.inputmethod.compat.EditorInfoCompatUtils;
import org.futo.inputmethod.compat.ViewOutlineProviderCompatUtils;
import org.futo.inputmethod.compat.ViewOutlineProviderCompatUtils.InsetsUpdater;
import org.futo.inputmethod.dictionarypack.DictionaryPackConstants;
@@ -90,7 +87,7 @@ import org.futo.inputmethod.latin.settings.SettingsValues;
import org.futo.inputmethod.latin.suggestions.SuggestionStripView;
import org.futo.inputmethod.latin.suggestions.SuggestionStripViewAccessor;
import org.futo.inputmethod.latin.touchinputconsumer.GestureConsumer;
-import org.futo.inputmethod.latin.uix.DynamicThemeProviderOwner;
+import org.futo.inputmethod.latin.uix.actions.SwitchLanguageActionKt;
import org.futo.inputmethod.latin.uix.settings.SettingsActivity;
import org.futo.inputmethod.latin.utils.ApplicationUtils;
import org.futo.inputmethod.latin.utils.DialogUtils;
@@ -176,7 +173,7 @@ public class LatinIMELegacy implements KeyboardActionListener,
private final SuggestionStripController mSuggestionStripController;
private RichInputMethodManager mRichImm;
- @UsedForTesting final KeyboardSwitcher mKeyboardSwitcher;
+ public final KeyboardSwitcher mKeyboardSwitcher;
private final SubtypeState mSubtypeState = new SubtypeState();
private EmojiAltPhysicalKeyDetector mEmojiAltPhysicalKeyDetector;
private StatsUtilsManager mStatsUtilsManager;
@@ -329,9 +326,6 @@ public class LatinIMELegacy implements KeyboardActionListener,
case MSG_DEALLOCATE_MEMORY:
latinImeLegacy.deallocateMemory();
break;
- case MSG_SWITCH_LANGUAGE_AUTOMATICALLY:
- latinImeLegacy.switchLanguage((InputMethodSubtype)msg.obj);
- break;
}
}
@@ -465,10 +459,6 @@ public class LatinIMELegacy implements KeyboardActionListener,
obtainMessage(MSG_UPDATE_TAIL_BATCH_INPUT_COMPLETED, suggestedWords).sendToTarget();
}
- public void postSwitchLanguage(final InputMethodSubtype subtype) {
- obtainMessage(MSG_SWITCH_LANGUAGE_AUTOMATICALLY, subtype).sendToTarget();
- }
-
// Working variables for the following methods.
private boolean mIsOrientationChanging;
private boolean mPendingSuccessiveImsCallback;
@@ -589,23 +579,6 @@ public class LatinIMELegacy implements KeyboardActionListener,
mCurrentSubtypeHasBeenUsed = true;
}
- public void switchSubtype(final IBinder token, final RichInputMethodManager richImm) {
- final InputMethodSubtype currentSubtype = richImm.getInputMethodManager()
- .getCurrentInputMethodSubtype();
- final InputMethodSubtype lastActiveSubtype = mLastActiveSubtype;
- final boolean currentSubtypeHasBeenUsed = mCurrentSubtypeHasBeenUsed;
- if (currentSubtypeHasBeenUsed) {
- mLastActiveSubtype = currentSubtype;
- mCurrentSubtypeHasBeenUsed = false;
- }
- if (currentSubtypeHasBeenUsed
- && richImm.checkIfSubtypeBelongsToThisImeAndEnabled(lastActiveSubtype)
- && !currentSubtype.equals(lastActiveSubtype)) {
- richImm.setInputMethodAndSubtype(token, lastActiveSubtype);
- return;
- }
- richImm.switchToNextInputMethod(token, true /* onlyCurrentIme */);
- }
}
// Loading the native library eagerly to avoid unexpected UnsatisfiedLinkError at the initial
@@ -929,18 +902,7 @@ public class LatinIMELegacy implements KeyboardActionListener,
}
void onStartInputInternal(final EditorInfo editorInfo, final boolean restarting) {
- // If the primary hint language does not match the current subtype language, then try
- // to switch to the primary hint language.
- // TODO: Support all the locales in EditorInfo#hintLocales.
- final Locale primaryHintLocale = EditorInfoCompatUtils.getPrimaryHintLocale(editorInfo);
- if (primaryHintLocale == null) {
- return;
- }
- final InputMethodSubtype newSubtype = mRichImm.findSubtypeByLocale(primaryHintLocale);
- if (newSubtype == null || newSubtype.equals(mRichImm.getCurrentSubtype().getRawSubtype())) {
- return;
- }
- mHandler.postSwitchLanguage(newSubtype);
+
}
public void updateMainKeyboardViewSettings() {
@@ -1374,11 +1336,8 @@ public class LatinIMELegacy implements KeyboardActionListener,
if (isShowingOptionDialog()) return false;
switch (requestCode) {
case Constants.CUSTOM_CODE_SHOW_INPUT_METHOD_PICKER:
- if (mRichImm.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) {
- mRichImm.getInputMethodManager().showInputMethodPicker();
- return true;
- }
- return false;
+ ((LatinIME)mInputMethodService).getUixManager().showLanguageSwitcher();
+ return true;
}
return false;
}
@@ -1459,13 +1418,8 @@ public class LatinIMELegacy implements KeyboardActionListener,
return mOptionsDialog != null && mOptionsDialog.isShowing();
}
- public void switchLanguage(final InputMethodSubtype subtype) {
- final IBinder token = mInputMethodService.getWindow().getWindow().getAttributes().token;
- mRichImm.setInputMethodAndSubtype(token, subtype);
- }
-
public void switchToNextSubtype() {
- mRichImm.getInputMethodManager().showInputMethodPicker();
+ SwitchLanguageActionKt.switchToNextLanguage(mInputMethodService);
}
// TODO: Instead of checking for alphabetic keyboard here, separate keycodes for
@@ -2006,12 +1960,6 @@ public class LatinIMELegacy implements KeyboardActionListener,
mDictionaryFacilitator.clearUserHistoryDictionary(mInputMethodService);
}
- @UsedForTesting
- List getEnabledSubtypesForTest() {
- return (mRichImm != null) ? mRichImm.getMyEnabledInputMethodSubtypeList(
- true /* allowsImplicitlySelectedSubtypes */) : new ArrayList();
- }
-
public void dumpDictionaryForDebug(final String dictName) {
if (!mDictionaryFacilitator.isActive()) {
resetDictionaryFacilitatorIfNecessary();
diff --git a/java/src/org/futo/inputmethod/latin/RichInputMethodManager.java b/java/src/org/futo/inputmethod/latin/RichInputMethodManager.java
index 4a08ff1de..513b2eb9a 100644
--- a/java/src/org/futo/inputmethod/latin/RichInputMethodManager.java
+++ b/java/src/org/futo/inputmethod/latin/RichInputMethodManager.java
@@ -102,9 +102,6 @@ public class RichInputMethodManager {
// Initialize additional subtypes.
SubtypeLocaleUtils.init(context);
- final InputMethodSubtype[] additionalSubtypes = getAdditionalSubtypes();
- mImmWrapper.mImm.setAdditionalInputMethodSubtypes(
- getInputMethodIdOfThisIme(), additionalSubtypes);
// Initialize the current input method subtype and the shortcut IME.
refreshSubtypeCaches();
@@ -122,110 +119,6 @@ public class RichInputMethodManager {
return mImmWrapper.mImm;
}
- public List getMyEnabledInputMethodSubtypeList(
- boolean allowsImplicitlySelectedSubtypes) {
- return getEnabledInputMethodSubtypeList(
- getInputMethodInfoOfThisIme(), allowsImplicitlySelectedSubtypes);
- }
-
- public boolean switchToNextInputMethod(final IBinder token, final boolean onlyCurrentIme) {
- if (mImmWrapper.switchToNextInputMethod(token, onlyCurrentIme)) {
- return true;
- }
- // Was not able to call {@link InputMethodManager#switchToNextInputMethodIBinder,boolean)}
- // because the current device is running ICS or previous and lacks the API.
- if (switchToNextInputSubtypeInThisIme(token, onlyCurrentIme)) {
- return true;
- }
- return switchToNextInputMethodAndSubtype(token);
- }
-
- private boolean switchToNextInputSubtypeInThisIme(final IBinder token,
- final boolean onlyCurrentIme) {
- final InputMethodManager imm = mImmWrapper.mImm;
- final InputMethodSubtype currentSubtype = imm.getCurrentInputMethodSubtype();
- final List enabledSubtypes = getMyEnabledInputMethodSubtypeList(
- true /* allowsImplicitlySelectedSubtypes */);
- final int currentIndex = getSubtypeIndexInList(currentSubtype, enabledSubtypes);
- if (currentIndex == INDEX_NOT_FOUND) {
- Log.w(TAG, "Can't find current subtype in enabled subtypes: subtype="
- + SubtypeLocaleUtils.getSubtypeNameForLogging(currentSubtype));
- return false;
- }
- final int nextIndex = (currentIndex + 1) % enabledSubtypes.size();
- if (nextIndex <= currentIndex && !onlyCurrentIme) {
- // The current subtype is the last or only enabled one and it needs to switch to
- // next IME.
- return false;
- }
- final InputMethodSubtype nextSubtype = enabledSubtypes.get(nextIndex);
- setInputMethodAndSubtype(token, nextSubtype);
- return true;
- }
-
- private boolean switchToNextInputMethodAndSubtype(final IBinder token) {
- final InputMethodManager imm = mImmWrapper.mImm;
- final List enabledImis = imm.getEnabledInputMethodList();
- final int currentIndex = getImiIndexInList(getInputMethodInfoOfThisIme(), enabledImis);
- if (currentIndex == INDEX_NOT_FOUND) {
- Log.w(TAG, "Can't find current IME in enabled IMEs: IME package="
- + getInputMethodInfoOfThisIme().getPackageName());
- return false;
- }
- final InputMethodInfo nextImi = getNextNonAuxiliaryIme(currentIndex, enabledImis);
- final List enabledSubtypes = getEnabledInputMethodSubtypeList(nextImi,
- true /* allowsImplicitlySelectedSubtypes */);
- if (enabledSubtypes.isEmpty()) {
- // The next IME has no subtype.
- imm.setInputMethod(token, nextImi.getId());
- return true;
- }
- final InputMethodSubtype firstSubtype = enabledSubtypes.get(0);
- imm.setInputMethodAndSubtype(token, nextImi.getId(), firstSubtype);
- return true;
- }
-
- private static int getImiIndexInList(final InputMethodInfo inputMethodInfo,
- final List imiList) {
- final int count = imiList.size();
- for (int index = 0; index < count; index++) {
- final InputMethodInfo imi = imiList.get(index);
- if (imi.equals(inputMethodInfo)) {
- return index;
- }
- }
- return INDEX_NOT_FOUND;
- }
-
- // This method mimics {@link InputMethodManager#switchToNextInputMethod(IBinder,boolean)}.
- private static InputMethodInfo getNextNonAuxiliaryIme(final int currentIndex,
- final List imiList) {
- final int count = imiList.size();
- for (int i = 1; i < count; i++) {
- final int nextIndex = (currentIndex + i) % count;
- final InputMethodInfo nextImi = imiList.get(nextIndex);
- if (!isAuxiliaryIme(nextImi)) {
- return nextImi;
- }
- }
- return imiList.get(currentIndex);
- }
-
- // Copied from {@link InputMethodInfo}. See how auxiliary of IME is determined.
- private static boolean isAuxiliaryIme(final InputMethodInfo imi) {
- final int count = imi.getSubtypeCount();
- if (count == 0) {
- return false;
- }
- for (int index = 0; index < count; index++) {
- final InputMethodSubtype subtype = imi.getSubtypeAt(index);
- if (!subtype.isAuxiliary()) {
- return false;
- }
- }
- return true;
- }
-
private static class InputMethodInfoCache {
private final InputMethodManager mImm;
private final String mImePackageName;
@@ -287,38 +180,6 @@ public class RichInputMethodManager {
return getInputMethodInfoOfThisIme().getId();
}
- public boolean checkIfSubtypeBelongsToThisImeAndEnabled(final InputMethodSubtype subtype) {
- return checkIfSubtypeBelongsToList(subtype,
- getEnabledInputMethodSubtypeList(
- getInputMethodInfoOfThisIme(),
- true /* allowsImplicitlySelectedSubtypes */));
- }
-
- public boolean checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(
- final InputMethodSubtype subtype) {
- final boolean subtypeEnabled = checkIfSubtypeBelongsToThisImeAndEnabled(subtype);
- final boolean subtypeExplicitlyEnabled = checkIfSubtypeBelongsToList(subtype,
- getMyEnabledInputMethodSubtypeList(false /* allowsImplicitlySelectedSubtypes */));
- return subtypeEnabled && !subtypeExplicitlyEnabled;
- }
-
- private static boolean checkIfSubtypeBelongsToList(final InputMethodSubtype subtype,
- final List subtypes) {
- return getSubtypeIndexInList(subtype, subtypes) != INDEX_NOT_FOUND;
- }
-
- private static int getSubtypeIndexInList(final InputMethodSubtype subtype,
- final List subtypes) {
- final int count = subtypes.size();
- for (int index = 0; index < count; index++) {
- final InputMethodSubtype ims = subtypes.get(index);
- if (ims.equals(subtype)) {
- return index;
- }
- }
- return INDEX_NOT_FOUND;
- }
-
public void onSubtypeChanged(@Nonnull final InputMethodSubtype newSubtype) {
updateCurrentSubtype(newSubtype);
updateShortcutIme();
@@ -355,142 +216,9 @@ public class RichInputMethodManager {
return SubtypeLocaleUtils.getCombiningRulesExtraValue(getCurrentSubtype().getRawSubtype());
}
- public boolean hasMultipleEnabledIMEsOrSubtypes(final boolean shouldIncludeAuxiliarySubtypes) {
- final List enabledImis = mImmWrapper.mImm.getEnabledInputMethodList();
- return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, enabledImis);
- }
-
- public boolean hasMultipleEnabledSubtypesInThisIme(
- final boolean shouldIncludeAuxiliarySubtypes) {
- final List imiList = Collections.singletonList(
- getInputMethodInfoOfThisIme());
- return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, imiList);
- }
-
- private boolean hasMultipleEnabledSubtypes(final boolean shouldIncludeAuxiliarySubtypes,
- final List imiList) {
- // Number of the filtered IMEs
- int filteredImisCount = 0;
-
- for (InputMethodInfo imi : imiList) {
- // We can return true immediately after we find two or more filtered IMEs.
- if (filteredImisCount > 1) return true;
- final List subtypes = getEnabledInputMethodSubtypeList(imi, true);
- // IMEs that have no subtypes should be counted.
- if (subtypes.isEmpty()) {
- ++filteredImisCount;
- continue;
- }
-
- int auxCount = 0;
- for (InputMethodSubtype subtype : subtypes) {
- if (subtype.isAuxiliary()) {
- ++auxCount;
- }
- }
- final int nonAuxCount = subtypes.size() - auxCount;
-
- // IMEs that have one or more non-auxiliary subtypes should be counted.
- // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary
- // subtypes should be counted as well.
- if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) {
- ++filteredImisCount;
- }
- }
-
- if (filteredImisCount > 1) {
- return true;
- }
- final List subtypes = getMyEnabledInputMethodSubtypeList(true);
- int keyboardCount = 0;
- // imm.getEnabledInputMethodSubtypeList(null, true) will return the current IME's
- // both explicitly and implicitly enabled input method subtype.
- // (The current IME should be LatinIME.)
- for (InputMethodSubtype subtype : subtypes) {
- if (KEYBOARD_MODE.equals(subtype.getMode())) {
- ++keyboardCount;
- }
- }
- return keyboardCount > 1;
- }
-
- public InputMethodSubtype findSubtypeByLocaleAndKeyboardLayoutSet(final String localeString,
- final String keyboardLayoutSetName) {
- final InputMethodInfo myImi = getInputMethodInfoOfThisIme();
- final int count = myImi.getSubtypeCount();
- for (int i = 0; i < count; i++) {
- final InputMethodSubtype subtype = myImi.getSubtypeAt(i);
- final String layoutName = SubtypeLocaleUtils.getKeyboardLayoutSetName(subtype);
- if (localeString.equals(subtype.getLocale())
- && keyboardLayoutSetName.equals(layoutName)) {
- return subtype;
- }
- }
- return null;
- }
-
- public InputMethodSubtype findSubtypeByLocale(final Locale locale) {
- // Find the best subtype based on a straightforward matching algorithm.
- // TODO: Use LocaleList#getFirstMatch() instead.
- final List subtypes =
- getMyEnabledInputMethodSubtypeList(true /* allowsImplicitlySelectedSubtypes */);
- final int count = subtypes.size();
- for (int i = 0; i < count; ++i) {
- final InputMethodSubtype subtype = subtypes.get(i);
- final Locale subtypeLocale = InputMethodSubtypeCompatUtils.getLocaleObject(subtype);
- if (subtypeLocale.equals(locale)) {
- return subtype;
- }
- }
- for (int i = 0; i < count; ++i) {
- final InputMethodSubtype subtype = subtypes.get(i);
- final Locale subtypeLocale = InputMethodSubtypeCompatUtils.getLocaleObject(subtype);
- if (subtypeLocale.getLanguage().equals(locale.getLanguage()) &&
- subtypeLocale.getCountry().equals(locale.getCountry()) &&
- subtypeLocale.getVariant().equals(locale.getVariant())) {
- return subtype;
- }
- }
- for (int i = 0; i < count; ++i) {
- final InputMethodSubtype subtype = subtypes.get(i);
- final Locale subtypeLocale = InputMethodSubtypeCompatUtils.getLocaleObject(subtype);
- if (subtypeLocale.getLanguage().equals(locale.getLanguage()) &&
- subtypeLocale.getCountry().equals(locale.getCountry())) {
- return subtype;
- }
- }
- for (int i = 0; i < count; ++i) {
- final InputMethodSubtype subtype = subtypes.get(i);
- final Locale subtypeLocale = InputMethodSubtypeCompatUtils.getLocaleObject(subtype);
- if (subtypeLocale.getLanguage().equals(locale.getLanguage())) {
- return subtype;
- }
- }
- return null;
- }
-
- public void setInputMethodAndSubtype(final IBinder token, final InputMethodSubtype subtype) {
- mImmWrapper.mImm.setInputMethodAndSubtype(
- token, getInputMethodIdOfThisIme(), subtype);
- }
-
- public void setAdditionalInputMethodSubtypes(final InputMethodSubtype[] subtypes) {
- mImmWrapper.mImm.setAdditionalInputMethodSubtypes(
- getInputMethodIdOfThisIme(), subtypes);
- // Clear the cache so that we go read the {@link InputMethodInfo} of this IME and list of
- // subtypes again next time.
- refreshSubtypeCaches();
- }
-
- private List getEnabledInputMethodSubtypeList(final InputMethodInfo imi,
- final boolean allowsImplicitlySelectedSubtypes) {
- return mInputMethodInfoCache.getEnabledInputMethodSubtypeList(
- imi, allowsImplicitlySelectedSubtypes);
- }
-
public void refreshSubtypeCaches() {
mInputMethodInfoCache.clear();
- updateCurrentSubtype(mImmWrapper.mImm.getCurrentInputMethodSubtype());
+ updateCurrentSubtype(Subtypes.INSTANCE.getActiveSubtype(mContext));
updateShortcutIme();
}
@@ -545,13 +273,7 @@ public class RichInputMethodManager {
mShortcutSubtype.getLocale() + ", " + mShortcutSubtype.getMode())));
}
final RichInputMethodSubtype richSubtype = mCurrentRichInputMethodSubtype;
- final boolean implicitlyEnabledSubtype = checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(
- richSubtype.getRawSubtype());
final Locale systemLocale = mContext.getResources().getConfiguration().locale;
- LanguageOnSpacebarUtils.onSubtypeChanged(
- richSubtype, implicitlyEnabledSubtype, systemLocale);
- LanguageOnSpacebarUtils.setEnabledSubtypes(getMyEnabledInputMethodSubtypeList(
- true /* allowsImplicitlySelectedSubtypes */));
// TODO: Update an icon for shortcut IME
final Map> shortcuts =
diff --git a/java/src/org/futo/inputmethod/latin/RichInputMethodSubtype.java b/java/src/org/futo/inputmethod/latin/RichInputMethodSubtype.java
index 45d0d8965..77c09eae0 100644
--- a/java/src/org/futo/inputmethod/latin/RichInputMethodSubtype.java
+++ b/java/src/org/futo/inputmethod/latin/RichInputMethodSubtype.java
@@ -209,14 +209,7 @@ public class RichInputMethodSubtype {
@Nonnull
public static RichInputMethodSubtype getNoLanguageSubtype() {
RichInputMethodSubtype noLanguageSubtype = sNoLanguageSubtype;
- if (noLanguageSubtype == null) {
- final InputMethodSubtype rawNoLanguageSubtype = RichInputMethodManager.getInstance()
- .findSubtypeByLocaleAndKeyboardLayoutSet(
- SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.QWERTY);
- if (rawNoLanguageSubtype != null) {
- noLanguageSubtype = new RichInputMethodSubtype(rawNoLanguageSubtype);
- }
- }
+
if (noLanguageSubtype != null) {
sNoLanguageSubtype = noLanguageSubtype;
return noLanguageSubtype;
@@ -230,14 +223,7 @@ public class RichInputMethodSubtype {
@Nonnull
public static RichInputMethodSubtype getEmojiSubtype() {
RichInputMethodSubtype emojiSubtype = sEmojiSubtype;
- if (emojiSubtype == null) {
- final InputMethodSubtype rawEmojiSubtype = RichInputMethodManager.getInstance()
- .findSubtypeByLocaleAndKeyboardLayoutSet(
- SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.EMOJI);
- if (rawEmojiSubtype != null) {
- emojiSubtype = new RichInputMethodSubtype(rawEmojiSubtype);
- }
- }
+
if (emojiSubtype != null) {
sEmojiSubtype = emojiSubtype;
return emojiSubtype;
diff --git a/java/src/org/futo/inputmethod/latin/Subtypes.kt b/java/src/org/futo/inputmethod/latin/Subtypes.kt
index 926561374..9ea2120f7 100644
--- a/java/src/org/futo/inputmethod/latin/Subtypes.kt
+++ b/java/src/org/futo/inputmethod/latin/Subtypes.kt
@@ -1,26 +1,256 @@
package org.futo.inputmethod.latin
import android.content.Context
+import android.content.Intent
import android.view.inputmethod.InputMethodManager
+import android.view.inputmethod.InputMethodSubtype
+import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.LocalContentColor
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalInspectionMode
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.core.stringSetPreferencesKey
+import okhttp3.internal.toImmutableList
+import org.futo.inputmethod.latin.common.Constants
import org.futo.inputmethod.latin.uix.SettingsKey
-import org.futo.inputmethod.latin.uix.setSetting
+import org.futo.inputmethod.latin.uix.getSettingBlocking
+import org.futo.inputmethod.latin.uix.setSettingBlocking
+import org.futo.inputmethod.latin.uix.settings.NavigationItem
+import org.futo.inputmethod.latin.uix.settings.NavigationItemStyle
+import org.futo.inputmethod.latin.uix.settings.SettingsActivity
+import org.futo.inputmethod.latin.uix.settings.useDataStoreValueBlocking
+import org.futo.inputmethod.latin.uix.theme.Typography
+import org.futo.inputmethod.latin.utils.SubtypeLocaleUtils
+import java.util.Locale
val SubtypesSetting = SettingsKey(
stringSetPreferencesKey("subtypes"),
setOf()
)
-suspend fun Context.saveSubtypes() {
- val inputMethodManager = getSystemService(android.inputmethodservice.InputMethodService.INPUT_METHOD_SERVICE) as InputMethodManager
- val inputMethodList = inputMethodManager.getEnabledInputMethodSubtypeList(
- RichInputMethodManager.getInstance().inputMethodInfoOfThisIme,
- true
- )
+val ActiveSubtype = SettingsKey(
+ stringPreferencesKey("activeSubtype"),
+ ""
+)
- val encodedSubtypes = inputMethodList.map {
- it.locale + ":" + (it.extraValue ?: "") + ":" + it.languageTag
- }.toSet()
+object Subtypes {
+ fun convertToSubtype(string: String): InputMethodSubtype {
+ val splits = string.split(":")
+ val locale = splits[0]
- setSetting(SubtypesSetting, encodedSubtypes)
+ val extraValue = splits.getOrNull(1) ?: ""
+ val languageTag = splits.getOrNull(2) ?: ""
+
+ return InputMethodSubtypeBuilder()
+ .setSubtypeLocale(locale)
+ .setSubtypeExtraValue(extraValue)
+ .setLanguageTag(languageTag)
+ .build()
+ }
+
+ fun getActiveSubtype(context: Context): InputMethodSubtype {
+ val activeSubtype = context.getSettingBlocking(ActiveSubtype).ifEmpty {
+ context.getSettingBlocking(SubtypesSetting).firstOrNull() ?: "en_US:"
+ }
+
+ return convertToSubtype(activeSubtype)
+ }
+
+ fun hasMultipleEnabledSubtypes(context: Context): Boolean {
+ return context.getSettingBlocking(SubtypesSetting).size > 1
+ }
+
+ fun subtypeToString(subtype: InputMethodSubtype): String {
+ return subtype.locale + ":" + (subtype.extraValue ?: "") + ":" + subtype.languageTag
+ }
+
+ fun removeLanguage(context: Context, entry: InputMethodSubtype) {
+ val value = subtypeToString(entry)
+ val currentSetting = context.getSettingBlocking(SubtypesSetting)
+
+ context.setSettingBlocking(SubtypesSetting.key, currentSetting.filter { it != value && it != value.replace("::", ":") }.toSet())
+
+ if(context.getSettingBlocking(ActiveSubtype) == value) {
+ context.setSettingBlocking(ActiveSubtype.key, currentSetting.find {
+ it != value
+ } ?: "")
+ }
+ }
+
+ fun addLanguage(context: Context, language: Locale, layout: String) {
+ val value = subtypeToString(
+ InputMethodSubtypeBuilder()
+ .setSubtypeLocale(language.toString())
+ .setSubtypeExtraValue("KeyboardLayoutSet=$layout")
+ .build()
+ )
+ val currentSetting = context.getSettingBlocking(SubtypesSetting)
+
+ context.setSettingBlocking(SubtypesSetting.key, currentSetting + setOf(value))
+ }
+
+ fun getName(inputMethodSubtype: InputMethodSubtype): String {
+ return SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(inputMethodSubtype)
+ }
+
+ fun getNameForLocale(locale: String): String {
+ return getName(InputMethodSubtypeBuilder().setSubtypeLocale(locale).build())
+ }
+
+ fun getLocale(locale: String): Locale {
+ return Locale.forLanguageTag(locale.replace("_", "-"))
+ }
+
+ fun getLocale(inputMethodSubtype: InputMethodSubtype): Locale {
+ return getLocale(inputMethodSubtype.locale)
+ }
+
+ fun getLayoutName(context: Context, layout: String): String {
+ val resourceId = context.resources.getIdentifier("layout_$layout", "string", context.packageName)
+ if(resourceId == 0){
+ return layout
+ } else {
+ return context.getString(resourceId)
+ }
+ }
+
+ fun layoutsMappedByLanguage(layouts: Set): Map> {
+ val subtypes = layouts.map {
+ convertToSubtype(it)
+ }
+
+ return HashMap>().apply {
+ subtypes.forEach {
+ val list = this.getOrPut(it.locale) { mutableListOf() }
+ list.add(it)
+ }
+ }.mapValues { it.value.toImmutableList() }
+ }
+}
+
+
+@Composable
+@Preview
+fun LanguageSwitcherDialog(
+ onDismiss: () -> Unit = { }
+) {
+ val inspection = LocalInspectionMode.current
+ val context = LocalContext.current
+ val subtypeSet = if(inspection) {
+ setOf("en_US:", "pt_PT:", "lt:", "fr:KeyboardLayoutSet=bepo:")
+ } else {
+ useDataStoreValueBlocking(SubtypesSetting)
+ }
+
+ val subtypes = remember(subtypeSet) {
+ Subtypes.layoutsMappedByLanguage(subtypeSet)
+ }
+
+ val keys = remember(subtypes) { subtypes.keys.toList().sorted() }
+
+ val activeSubtype = if(inspection) {
+ "pt_PT:"
+ } else {
+ useDataStoreValueBlocking(ActiveSubtype)
+ }
+
+ Surface(shape = RoundedCornerShape(48.dp), color = MaterialTheme.colorScheme.background) {
+ Column {
+ Spacer(modifier = Modifier.height(16.dp))
+ Text(
+ "Select language",
+ textAlign = TextAlign.Center,
+ style = Typography.titleLarge,
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(0.dp, 16.dp)
+ )
+
+ LazyColumn(modifier = Modifier.weight(1.0f)) {
+ items(keys) { locale ->
+
+ subtypes[locale]!!.forEach { subtype ->
+ val layout = Subtypes.getLayoutName(context,
+ subtype.getExtraValueOf(Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET) ?: ""
+ )
+
+ val title = if(inspection) { subtype.locale } else { Subtypes.getName(subtype) }
+
+ val selected = activeSubtype == Subtypes.subtypeToString(subtype)
+
+ val item = @Composable {
+ NavigationItem(
+ title = title,
+ subtitle = layout.ifBlank { null },
+ style = NavigationItemStyle.MiscNoArrow,
+ navigate = {
+ context.setSettingBlocking(ActiveSubtype.key, Subtypes.subtypeToString(subtype))
+ onDismiss()
+ }
+ )
+ }
+
+ if (selected) {
+ Surface(color = MaterialTheme.colorScheme.primary) {
+ CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onPrimary) {
+ item()
+ }
+ }
+ } else {
+ item()
+ }
+
+ }
+ }
+ }
+
+ Row(modifier = Modifier.height(64.dp)) {
+ Spacer(modifier = Modifier.weight(1.0f))
+ TextButton(onClick = {
+ val inputMethodManager =
+ context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+ inputMethodManager.showInputMethodPicker()
+
+ onDismiss()
+ }) {
+ Text("Switch Keyboard")
+ }
+ TextButton(onClick = {
+ val intent = Intent()
+ intent.setClass(context, SettingsActivity::class.java)
+ intent.setFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
+ )
+ intent.putExtra("navDest", "languages")
+ context.startActivity(intent)
+
+ onDismiss()
+ }) {
+ Text("Languages")
+ }
+ Spacer(modifier = Modifier.width(32.dp))
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/java/src/org/futo/inputmethod/latin/SystemBroadcastReceiver.java b/java/src/org/futo/inputmethod/latin/SystemBroadcastReceiver.java
index da4bfbc8a..cb6436c0e 100644
--- a/java/src/org/futo/inputmethod/latin/SystemBroadcastReceiver.java
+++ b/java/src/org/futo/inputmethod/latin/SystemBroadcastReceiver.java
@@ -59,12 +59,6 @@ public final class SystemBroadcastReceiver extends BroadcastReceiver {
final String intentAction = intent.getAction();
if (Intent.ACTION_MY_PACKAGE_REPLACED.equals(intentAction)) {
Log.i(TAG, "Package has been replaced: " + context.getPackageName());
- // Need to restore additional subtypes because system always clears additional
- // subtypes when the package is replaced.
- RichInputMethodManager.init(context);
- final RichInputMethodManager richImm = RichInputMethodManager.getInstance();
- final InputMethodSubtype[] additionalSubtypes = richImm.getAdditionalSubtypes();
- richImm.setAdditionalInputMethodSubtypes(additionalSubtypes);
} else if (Intent.ACTION_BOOT_COMPLETED.equals(intentAction)) {
Log.i(TAG, "Boot has been completed");
} else if (Intent.ACTION_LOCALE_CHANGED.equals(intentAction)) {
diff --git a/java/src/org/futo/inputmethod/latin/uix/ImportResourceActivity.kt b/java/src/org/futo/inputmethod/latin/uix/ImportResourceActivity.kt
index 4f237336f..83ee61047 100644
--- a/java/src/org/futo/inputmethod/latin/uix/ImportResourceActivity.kt
+++ b/java/src/org/futo/inputmethod/latin/uix/ImportResourceActivity.kt
@@ -38,7 +38,8 @@ import org.futo.inputmethod.latin.Dictionary
import org.futo.inputmethod.latin.LatinIMELegacy
import org.futo.inputmethod.latin.R
import org.futo.inputmethod.latin.ReadOnlyBinaryDictionary
-import org.futo.inputmethod.latin.RichInputMethodManager
+import org.futo.inputmethod.latin.Subtypes
+import org.futo.inputmethod.latin.SubtypesSetting
import org.futo.inputmethod.latin.uix.settings.NavigationItem
import org.futo.inputmethod.latin.uix.settings.NavigationItemStyle
import org.futo.inputmethod.latin.uix.settings.ScreenTitle
@@ -68,13 +69,16 @@ data class InputLanguage(
)
fun getActiveLanguages(context: Context): List {
- RichInputMethodManager.init(context)
-
- return RichInputMethodManager.getInstance().getMyEnabledInputMethodSubtypeList(true).map {
- val name = SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(it)
-
- InputLanguage(it.locale, name, it)
- }.toList()
+ SubtypeLocaleUtils.init(context)
+ return context.getSettingBlocking(SubtypesSetting)
+ .let { Subtypes.layoutsMappedByLanguage(it) }
+ .map {
+ InputLanguage(
+ it.value.first().locale,
+ Subtypes.getName(it.value.first()),
+ it.value.first()
+ )
+ }
}
diff --git a/java/src/org/futo/inputmethod/latin/uix/UixManager.kt b/java/src/org/futo/inputmethod/latin/uix/UixManager.kt
index 0933672c9..7bd827110 100644
--- a/java/src/org/futo/inputmethod/latin/uix/UixManager.kt
+++ b/java/src/org/futo/inputmethod/latin/uix/UixManager.kt
@@ -46,6 +46,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.futo.inputmethod.latin.AudioAndHapticFeedbackManager
import org.futo.inputmethod.latin.BuildConfig
+import org.futo.inputmethod.latin.LanguageSwitcherDialog
import org.futo.inputmethod.latin.LatinIME
import org.futo.inputmethod.latin.R
import org.futo.inputmethod.latin.SuggestedWords
@@ -57,6 +58,7 @@ import org.futo.inputmethod.latin.uix.actions.ActionRegistry
import org.futo.inputmethod.latin.uix.actions.EmojiAction
import org.futo.inputmethod.latin.uix.settings.SettingsActivity
import org.futo.inputmethod.latin.uix.theme.ThemeOption
+import org.futo.inputmethod.latin.uix.theme.UixThemeAuto
import org.futo.inputmethod.latin.uix.theme.UixThemeWrapper
import org.futo.inputmethod.updates.DISABLE_UPDATE_REMINDER
import org.futo.inputmethod.updates.autoDeferManualUpdateIfNeeded
@@ -66,7 +68,6 @@ import org.futo.inputmethod.updates.openManualUpdateCheck
import org.futo.inputmethod.updates.retrieveSavedLastUpdateCheckResult
import java.util.Locale
-
private class LatinIMEActionInputTransaction(
private val inputLogic: InputLogic,
shouldApplySpace: Boolean,
@@ -334,13 +335,13 @@ class UixManager(private val latinIME: LatinIME) {
}
}
- val wordBeingForgotten: MutableState = mutableStateOf(null)
- val forgetWordDismissed: MutableState = mutableStateOf(true)
+ private val wordBeingForgotten: MutableState = mutableStateOf(null)
+ private val forgetWordDismissed: MutableState = mutableStateOf(true)
@Composable
fun BoxScope.ForgetWordDialog() {
AnimatedVisibility(
- visible = forgetWordDismissed.value == false,
+ visible = !forgetWordDismissed.value,
modifier = Modifier.matchParentSize(),
enter = fadeIn(),
exit = fadeOut()
@@ -349,11 +350,13 @@ class UixManager(private val latinIME: LatinIME) {
Box(modifier = Modifier.matchParentSize()) {
Surface(
color = Color.Black.copy(alpha = 0.66f),
- modifier = Modifier.matchParentSize().pointerInput(Unit) {
- this.detectTapGestures(onPress = {
- forgetWordDismissed.value = true
- })
- }
+ modifier = Modifier
+ .matchParentSize()
+ .pointerInput(Unit) {
+ this.detectTapGestures(onPress = {
+ forgetWordDismissed.value = true
+ })
+ }
) { }
Surface(
@@ -405,6 +408,23 @@ class UixManager(private val latinIME: LatinIME) {
}
}
+ private var languageSwitcherDialog: DialogComposeView? = null
+ fun showLanguageSwitcher() {
+ // Dismiss old dialog
+ languageSwitcherDialog?.dismiss()
+
+ // Create new dialog
+ languageSwitcherDialog = createDialogComposeView(latinIME) {
+ UixThemeAuto {
+ LanguageSwitcherDialog(
+ onDismiss = { it.dismiss() }
+ )
+ }
+ }
+
+ languageSwitcherDialog?.show()
+ }
+
fun setContent() {
composeView?.setContent {
UixThemeWrapper(latinIME.colorScheme) {
@@ -522,6 +542,7 @@ class UixManager(private val latinIME: LatinIME) {
fun onInputFinishing() {
closeActionWindow()
+ languageSwitcherDialog?.dismiss()
}
fun cleanUpPersistentStates() {
diff --git a/java/src/org/futo/inputmethod/latin/uix/Utils.kt b/java/src/org/futo/inputmethod/latin/uix/Utils.kt
index 7a7bf939e..58580007f 100644
--- a/java/src/org/futo/inputmethod/latin/uix/Utils.kt
+++ b/java/src/org/futo/inputmethod/latin/uix/Utils.kt
@@ -1,8 +1,20 @@
package org.futo.inputmethod.latin.uix
+import android.app.Dialog
import android.content.Context
import android.util.TypedValue
+import android.view.Gravity
+import android.view.ViewGroup
+import android.view.Window
+import android.view.WindowManager
+import androidx.appcompat.content.res.AppCompatResources
import androidx.compose.material3.ColorScheme
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.platform.ComposeView
+import androidx.lifecycle.setViewTreeLifecycleOwner
+import androidx.savedstate.setViewTreeSavedStateRegistryOwner
+import org.futo.inputmethod.latin.LatinIME
+import org.futo.inputmethod.latin.R
import java.net.URLDecoder
import java.net.URLEncoder
@@ -29,4 +41,71 @@ fun String.urlEncode(): String {
fun String.urlDecode(): String {
return URLDecoder.decode(this, "utf-8")
+}
+
+
+// This ugly workaround is required as Android Compose freaks out when you use a Dialog outside of
+// an activity (i.e. in an input method service)
+data class DialogComposeView(
+ val dialog: Dialog,
+ val composeView: ComposeView
+)
+
+fun createDialogComposeView(
+ latinIME: LatinIME,
+ maxWidthProportion: Float = 0.9f,
+ maxHeightProportion: Float = 0.75f,
+ dimAmount: Float = 0.5f,
+ onDismiss: () -> Unit = { },
+ content: @Composable (Dialog) -> Unit,
+): DialogComposeView {
+ val context: Context = latinIME
+
+ val composeView = ComposeView(context)
+
+ val dialog = Dialog(context).apply {
+ requestWindowFeature(Window.FEATURE_NO_TITLE)
+ setContentView(composeView)
+
+ window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+
+ setOnDismissListener {
+ onDismiss()
+ }
+ }
+
+ val window = dialog.window
+ window?.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM or WindowManager.LayoutParams.FLAG_DIM_BEHIND)
+ window?.attributes?.token = latinIME.latinIMELegacy.mKeyboardSwitcher.mainKeyboardView.windowToken
+ window?.attributes?.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG
+
+ window?.apply {
+ val displayMetrics = context.resources.displayMetrics
+ val width = displayMetrics.widthPixels
+ val height = displayMetrics.heightPixels
+
+ val maxWidth = (width * maxWidthProportion).toInt()
+ val maxHeight = (height * maxHeightProportion).toInt()
+
+ setLayout(maxWidth, maxHeight)
+ setGravity(Gravity.CENTER)
+
+ setBackgroundDrawable(AppCompatResources.getDrawable(context, R.drawable.empty))
+ setDimAmount(dimAmount)
+ }
+
+ composeView.setViewTreeLifecycleOwner(latinIME)
+ composeView.setViewTreeSavedStateRegistryOwner(latinIME)
+
+ composeView.setContent { content(dialog) }
+
+ return DialogComposeView(dialog, composeView)
+}
+
+fun DialogComposeView.show() {
+ dialog.show()
+}
+
+fun DialogComposeView.dismiss() {
+ dialog.dismiss()
}
\ No newline at end of file
diff --git a/java/src/org/futo/inputmethod/latin/uix/actions/Registry.kt b/java/src/org/futo/inputmethod/latin/uix/actions/Registry.kt
index ab8728b1a..79368a827 100644
--- a/java/src/org/futo/inputmethod/latin/uix/actions/Registry.kt
+++ b/java/src/org/futo/inputmethod/latin/uix/actions/Registry.kt
@@ -20,6 +20,7 @@ val AllActions = listOf(
RedoAction,
VoiceInputAction,
SystemVoiceInputAction,
+ SwitchLanguageAction
)
@@ -70,7 +71,8 @@ val DefaultActions = listOf(
ClipboardAction,
SettingsAction,
ThemeAction,
- MemoryDebugAction
+ MemoryDebugAction,
+ SwitchLanguageAction
)
val DefaultActionsString = ActionRegistry.actionsToString(DefaultActions)
diff --git a/java/src/org/futo/inputmethod/latin/uix/actions/SwitchLanguageAction.kt b/java/src/org/futo/inputmethod/latin/uix/actions/SwitchLanguageAction.kt
new file mode 100644
index 000000000..2f20be335
--- /dev/null
+++ b/java/src/org/futo/inputmethod/latin/uix/actions/SwitchLanguageAction.kt
@@ -0,0 +1,32 @@
+package org.futo.inputmethod.latin.uix.actions
+
+import android.content.Context
+import org.futo.inputmethod.latin.ActiveSubtype
+import org.futo.inputmethod.latin.R
+import org.futo.inputmethod.latin.SubtypesSetting
+import org.futo.inputmethod.latin.uix.Action
+import org.futo.inputmethod.latin.uix.getSettingBlocking
+import org.futo.inputmethod.latin.uix.setSettingBlocking
+
+fun switchToNextLanguage(context: Context) {
+ val enabledSubtypes = context.getSettingBlocking(SubtypesSetting).toList()
+ val currentSubtype = context.getSettingBlocking(ActiveSubtype)
+
+ val index = enabledSubtypes.indexOf(currentSubtype)
+ val nextIndex = if(index == -1) {
+ 0
+ } else {
+ (index + 1) % enabledSubtypes.size
+ }
+
+ context.setSettingBlocking(ActiveSubtype.key, enabledSubtypes[nextIndex])
+}
+
+val SwitchLanguageAction = Action(
+ icon = R.drawable.globe,
+ name = R.string.show_language_switch_key,
+ simplePressImpl = { manager, _ ->
+ switchToNextLanguage(manager.getContext())
+ },
+ windowImpl = null,
+)
\ No newline at end of file
diff --git a/java/src/org/futo/inputmethod/latin/uix/settings/Components.kt b/java/src/org/futo/inputmethod/latin/uix/settings/Components.kt
index 5f898b82c..478f8243b 100644
--- a/java/src/org/futo/inputmethod/latin/uix/settings/Components.kt
+++ b/java/src/org/futo/inputmethod/latin/uix/settings/Components.kt
@@ -23,6 +23,10 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.ArrowForward
import androidx.compose.material.icons.filled.Send
+import androidx.compose.material3.DropdownMenuItem
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.ExposedDropdownMenuBox
+import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
@@ -539,3 +543,64 @@ fun SettingTextField(title: String, placeholder: String, field: SettingsKey DropDownPicker(
+ label: String,
+ options: List,
+ selection: T?,
+ onSet: (T) -> Unit,
+ getDisplayName: (T) -> String,
+ modifier: Modifier = Modifier
+) {
+ var expanded by remember { mutableStateOf(false) }
+ ExposedDropdownMenuBox(
+ expanded = expanded,
+ onExpandedChange = {
+ expanded = !expanded
+ },
+ modifier = modifier
+ ) {
+ TextField(
+ readOnly = true,
+ value = selection?.let(getDisplayName) ?: "None",
+ onValueChange = { },
+ label = if (label.isNotBlank()) {
+ { Text(label) }
+ } else {
+ null
+ },
+ trailingIcon = {
+ ExposedDropdownMenuDefaults.TrailingIcon(
+ expanded = expanded
+ )
+ },
+ colors = ExposedDropdownMenuDefaults.textFieldColors(
+ focusedLabelColor = MaterialTheme.colorScheme.onPrimaryContainer,
+ focusedLeadingIconColor = MaterialTheme.colorScheme.onPrimaryContainer,
+ focusedIndicatorColor = MaterialTheme.colorScheme.onPrimaryContainer,
+ focusedTrailingIconColor = MaterialTheme.colorScheme.onPrimaryContainer,
+ ),
+ modifier = Modifier.menuAnchor()
+ )
+ ExposedDropdownMenu(
+ expanded = expanded,
+ onDismissRequest = {
+ expanded = false
+ }
+ ) {
+ options.forEach { selectionOption ->
+ DropdownMenuItem(
+ text = {
+ Text(getDisplayName(selectionOption))
+ },
+ onClick = {
+ onSet(selectionOption)
+ expanded = false
+ }
+ )
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/java/src/org/futo/inputmethod/latin/uix/settings/SettingsNavigator.kt b/java/src/org/futo/inputmethod/latin/uix/settings/SettingsNavigator.kt
index 92b0cf0c0..1ccadbb22 100644
--- a/java/src/org/futo/inputmethod/latin/uix/settings/SettingsNavigator.kt
+++ b/java/src/org/futo/inputmethod/latin/uix/settings/SettingsNavigator.kt
@@ -11,6 +11,7 @@ import androidx.navigation.compose.rememberNavController
import org.futo.inputmethod.latin.R
import org.futo.inputmethod.latin.uix.ErrorDialog
import org.futo.inputmethod.latin.uix.InfoDialog
+import org.futo.inputmethod.latin.uix.settings.pages.AddLanguageScreen
import org.futo.inputmethod.latin.uix.settings.pages.AdvancedParametersScreen
import org.futo.inputmethod.latin.uix.settings.pages.BlacklistScreen
import org.futo.inputmethod.latin.uix.settings.pages.CreditsScreen
@@ -49,6 +50,7 @@ fun SettingsNavigator(
) {
composable("home") { HomeScreen(navController) }
composable("languages") { LanguagesScreen(navController) }
+ composable("addLanguage") { AddLanguageScreen(navController) }
composable("predictiveText") { PredictiveTextScreen(navController) }
composable("advancedparams") { AdvancedParametersScreen(navController) }
composable("typing") { TypingScreen(navController) }
diff --git a/java/src/org/futo/inputmethod/latin/uix/settings/pages/AddLanguage.kt b/java/src/org/futo/inputmethod/latin/uix/settings/pages/AddLanguage.kt
new file mode 100644
index 000000000..c27a2bf83
--- /dev/null
+++ b/java/src/org/futo/inputmethod/latin/uix/settings/pages/AddLanguage.kt
@@ -0,0 +1,160 @@
+package org.futo.inputmethod.latin.uix.settings.pages
+
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.material3.Button
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.navigation.NavHostController
+import androidx.navigation.compose.rememberNavController
+import org.futo.inputmethod.latin.Subtypes
+import org.futo.inputmethod.latin.uix.settings.DropDownPicker
+import org.futo.inputmethod.latin.uix.settings.ScreenTitle
+import org.futo.inputmethod.latin.uix.settings.ScrollableList
+import org.futo.inputmethod.latin.uix.settings.SettingItem
+
+val QwertyVariants = listOf("qwerty", "qwertz", "dvorak", "azerty", "colemak", "bepo", "pcqwerty")
+
+val locales = mapOf(
+ "af" to listOf("qwerty"),
+ "ar" to listOf("arabic"),
+ "az_AZ" to listOf("qwerty"),
+ "be_BY" to listOf("east_slavic"),
+ "bg" to listOf("bulgarian"),
+ "bg" to listOf("bulgarian_bds"),
+ "bn_BD" to listOf("bengali_akkhor"),
+ "bn_IN" to listOf("bengali"),
+ "ca" to listOf("spanish"),
+ "cs" to listOf("qwertz"),
+ "da" to listOf("nordic"),
+ "de" to listOf("qwertz"),
+ "de_CH" to listOf("swiss"),
+ "el" to listOf("greek"),
+ "en_IN" to listOf("qwerty"),
+ "en_US" to QwertyVariants,
+ "en_GB" to QwertyVariants,
+ "eo" to listOf("spanish"),
+ "es" to listOf("spanish"),
+ "es_US" to listOf("spanish"),
+ "es_419" to listOf("spanish"),
+ "et_EE" to listOf("nordic"),
+ "eu_ES" to listOf("spanish"),
+ "fa" to listOf("farsi"),
+ "fi" to listOf("nordic"),
+ "fr" to listOf("azerty", "qwerty", "swiss", "bepo"),
+ "fr_CA" to listOf("qwerty", "azerty", "swiss", "bepo"),
+ "fr_CH" to listOf("swiss", "qwerty", "azerty", "bepo"),
+ "gl_ES" to listOf("spanish"),
+ "hi" to listOf("hindi", "hindi_compact"),
+ //"hi_ZZ" to listOf("qwerty"),
+ "hr" to listOf("qwertz"),
+ "hu" to listOf("qwertz"),
+ "hy_AM" to listOf("armenian_phonetic"),
+ "in" to listOf("qwerty"),
+ "is" to listOf("qwerty"),
+ "it" to listOf("qwerty"),
+ "it_CH" to listOf("swiss"),
+ "iw" to listOf("hebrew"),
+ "ka_GE" to listOf("georgian"),
+ "kk" to listOf("east_slavic"),
+ "km_KH" to listOf("khmer"),
+ "kn_IN" to listOf("kannada"),
+ "ky" to listOf("east_slavic"),
+ "lo_LA" to listOf("lao"),
+ "lt" to listOf("qwerty"),
+ "lv" to listOf("qwerty"),
+ "mk" to listOf("south_slavic"),
+ "ml_IN" to listOf("malayalam"),
+ "mn_MN" to listOf("mongolian"),
+ "mr_IN" to listOf("marathi"),
+ "ms_MY" to listOf("qwerty"),
+ "nb" to listOf("nordic"),
+ "ne_NP" to listOf("nepali_romanized", "nepali_traditional"),
+ "nl" to listOf("qwerty"),
+ "nl_BE" to listOf("azerty"),
+ "pl" to listOf("qwerty"),
+ "pt_BR" to listOf("qwerty"),
+ "pt_PT" to listOf("qwerty"),
+ "ro" to listOf("qwerty"),
+ "ru" to listOf("east_slavic"),
+ "si_LK" to listOf("sinhala"),
+ "sk" to listOf("qwerty"),
+ "sl" to listOf("qwerty"),
+ "sr" to listOf("south_slavic"),
+ "sr_ZZ" to listOf("serbian_qwertz"),
+ "sv" to listOf("nordic"),
+ "sw" to listOf("qwerty"),
+ "ta_IN" to listOf("tamil"),
+ "ta_LK" to listOf("tamil"),
+ "ta_SG" to listOf("tamil"),
+ "te_IN" to listOf("telugu"),
+ "th" to listOf("thai"),
+ "tl" to listOf("spanish"),
+ "tr" to listOf("qwerty"),
+ "uk" to listOf("east_slavic"),
+ "uz_UZ" to listOf("uzbek"),
+ "vi" to listOf("qwerty"),
+ "zu" to listOf("qwerty"),
+ "zz" to listOf("qwerty"),
+)
+
+@Preview
+@Composable
+fun AddLanguageScreen(navController: NavHostController = rememberNavController()) {
+ val context = LocalContext.current
+
+ val selectedLocale: MutableState = remember { mutableStateOf(context.resources.configuration.locale.toString()) }
+ val selectedLayout: MutableState = remember { mutableStateOf("qwerty") }
+
+ val keys = remember { locales.keys.toList() }
+ ScrollableList {
+ ScreenTitle("Add Language", showBack = true, navController)
+
+ SettingItem(title = "Language") {
+ DropDownPicker(
+ "",
+ keys,
+ selectedLocale.value,
+ {
+ selectedLocale.value = it
+ selectedLayout.value = locales[it]!!.first()
+ },
+ {
+ Subtypes.getNameForLocale(it)
+ },
+ modifier = Modifier.width(180.dp)
+ )
+ }
+
+ SettingItem(title = "Layout") {
+ DropDownPicker(
+ "",
+ locales[selectedLocale.value] ?: listOf(),
+ selectedLayout.value,
+ { selectedLayout.value = it },
+ { Subtypes.getLayoutName(context, it) },
+ modifier = Modifier.width(180.dp)
+ )
+ }
+
+ Button(onClick = {
+ Subtypes.addLanguage(
+ context,
+ Subtypes.getLocale(selectedLocale.value),
+ selectedLayout.value
+ )
+
+ navController.navigateUp()
+ }, modifier = Modifier.fillMaxWidth().padding(16.dp)) {
+ Text("Add")
+ }
+ }
+}
\ No newline at end of file
diff --git a/java/src/org/futo/inputmethod/latin/uix/settings/pages/Credits.kt b/java/src/org/futo/inputmethod/latin/uix/settings/pages/Credits.kt
index 61d630154..407e0a93b 100644
--- a/java/src/org/futo/inputmethod/latin/uix/settings/pages/Credits.kt
+++ b/java/src/org/futo/inputmethod/latin/uix/settings/pages/Credits.kt
@@ -52,6 +52,11 @@ fun CreditsScreen(navController: NavHostController = rememberNavController()) {
modifier = Modifier.clickable {
context.openURI("https://github.com/gkonovalov/android-vad")
})
+
+ ParagraphText("Some keyboard layouts were taken from the CyanogenMod/LineageOS fork of the LatinIME keyboard. Their fork is Apache-2.0 licensed. Copyright (C) 2015 The CyanogenMod Project",
+ modifier = Modifier.clickable {
+ context.openURI("https://github.com/LineageOS/android_packages_inputmethods_LatinIME")
+ })
Spacer(modifier = Modifier.height(16.dp))
ParagraphText("Note: The authors listed above are not affiliated with us and do not endorse or promote us")
diff --git a/java/src/org/futo/inputmethod/latin/uix/settings/pages/Languages.kt b/java/src/org/futo/inputmethod/latin/uix/settings/pages/Languages.kt
index ee9925e80..1dddb3b42 100644
--- a/java/src/org/futo/inputmethod/latin/uix/settings/pages/Languages.kt
+++ b/java/src/org/futo/inputmethod/latin/uix/settings/pages/Languages.kt
@@ -1,32 +1,39 @@
package org.futo.inputmethod.latin.uix.settings.pages
-import android.content.Context
-import android.view.inputmethod.InputMethodManager
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Clear
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
-import androidx.compose.runtime.collectAsState
-import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
-import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
-import okhttp3.internal.toImmutableList
import org.futo.inputmethod.latin.BinaryDictionaryGetter
import org.futo.inputmethod.latin.R
-import org.futo.inputmethod.latin.RichInputMethodManager
-import org.futo.inputmethod.latin.saveSubtypes
+import org.futo.inputmethod.latin.Subtypes
+import org.futo.inputmethod.latin.SubtypesSetting
+import org.futo.inputmethod.latin.common.Constants
import org.futo.inputmethod.latin.uix.FileKind
import org.futo.inputmethod.latin.uix.ResourceHelper
import org.futo.inputmethod.latin.uix.getSetting
@@ -35,10 +42,10 @@ import org.futo.inputmethod.latin.uix.settings.NavigationItem
import org.futo.inputmethod.latin.uix.settings.NavigationItemStyle
import org.futo.inputmethod.latin.uix.settings.ScreenTitle
import org.futo.inputmethod.latin.uix.settings.ScrollableList
-import org.futo.inputmethod.latin.uix.settings.Tip
-import org.futo.inputmethod.latin.uix.settings.openLanguageSettings
+import org.futo.inputmethod.latin.uix.settings.SettingItem
+import org.futo.inputmethod.latin.uix.settings.useDataStoreValueBlocking
+import org.futo.inputmethod.latin.uix.theme.Typography
import org.futo.inputmethod.latin.uix.youAreImporting
-import org.futo.inputmethod.latin.utils.SubtypeLocaleUtils
import org.futo.inputmethod.latin.xlm.ModelPaths
import org.futo.inputmethod.updates.openURI
import java.util.Locale
@@ -101,27 +108,12 @@ fun LanguagesScreen(navController: NavHostController = rememberNavController())
val context = LocalContext.current
val deleteDialogInfo: MutableState = remember { mutableStateOf(null) }
- val inputMethodManager = remember { context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager }
- val inputMethodList = remember { mutableStateOf(
- inputMethodManager.getEnabledInputMethodSubtypeList(
- RichInputMethodManager.getInstance().inputMethodInfoOfThisIme,
- true
- ).toImmutableList()
- ) }
-
- val lifecycleOwner = LocalLifecycleOwner.current
- val lifecycleState by lifecycleOwner.lifecycle.currentStateFlow.collectAsState()
-
- LaunchedEffect(lifecycleState) {
- delay(250L)
- inputMethodList.value = inputMethodManager.getEnabledInputMethodSubtypeList(
- RichInputMethodManager.getInstance().inputMethodInfoOfThisIme,
- true
- )
-
- context.saveSubtypes()
+ val inputMethods = useDataStoreValueBlocking(SubtypesSetting)
+ val inputMethodList = remember(inputMethods) {
+ Subtypes.layoutsMappedByLanguage(inputMethods)
}
+ val inputMethodKeys = remember(inputMethodList) { inputMethodList.keys.toList().sorted() }
if(deleteDialogInfo.value != null) {
val info = deleteDialogInfo.value!!
@@ -139,17 +131,19 @@ fun LanguagesScreen(navController: NavHostController = rememberNavController())
ScreenTitle("Languages", showBack = true, navController)
NavigationItem(
- title = "Enable/disable languages",
+ title = "Add language",
style = NavigationItemStyle.Misc,
- navigate = { context.openLanguageSettings() },
+ navigate = {
+ navController.navigate("addLanguage")
+ },
)
- Tip("Note: This screen is a WIP, use the above option to toggle languages")
+ inputMethodKeys.forEach { localeString ->
+ val subtypes = inputMethodList[localeString]!!
- inputMethodList.value.forEach {
- val name = SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(it)
+ val locale = Subtypes.getLocale(localeString)
- val locale = Locale.forLanguageTag(it.locale.replace("_", "-"))
+ val name = Subtypes.getName(subtypes.first())
val voiceInputModelName = ResourceHelper.tryFindingVoiceInputModelForLocale(context, locale)?.name?.let { stringResource(it) }
val dictionaryName = runBlocking { ResourceHelper.findKeyForLocaleAndKind(context, locale, FileKind.Dictionary) }?.let {
@@ -170,7 +164,36 @@ fun LanguagesScreen(navController: NavHostController = rememberNavController())
transformerModel = transformerName
)
- ScreenTitle(name)
+ Row(modifier = Modifier.fillMaxWidth()) {
+ Spacer(modifier = Modifier.width(16.dp))
+
+ Column(modifier = Modifier.align(Alignment.CenterVertically).padding(0.dp, 16.dp)) {
+ Text(name, style = Typography.titleLarge)
+ if(subtypes.size == 1) {
+ val layout = Subtypes.getLayoutName(context,
+ subtypes.first().getExtraValueOf(Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET) ?: ""
+ )
+
+ Text(layout,
+ style = Typography.bodySmall,
+ color = MaterialTheme.colorScheme.outline)
+ }
+ }
+
+ Spacer(modifier = Modifier.weight(1.0f))
+
+ if(subtypes.size == 1) {
+ IconButton(modifier = Modifier.fillMaxHeight().align(Alignment.CenterVertically), onClick = {
+ Subtypes.removeLanguage(context, subtypes.first())
+ }) {
+ Icon(
+ Icons.Default.Clear,
+ contentDescription = "Remove language",
+ modifier = Modifier
+ )
+ }
+ }
+ }
NavigationItem(
title = options.voiceInputModel ?: "None",
@@ -208,6 +231,25 @@ fun LanguagesScreen(navController: NavHostController = rememberNavController())
},
icon = painterResource(id = R.drawable.cpu)
)
+ if(subtypes.size > 1) {
+ subtypes.forEach {
+ val layout = Subtypes.getLayoutName(
+ context,
+ it.getExtraValueOf(Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET)
+ )
+ SettingItem(title = "Layout $layout") {
+ IconButton(modifier = Modifier.fillMaxHeight(), onClick = {
+ Subtypes.removeLanguage(context, it)
+ }) {
+ Icon(
+ Icons.Default.Clear,
+ contentDescription = "Remove layout $layout",
+ modifier = Modifier
+ )
+ }
+ }
+ }
+ }
}
}
diff --git a/java/src/org/futo/inputmethod/latin/utils/DictionaryInfoUtils.java b/java/src/org/futo/inputmethod/latin/utils/DictionaryInfoUtils.java
index eacb6f3d8..6f35112bf 100644
--- a/java/src/org/futo/inputmethod/latin/utils/DictionaryInfoUtils.java
+++ b/java/src/org/futo/inputmethod/latin/utils/DictionaryInfoUtils.java
@@ -574,17 +574,6 @@ public class DictionaryInfoUtils {
addOrUpdateDictInfo(dictList, dictionaryInfo);
}
- // Generate the dictionary information from the enabled subtypes. This will not
- // overwrite the real records.
- RichInputMethodManager.init(context);
- List enabledSubtypes = RichInputMethodManager
- .getInstance().getMyEnabledInputMethodSubtypeList(true);
- for (InputMethodSubtype subtype : enabledSubtypes) {
- Locale locale = LocaleUtils.constructLocaleFromString(subtype.getLocale());
- DictionaryInfo dictionaryInfo = createDictionaryInfoFromLocale(locale);
- addOrUpdateDictInfo(dictList, dictionaryInfo);
- }
-
return dictList;
}
diff --git a/java/src/org/futo/inputmethod/latin/utils/SubtypeLocaleUtils.java b/java/src/org/futo/inputmethod/latin/utils/SubtypeLocaleUtils.java
index 43a10e227..da0248c1b 100644
--- a/java/src/org/futo/inputmethod/latin/utils/SubtypeLocaleUtils.java
+++ b/java/src/org/futo/inputmethod/latin/utils/SubtypeLocaleUtils.java
@@ -27,6 +27,7 @@ import android.util.Log;
import android.view.inputmethod.InputMethodSubtype;
import org.futo.inputmethod.latin.R;
+import org.futo.inputmethod.latin.Subtypes;
import org.futo.inputmethod.latin.common.LocaleUtils;
import org.futo.inputmethod.latin.common.StringUtils;
@@ -286,6 +287,19 @@ public final class SubtypeLocaleUtils {
final String replacementString = getReplacementString(subtype, displayLocale);
// TODO: rework this for multi-lingual subtypes
final int nameResId = subtype.getNameResId();
+
+ if(nameResId == 0) {
+ if(replacementString.isEmpty()) {
+ return StringUtils.capitalizeFirstCodePoint(
+ Subtypes.INSTANCE.getLocale(subtype).getDisplayName(displayLocale),
+ displayLocale);
+ } else {
+ return StringUtils.capitalizeFirstCodePoint(
+ replacementString,
+ displayLocale);
+ }
+ }
+
final RunInLocale getSubtypeName = new RunInLocale() {
@Override
protected String job(final Resources res) {