diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7bdd7fde..3f6e4c8d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ diff --git a/app/src/main/java/io/github/sspanak/tt9/ime/AbstractHandler.java b/app/src/main/java/io/github/sspanak/tt9/ime/AbstractHandler.java index 8862ee2b..7e73dd7f 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ime/AbstractHandler.java +++ b/app/src/main/java/io/github/sspanak/tt9/ime/AbstractHandler.java @@ -24,10 +24,11 @@ abstract public class AbstractHandler extends InputMethodService { // UI abstract protected void createSuggestionBar(View mainView); - abstract protected void forceShowWindow(); - abstract protected void renderMainView(); - abstract protected void setStatusIcon(InputMode mode); - abstract protected void setStatusText(String status); - abstract protected boolean shouldBeVisible(); + + + abstract protected InputMode getInputMode(); + abstract protected int getInputModeId(); + abstract protected SuggestionOps getSuggestionOps(); abstract protected boolean shouldBeOff(); + abstract protected TraditionalT9 getFinalContext(); } diff --git a/app/src/main/java/io/github/sspanak/tt9/ime/CommandHandler.java b/app/src/main/java/io/github/sspanak/tt9/ime/CommandHandler.java new file mode 100644 index 00000000..f33d27b8 --- /dev/null +++ b/app/src/main/java/io/github/sspanak/tt9/ime/CommandHandler.java @@ -0,0 +1,176 @@ +package io.github.sspanak.tt9.ime; + +import io.github.sspanak.tt9.R; +import io.github.sspanak.tt9.db.DictionaryLoader; +import io.github.sspanak.tt9.ime.modes.InputMode; +import io.github.sspanak.tt9.ime.modes.ModeABC; +import io.github.sspanak.tt9.languages.LanguageCollection; +import io.github.sspanak.tt9.ui.UI; +import io.github.sspanak.tt9.ui.dialogs.AddWordDialog; + +abstract class CommandHandler extends TypingHandler { + @Override + protected boolean onBack() { + if (mainView.isCommandPaletteShown()) { + mainView.hideCommandPalette(); + statusBar.setText(mInputMode); + return true; + } + + return false; + } + + + @Override + public boolean onBackspace() { + if (mainView.isCommandPaletteShown()) { + return false; + } + + return super.onBackspace(); + } + + + @Override + public boolean onHotkey(int keyCode, boolean repeat, boolean validateOnly) { + return mainView.isCommandPaletteShown(); + } + + + @Override + protected boolean onNumber(int key, boolean hold, int repeat) { + if (!shouldBeOff() && mainView.isCommandPaletteShown()) { + onCommand(key); + return true; + } + + return super.onNumber(key, hold, repeat); + } + + + @Override + public boolean onOK() { + return mainView.isCommandPaletteShown(); + } + + + private void onCommand(int key) { + switch (key) { + case 0: + changeKeyboard(); + break; + case 1: + showSettings(); + break; + case 2: + mainView.hideCommandPalette(); + statusBar.setText(mInputMode); + addWord(); + break; + } + } + + + public void addWord() { + if (mInputMode.isNumeric()) { + return; + } + + if (DictionaryLoader.getInstance(this).isRunning()) { + UI.toastShortSingle(this, R.string.dictionary_loading_please_wait); + return; + } + + suggestionOps.cancelDelayedAccept(); + mInputMode.onAcceptSuggestion(suggestionOps.acceptIncomplete()); + + String word = textField.getSurroundingWord(mLanguage); + if (word.isEmpty()) { + UI.toastLong(this, R.string.add_word_no_selection); + } else { + AddWordDialog.show(this, mLanguage.getId(), word); + } + } + + + public void changeKeyboard() { + suggestionOps.cancelDelayedAccept(); + UI.showChangeKeyboardDialog(this); + } + + + protected void nextInputMode() { + if (mInputMode.isPassthrough()) { + return; + } else if (allowedInputModes.size() == 1 && allowedInputModes.contains(InputMode.MODE_123)) { + mInputMode = !mInputMode.is123() ? InputMode.getInstance(settings, mLanguage, inputType, InputMode.MODE_123) : mInputMode; + } + // when typing a word or viewing scrolling the suggestions, only change the case + else if (!suggestionOps.isEmpty()) { + nextTextCase(); + } + // make "abc" and "ABC" separate modes from user perspective + else if (mInputMode instanceof ModeABC && mLanguage.hasUpperCase() && mInputMode.getTextCase() == InputMode.CASE_LOWER) { + mInputMode.nextTextCase(); + } else { + int nextModeIndex = (allowedInputModes.indexOf(mInputMode.getId()) + 1) % allowedInputModes.size(); + mInputMode = InputMode.getInstance(settings, mLanguage, inputType, allowedInputModes.get(nextModeIndex)); + mInputMode.setTextFieldCase(inputType.determineTextCase()); + mInputMode.determineNextWordTextCase(textField.getStringBeforeCursor()); + + resetKeyRepeat(); + } + + // save the settings for the next time + settings.saveInputMode(mInputMode.getId()); + settings.saveTextCase(mInputMode.getTextCase()); + + statusBar.setText(mInputMode); + } + + + protected void nextLang() { + // select the next language + int previous = mEnabledLanguages.indexOf(mLanguage.getId()); + int next = (previous + 1) % mEnabledLanguages.size(); + mLanguage = LanguageCollection.getLanguage(getApplicationContext(), mEnabledLanguages.get(next)); + + // validate and save it for the next time + validateLanguages(); + } + + + protected void nextTextCase() { + String currentSuggestionBefore = suggestionOps.getCurrent(); + int currentSuggestionIndex = suggestionOps.getCurrentIndex(); + + // When we are in AUTO mode and the dictionary word is in uppercase, + // the mode would switch to UPPERCASE, but visually, the word would not change. + // This is why we retry, until there is a visual change. + for (int retries = 0; retries < 2 && mInputMode.nextTextCase(); retries++) { + String currentSuggestionAfter = mInputMode.getSuggestions().size() >= suggestionOps.getCurrentIndex() ? mInputMode.getSuggestions().get(suggestionOps.getCurrentIndex()) : ""; + // If the suggestions are special characters, changing the text case means selecting the + // next character group. Hence, "before" and "after" are different. Also, if the new suggestion + // list is shorter, the "before" index may be invalid, so "after" would be empty. + // In these cases, we scroll to the first one, for consistency. + if (currentSuggestionAfter.isEmpty() || !currentSuggestionBefore.equalsIgnoreCase(currentSuggestionAfter)) { + currentSuggestionIndex = 0; + break; + } + + // the suggestion list is the same and the text case is different, so let's use it + if (!currentSuggestionBefore.equals(currentSuggestionAfter)) { + break; + } + } + + suggestionOps.set(mInputMode.getSuggestions(), currentSuggestionIndex); + textField.setComposingText(suggestionOps.getCurrent()); + } + + + public void showSettings() { + suggestionOps.cancelDelayedAccept(); + UI.showSettingsScreen(this); + } +} diff --git a/app/src/main/java/io/github/sspanak/tt9/ime/HotkeyHandler.java b/app/src/main/java/io/github/sspanak/tt9/ime/HotkeyHandler.java index fc6c8655..9918ed0d 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ime/HotkeyHandler.java +++ b/app/src/main/java/io/github/sspanak/tt9/ime/HotkeyHandler.java @@ -7,21 +7,19 @@ import android.view.inputmethod.InputConnection; import io.github.sspanak.tt9.R; import io.github.sspanak.tt9.db.DictionaryLoader; import io.github.sspanak.tt9.ime.helpers.TextField; -import io.github.sspanak.tt9.ime.modes.InputMode; -import io.github.sspanak.tt9.ime.modes.ModeABC; import io.github.sspanak.tt9.ime.modes.ModePredictive; import io.github.sspanak.tt9.languages.LanguageCollection; import io.github.sspanak.tt9.languages.LanguageKind; import io.github.sspanak.tt9.preferences.helpers.Hotkeys; import io.github.sspanak.tt9.ui.UI; -import io.github.sspanak.tt9.ui.dialogs.AddWordDialog; -public abstract class HotkeyHandler extends TypingHandler { +public abstract class HotkeyHandler extends CommandHandler { private boolean isSystemRTL; @Override protected void onInit() { + super.onInit(); if (settings.areHotkeysInitialized()) { Hotkeys.setDefault(settings); } @@ -35,12 +33,17 @@ public abstract class HotkeyHandler extends TypingHandler { } - @Override public boolean onBack() { - return settings.isMainLayoutNumpad(); + @Override + public boolean onBack() { + return super.onBack() || settings.isMainLayoutNumpad(); } @Override public boolean onOK() { + if (super.onOK()) { + return true; + } + suggestionOps.cancelDelayedAccept(); if (!suggestionOps.isEmpty()) { @@ -63,16 +66,16 @@ public abstract class HotkeyHandler extends TypingHandler { public boolean onHotkey(int keyCode, boolean repeat, boolean validateOnly) { + if (super.onHotkey(keyCode, repeat, validateOnly)) { + return true; + } + if (keyCode == KeyEvent.KEYCODE_UNKNOWN) { return false; } - if (keyCode == settings.getKeyAddWord()) { - return onKeyAddWord(validateOnly); - } - - if (keyCode == settings.getKeyChangeKeyboard()) { - return onKeyChangeKeyboard(validateOnly); + if (keyCode == settings.getKeyCommandPalette()) { + return onKeyCommandPalette(validateOnly); } if (keyCode == settings.getKeyFilterClear()) { @@ -99,55 +102,10 @@ public abstract class HotkeyHandler extends TypingHandler { return onKeyScrollSuggestion(validateOnly, false); } - if (keyCode == settings.getKeyShowSettings()) { - return onKeyShowSettings(validateOnly); - } - return false; } - public boolean onKeyAddWord(boolean validateOnly) { - if (shouldBeOff() || mInputMode.isNumeric()) { - return false; - } - - if (validateOnly) { - return true; - } - - if (DictionaryLoader.getInstance(this).isRunning()) { - UI.toastShortSingle(this, R.string.dictionary_loading_please_wait); - return true; - } - - suggestionOps.cancelDelayedAccept(); - mInputMode.onAcceptSuggestion(suggestionOps.acceptIncomplete()); - - String word = textField.getSurroundingWord(mLanguage); - if (word.isEmpty()) { - UI.toastLong(this, R.string.add_word_no_selection); - } else { - AddWordDialog.show(this, mLanguage.getId(), word); - } - - return true; - } - - - public boolean onKeyChangeKeyboard(boolean validateOnly) { - if (shouldBeOff()) { - return false; - } - - if (!validateOnly) { - UI.showChangeKeyboardDialog(this); - } - - return true; - } - - public boolean onKeyFilterClear(boolean validateOnly) { if (suggestionOps.isEmpty()) { return false; @@ -230,8 +188,8 @@ public abstract class HotkeyHandler extends TypingHandler { mInputMode.clearWordStem(); getSuggestions(); - setStatusText(mInputMode.toString()); - renderMainView(); + statusBar.setText(mInputMode); + mainView.render(); if (!suggestionOps.isEmpty() || settings.isMainLayoutStealth()) { UI.toastShortSingle(this, mInputMode.getClass().getSimpleName(), mInputMode.toString()); } @@ -256,7 +214,7 @@ public abstract class HotkeyHandler extends TypingHandler { suggestionOps.scheduleDelayedAccept(mInputMode.getAutoAcceptTimeout()); // restart the timer nextInputMode(); - renderMainView(); + mainView.render(); if (settings.isMainLayoutStealth()) { UI.toastShortSingle(this, mInputMode.getClass().getSimpleName(), mInputMode.toString()); @@ -267,86 +225,21 @@ public abstract class HotkeyHandler extends TypingHandler { } - public boolean onKeyShowSettings(boolean validateOnly) { + public boolean onKeyCommandPalette(boolean validateOnly) { if (shouldBeOff()) { return false; } if (!validateOnly) { suggestionOps.cancelDelayedAccept(); - UI.showSettingsScreen(this); + suggestionOps.acceptIncomplete(); + mInputMode.reset(); + + mainView.showCommandPalette(); + statusBar.setText(getString(R.string.commands_select_command)); + forceShowWindow(); } return true; } - - - private void nextInputMode() { - if (mInputMode.isPassthrough()) { - return; - } else if (allowedInputModes.size() == 1 && allowedInputModes.contains(InputMode.MODE_123)) { - mInputMode = !mInputMode.is123() ? InputMode.getInstance(settings, mLanguage, inputType, InputMode.MODE_123) : mInputMode; - } - // when typing a word or viewing scrolling the suggestions, only change the case - else if (!suggestionOps.isEmpty()) { - nextTextCase(); - } - // make "abc" and "ABC" separate modes from user perspective - else if (mInputMode instanceof ModeABC && mLanguage.hasUpperCase() && mInputMode.getTextCase() == InputMode.CASE_LOWER) { - mInputMode.nextTextCase(); - } else { - int nextModeIndex = (allowedInputModes.indexOf(mInputMode.getId()) + 1) % allowedInputModes.size(); - mInputMode = InputMode.getInstance(settings, mLanguage, inputType, allowedInputModes.get(nextModeIndex)); - mInputMode.setTextFieldCase(inputType.determineTextCase()); - mInputMode.determineNextWordTextCase(textField.getStringBeforeCursor()); - - resetKeyRepeat(); - } - - // save the settings for the next time - settings.saveInputMode(mInputMode.getId()); - settings.saveTextCase(mInputMode.getTextCase()); - - setStatusText(mInputMode.toString()); - } - - - protected void nextLang() { - // select the next language - int previous = mEnabledLanguages.indexOf(mLanguage.getId()); - int next = (previous + 1) % mEnabledLanguages.size(); - mLanguage = LanguageCollection.getLanguage(getApplicationContext(), mEnabledLanguages.get(next)); - - // validate and save it for the next time - validateLanguages(); - } - - - private void nextTextCase() { - String currentSuggestionBefore = suggestionOps.getCurrent(); - int currentSuggestionIndex = suggestionOps.getCurrentIndex(); - - // When we are in AUTO mode and the dictionary word is in uppercase, - // the mode would switch to UPPERCASE, but visually, the word would not change. - // This is why we retry, until there is a visual change. - for (int retries = 0; retries < 2 && mInputMode.nextTextCase(); retries++) { - String currentSuggestionAfter = mInputMode.getSuggestions().size() >= suggestionOps.getCurrentIndex() ? mInputMode.getSuggestions().get(suggestionOps.getCurrentIndex()) : ""; - // If the suggestions are special characters, changing the text case means selecting the - // next character group. Hence, "before" and "after" are different. Also, if the new suggestion - // list is shorter, the "before" index may be invalid, so "after" would be empty. - // In these cases, we scroll to the first one, for consistency. - if (currentSuggestionAfter.isEmpty() || !currentSuggestionBefore.equalsIgnoreCase(currentSuggestionAfter)) { - currentSuggestionIndex = 0; - break; - } - - // the suggestion list is the same and the text case is different, so let's use it - if (!currentSuggestionBefore.equals(currentSuggestionAfter)) { - break; - } - } - - suggestionOps.set(mInputMode.getSuggestions(), currentSuggestionIndex); - textField.setComposingText(suggestionOps.getCurrent()); - } } diff --git a/app/src/main/java/io/github/sspanak/tt9/ime/KeyPadHandler.java b/app/src/main/java/io/github/sspanak/tt9/ime/KeyPadHandler.java index ac8aa701..0e2011f2 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ime/KeyPadHandler.java +++ b/app/src/main/java/io/github/sspanak/tt9/ime/KeyPadHandler.java @@ -8,9 +8,7 @@ import io.github.sspanak.tt9.preferences.settings.SettingsStore; import io.github.sspanak.tt9.util.Timer; -abstract class KeyPadHandler extends AbstractHandler { - protected SettingsStore settings; - +abstract class KeyPadHandler extends UiHandler { // debounce handling private final static String DEBOUNCE_TIMER = "debounce_"; diff --git a/app/src/main/java/io/github/sspanak/tt9/ime/TraditionalT9.java b/app/src/main/java/io/github/sspanak/tt9/ime/TraditionalT9.java index 3e6b9e28..10a4eb35 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ime/TraditionalT9.java +++ b/app/src/main/java/io/github/sspanak/tt9/ime/TraditionalT9.java @@ -1,35 +1,26 @@ package io.github.sspanak.tt9.ime; import android.content.Intent; -import android.os.Build; import android.os.Handler; import android.os.Looper; import android.view.View; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; -import android.view.inputmethod.InputMethodManager; import androidx.annotation.NonNull; -import io.github.sspanak.tt9.R; import io.github.sspanak.tt9.db.DictionaryLoader; import io.github.sspanak.tt9.db.WordStoreAsync; -import io.github.sspanak.tt9.hacks.DeviceInfo; import io.github.sspanak.tt9.hacks.InputType; -import io.github.sspanak.tt9.ime.modes.InputMode; import io.github.sspanak.tt9.ime.modes.ModePredictive; import io.github.sspanak.tt9.preferences.settings.SettingsStore; import io.github.sspanak.tt9.ui.UI; import io.github.sspanak.tt9.ui.dialogs.PopupDialog; -import io.github.sspanak.tt9.ui.main.MainView; -import io.github.sspanak.tt9.ui.tray.StatusBar; import io.github.sspanak.tt9.util.Logger; public class TraditionalT9 extends MainViewOps { @NonNull private final Handler normalizationHandler = new Handler(Looper.getMainLooper()); - private MainView mainView = null; - private StatusBar statusBar = null; @Override @@ -46,14 +37,12 @@ public class TraditionalT9 extends MainViewOps { } - // Some devices have their own super.onCreateXxxView(), which does some magic allowing our MainView to remain visible. - // This is why we must call the super method, instead of returning null, as in the AOSP code. @Override public View onCreateInputView() { - mainView.forceCreateView(); + mainView.forceCreateInputView(); initTray(); setDarkTheme(); - setStatusText(mInputMode.toString()); + statusBar.setText(mInputMode); suggestionOps.set(mInputMode.getSuggestions()); return mainView.getView(); @@ -120,47 +109,11 @@ public class TraditionalT9 extends MainViewOps { @Override protected void onInit() { Logger.setLevel(settings.getLogLevel()); - WordStoreAsync.init(this); - - if (mainView == null) { - mainView = new MainView(this); - initTray(); - } - super.onInit(); } - private void initTray() { - setInputView(mainView.getView()); - createSuggestionBar(mainView.getView()); - statusBar = new StatusBar(mainView.getView()); - } - - - private void setDarkTheme() { - mainView.setDarkTheme(settings.getDarkTheme()); - statusBar.setDarkTheme(settings.getDarkTheme()); - suggestionOps.setDarkTheme(settings.getDarkTheme()); - } - - - private void initUi() { - if (mainView.createView()) { - initTray(); - } - setStatusIcon(mInputMode); - setStatusText(mInputMode.toString()); - setDarkTheme(); - mainView.render(); - - if (!isInputViewShown()) { - updateInputViewShown(); - } - } - - @Override protected boolean onStart(InputConnection connection, EditorInfo field) { if (!super.onStart(connection, field)) { @@ -189,7 +142,7 @@ public class TraditionalT9 extends MainViewOps { onFinishTyping(); suggestionOps.clear(); setStatusIcon(mInputMode); - setStatusText(mInputMode.toString()); + statusBar.setText(mInputMode); if (isInputViewShown()) { updateInputViewShown(); @@ -212,61 +165,8 @@ public class TraditionalT9 extends MainViewOps { } - /** - * Populates the UI elements with strings and icons - */ @Override - protected void renderMainView() { - mainView.render(); - } - - - /** - * forceShowWindow - * Some applications may hide our window and it remains invisible until the screen is touched or OK is pressed. - * This is fine for touchscreen keyboards, but the hardware keyboard allows typing even when the window and the suggestions - * are invisible. This function forces the InputMethodManager to show our window. - * WARNING! Calling this may cause a restart, which will cause InputMode to be recreated. Depending - * on how much time the restart takes, this may erase the current user input. - */ - @Override - protected void forceShowWindow() { - if (isInputViewShown() || !shouldBeVisible()) { - return; - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - requestShowSelf(DeviceInfo.isSonimGen2(getApplicationContext()) ? 0 : InputMethodManager.SHOW_IMPLICIT); - } else { - showWindow(true); - } - } - - - @Override - protected void setStatusIcon(InputMode mode) { - if (!mode.isPassthrough() && settings.isStatusIconEnabled()) { - showStatusIcon(R.drawable.ic_status); - } else { - hideStatusIcon(); - } - } - - - @Override - protected void setStatusText(String status) { - statusBar.setText(status); - } - - - @Override - protected boolean shouldBeVisible() { - return getInputModeId() != InputMode.MODE_PASSTHROUGH && !settings.isMainLayoutStealth(); - } - - - @Override - protected boolean shouldBeOff() { - return currentInputConnection == null || mInputMode.isPassthrough(); + protected TraditionalT9 getFinalContext() { + return this; } } diff --git a/app/src/main/java/io/github/sspanak/tt9/ime/TypingHandler.java b/app/src/main/java/io/github/sspanak/tt9/ime/TypingHandler.java index 6bb49904..28cb9d1b 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ime/TypingHandler.java +++ b/app/src/main/java/io/github/sspanak/tt9/ime/TypingHandler.java @@ -39,11 +39,16 @@ public abstract class TypingHandler extends KeyPadHandler { protected ArrayList mEnabledLanguages; protected Language mLanguage; - @Override + protected void createSuggestionBar(View mainView) { suggestionOps = new SuggestionOps(settings, mainView, this::onAcceptSuggestionsDelayed, this::onOK); } + + protected boolean shouldBeOff() { + return currentInputConnection == null || mInputMode.isPassthrough(); + } + @Override protected boolean onStart(InputConnection connection, EditorInfo field) { boolean restart = textField.equals(connection, field); @@ -302,6 +307,10 @@ public abstract class TypingHandler extends KeyPadHandler { } + @Override + public SuggestionOps getSuggestionOps() { + return suggestionOps; + } protected void getSuggestions() { if (mInputMode instanceof ModePredictive && DictionaryLoader.getInstance(this).isRunning()) { diff --git a/app/src/main/java/io/github/sspanak/tt9/ime/UiHandler.java b/app/src/main/java/io/github/sspanak/tt9/ime/UiHandler.java new file mode 100644 index 00000000..6007b4cb --- /dev/null +++ b/app/src/main/java/io/github/sspanak/tt9/ime/UiHandler.java @@ -0,0 +1,91 @@ +package io.github.sspanak.tt9.ime; + +import android.os.Build; +import android.view.inputmethod.InputMethodManager; + +import io.github.sspanak.tt9.R; +import io.github.sspanak.tt9.hacks.DeviceInfo; +import io.github.sspanak.tt9.ime.modes.InputMode; +import io.github.sspanak.tt9.preferences.settings.SettingsStore; +import io.github.sspanak.tt9.ui.main.MainView; +import io.github.sspanak.tt9.ui.tray.StatusBar; + +abstract class UiHandler extends AbstractHandler { + protected SettingsStore settings; + protected MainView mainView = null; + protected StatusBar statusBar = null; + + + @Override + protected void onInit() { + if (mainView == null) { + mainView = new MainView(getFinalContext()); + initTray(); + } + } + + + protected void initTray() { + setInputView(mainView.getView()); + createSuggestionBar(mainView.getView()); + statusBar = new StatusBar(mainView.getView()); + } + + + protected void initUi() { + if (mainView.createInputView()) { + initTray(); + } + setDarkTheme(); + setStatusIcon(getInputMode()); + statusBar.setText(getInputMode()); + mainView.hideCommandPalette(); + mainView.render(); + + if (!isInputViewShown()) { + updateInputViewShown(); + } + } + + + protected void setDarkTheme() { + mainView.setDarkTheme(settings.getDarkTheme()); + statusBar.setDarkTheme(settings.getDarkTheme()); + getSuggestionOps().setDarkTheme(settings.getDarkTheme()); + } + + + protected void setStatusIcon(InputMode mode) { + if (!mode.isPassthrough() && settings.isStatusIconEnabled()) { + showStatusIcon(R.drawable.ic_status); + } else { + hideStatusIcon(); + } + } + + + protected boolean shouldBeVisible() { + return getInputModeId() != InputMode.MODE_PASSTHROUGH && !settings.isMainLayoutStealth(); + } + + + /** + * forceShowWindow + * Some applications may hide our window and it remains invisible until the screen is touched or OK is pressed. + * This is fine for touchscreen keyboards, but the hardware keyboard allows typing even when the window and the suggestions + * are invisible. This function forces the InputMethodManager to show our window. + * WARNING! Calling this may cause a restart, which will cause InputMode to be recreated. Depending + * on how much time the restart takes, this may erase the current user input. + */ + protected void forceShowWindow() { + if (isInputViewShown() || !shouldBeVisible()) { + return; + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + requestShowSelf(DeviceInfo.isSonimGen2(getApplicationContext()) ? 0 : InputMethodManager.SHOW_IMPLICIT); + } else { + showWindow(true); + } + } +} diff --git a/app/src/main/java/io/github/sspanak/tt9/ime/helpers/Key.java b/app/src/main/java/io/github/sspanak/tt9/ime/helpers/Key.java index 9ee57aea..ab360df8 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ime/helpers/Key.java +++ b/app/src/main/java/io/github/sspanak/tt9/ime/helpers/Key.java @@ -37,16 +37,14 @@ public class Key { public static boolean isHotkey(SettingsStore settings, int keyCode) { - return keyCode == settings.getKeyAddWord() - || keyCode == settings.getKeyBackspace() - || keyCode == settings.getKeyChangeKeyboard() + return keyCode == settings.getKeyBackspace() + || keyCode == settings.getKeyCommandPalette() || keyCode == settings.getKeyFilterClear() || keyCode == settings.getKeyFilterSuggestions() || keyCode == settings.getKeyPreviousSuggestion() || keyCode == settings.getKeyNextSuggestion() || keyCode == settings.getKeyNextInputMode() - || keyCode == settings.getKeyNextLanguage() - || keyCode == settings.getKeyShowSettings(); + || keyCode == settings.getKeyNextLanguage(); } diff --git a/app/src/main/java/io/github/sspanak/tt9/preferences/helpers/Hotkeys.java b/app/src/main/java/io/github/sspanak/tt9/preferences/helpers/Hotkeys.java index 49a21b40..47f5e4d5 100644 --- a/app/src/main/java/io/github/sspanak/tt9/preferences/helpers/Hotkeys.java +++ b/app/src/main/java/io/github/sspanak/tt9/preferences/helpers/Hotkeys.java @@ -67,16 +67,14 @@ public class Hotkeys { int previousSuggestion = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_DPAD_LEFT) ? KeyEvent.KEYCODE_DPAD_LEFT : 0; settings.setDefaultKeys( - KeyEvent.KEYCODE_STAR, backspace, - 0, // "change keyboard" is unassigned by default + KeyEvent.KEYCODE_STAR, clearFilter, filter, previousSuggestion, nextSuggestion, KeyEvent.KEYCODE_POUND, - -KeyEvent.KEYCODE_POUND, // negative means "hold" - -KeyEvent.KEYCODE_STAR + -KeyEvent.KEYCODE_POUND // negative means "hold" ); } diff --git a/app/src/main/java/io/github/sspanak/tt9/preferences/screens/hotkeys/HotkeysScreen.java b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/hotkeys/HotkeysScreen.java index fec7d439..cbd31140 100644 --- a/app/src/main/java/io/github/sspanak/tt9/preferences/screens/hotkeys/HotkeysScreen.java +++ b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/hotkeys/HotkeysScreen.java @@ -20,16 +20,14 @@ public class HotkeysScreen extends BaseScreenFragment { @Override public void onCreate() { DropDownPreference[] dropDowns = { - findPreference(SectionKeymap.ITEM_ADD_WORD), findPreference(SectionKeymap.ITEM_BACKSPACE), - findPreference(SectionKeymap.ITEM_CHANGE_KEYBOARD), + findPreference(SectionKeymap.ITEM_COMMAND_PALETTE), findPreference(SectionKeymap.ITEM_FILTER_CLEAR), findPreference(SectionKeymap.ITEM_FILTER_SUGGESTIONS), findPreference(SectionKeymap.ITEM_PREVIOUS_SUGGESTION), findPreference(SectionKeymap.ITEM_NEXT_SUGGESTION), findPreference(SectionKeymap.ITEM_NEXT_INPUT_MODE), findPreference(SectionKeymap.ITEM_NEXT_LANGUAGE), - findPreference(SectionKeymap.ITEM_SHOW_SETTINGS), }; SectionKeymap section = new SectionKeymap(Arrays.asList(dropDowns), activity); section.populate().activate(); diff --git a/app/src/main/java/io/github/sspanak/tt9/preferences/screens/hotkeys/SectionKeymap.java b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/hotkeys/SectionKeymap.java index b09380f8..09c4d6b6 100644 --- a/app/src/main/java/io/github/sspanak/tt9/preferences/screens/hotkeys/SectionKeymap.java +++ b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/hotkeys/SectionKeymap.java @@ -12,16 +12,14 @@ import io.github.sspanak.tt9.preferences.settings.SettingsStore; import io.github.sspanak.tt9.util.Logger; public class SectionKeymap { - public static final String ITEM_ADD_WORD = "key_add_word"; public static final String ITEM_BACKSPACE = "key_backspace"; - public static final String ITEM_CHANGE_KEYBOARD = "key_change_keyboard"; + public static final String ITEM_COMMAND_PALETTE = "key_command_palette"; public static final String ITEM_FILTER_CLEAR = "key_filter_clear"; public static final String ITEM_FILTER_SUGGESTIONS = "key_filter_suggestions"; public static final String ITEM_PREVIOUS_SUGGESTION = "key_previous_suggestion"; public static final String ITEM_NEXT_SUGGESTION = "key_next_suggestion"; public static final String ITEM_NEXT_INPUT_MODE = "key_next_input_mode"; public static final String ITEM_NEXT_LANGUAGE = "key_next_language"; - public static final String ITEM_SHOW_SETTINGS = "key_show_settings"; private final Hotkeys hotkeys; private final Collection items; @@ -116,7 +114,7 @@ public class SectionKeymap { private void previewCurrentKey(DropDownPreference dropDown) { - previewCurrentKey(dropDown, dropDown.getValue()); + previewCurrentKey(dropDown, dropDown != null ? dropDown.getValue() : null); } diff --git a/app/src/main/java/io/github/sspanak/tt9/preferences/settings/SettingsHotkeys.java b/app/src/main/java/io/github/sspanak/tt9/preferences/settings/SettingsHotkeys.java index b005affe..fbdb0fc5 100644 --- a/app/src/main/java/io/github/sspanak/tt9/preferences/settings/SettingsHotkeys.java +++ b/app/src/main/java/io/github/sspanak/tt9/preferences/settings/SettingsHotkeys.java @@ -9,33 +9,29 @@ class SettingsHotkeys extends SettingsHacks { SettingsHotkeys(Context context) { super(context); } public boolean areHotkeysInitialized() { - return !prefs.getBoolean("hotkeys_initialized", false); + return !prefs.getBoolean("hotkeys_v2_initialized", false); } public void setDefaultKeys( - int addWord, int backspace, - int changeKeyboard, + int comandPalette, int filterClear, int filterSuggestions, int previousSuggestion, int nextSuggestion, int nextInputMode, - int nextLanguage, - int showSettings + int nextLanguage ) { prefsEditor - .putString(SectionKeymap.ITEM_ADD_WORD, String.valueOf(addWord)) .putString(SectionKeymap.ITEM_BACKSPACE, String.valueOf(backspace)) - .putString(SectionKeymap.ITEM_CHANGE_KEYBOARD, String.valueOf(changeKeyboard)) + .putString(SectionKeymap.ITEM_COMMAND_PALETTE, String.valueOf(comandPalette)) .putString(SectionKeymap.ITEM_FILTER_CLEAR, String.valueOf(filterClear)) .putString(SectionKeymap.ITEM_FILTER_SUGGESTIONS, String.valueOf(filterSuggestions)) .putString(SectionKeymap.ITEM_PREVIOUS_SUGGESTION, String.valueOf(previousSuggestion)) .putString(SectionKeymap.ITEM_NEXT_SUGGESTION, String.valueOf(nextSuggestion)) .putString(SectionKeymap.ITEM_NEXT_INPUT_MODE, String.valueOf(nextInputMode)) .putString(SectionKeymap.ITEM_NEXT_LANGUAGE, String.valueOf(nextLanguage)) - .putString(SectionKeymap.ITEM_SHOW_SETTINGS, String.valueOf(showSettings)) - .putBoolean("hotkeys_initialized", true) + .putBoolean("hotkeys_v2_initialized", true) .apply(); } @@ -45,15 +41,9 @@ class SettingsHotkeys extends SettingsHacks { } - public int getKeyAddWord() { - return getFunctionKey(SectionKeymap.ITEM_ADD_WORD); - } public int getKeyBackspace() { return getFunctionKey(SectionKeymap.ITEM_BACKSPACE); } - public int getKeyChangeKeyboard() { - return getFunctionKey(SectionKeymap.ITEM_CHANGE_KEYBOARD); - } public int getKeyFilterClear() { return getFunctionKey(SectionKeymap.ITEM_FILTER_CLEAR); } @@ -72,7 +62,7 @@ class SettingsHotkeys extends SettingsHacks { public int getKeyNextLanguage() { return getFunctionKey(SectionKeymap.ITEM_NEXT_LANGUAGE); } - public int getKeyShowSettings() { - return getFunctionKey(SectionKeymap.ITEM_SHOW_SETTINGS); + public int getKeyCommandPalette() { + return getFunctionKey(SectionKeymap.ITEM_COMMAND_PALETTE); } } diff --git a/app/src/main/java/io/github/sspanak/tt9/ui/ActivityWithNavigation.java b/app/src/main/java/io/github/sspanak/tt9/ui/ActivityWithNavigation.java index c420af3a..d5d15041 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ui/ActivityWithNavigation.java +++ b/app/src/main/java/io/github/sspanak/tt9/ui/ActivityWithNavigation.java @@ -25,6 +25,13 @@ abstract public class ActivityWithNavigation extends AppCompatActivity { private int lastKey = KeyEvent.KEYCODE_UNKNOWN; + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getSettings(); + } + + @Override public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) { super.onCreate(savedInstanceState, persistentState); diff --git a/app/src/main/java/io/github/sspanak/tt9/ui/main/BaseMainLayout.java b/app/src/main/java/io/github/sspanak/tt9/ui/main/BaseMainLayout.java index 37c0e71f..59846afc 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ui/main/BaseMainLayout.java +++ b/app/src/main/java/io/github/sspanak/tt9/ui/main/BaseMainLayout.java @@ -15,7 +15,8 @@ abstract class BaseMainLayout { private final int xml; protected View view = null; - @NonNull protected ArrayList keys = new ArrayList<>(); + @NonNull protected final ArrayList keys = new ArrayList<>(); + BaseMainLayout(TraditionalT9 tt9, int xml) { this.tt9 = tt9; @@ -33,24 +34,24 @@ abstract class BaseMainLayout { * More info: * ... */ - abstract public void setDarkTheme(boolean yes); - - - /** - * render - * Do all the necessary stuff to display the View. - */ - abstract public void render(); + void setDarkTheme(boolean dark) {} /** * getKeys - * Returns a list of all the usable Soft Keys. + * Returns a list of all the usable Soft Keys. Useful for attaching click handlers and changing + * the color theme. */ - abstract protected ArrayList getKeys(); + @NonNull protected ArrayList getKeys() { return keys; } + + /** + * getSeparators + * Returns a list of all the separators in the layout so that they can be themed properly. + */ + protected ArrayList getSeparators() { return new ArrayList<>(); } - public View getView() { + protected View getView() { if (view == null) { view = View.inflate(tt9.getApplicationContext(), xml, null); } @@ -59,7 +60,7 @@ abstract class BaseMainLayout { } - public void enableClickHandlers() { + protected void enableClickHandlers() { for (SoftKey key : getKeys()) { key.setTT9(tt9); } @@ -80,4 +81,11 @@ abstract class BaseMainLayout { return keyList; } + + + /** + * render + * Do all the necessary stuff to display the View. + */ + abstract void render(); } diff --git a/app/src/main/java/io/github/sspanak/tt9/ui/main/MainLayoutNumpad.java b/app/src/main/java/io/github/sspanak/tt9/ui/main/MainLayoutNumpad.java index b4115423..32af0cd9 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ui/main/MainLayoutNumpad.java +++ b/app/src/main/java/io/github/sspanak/tt9/ui/main/MainLayoutNumpad.java @@ -3,6 +3,7 @@ package io.github.sspanak.tt9.ui.main; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; import java.util.ArrayList; @@ -17,29 +18,38 @@ class MainLayoutNumpad extends BaseMainLayout { super(tt9, R.layout.main_numpad); } + + private int getBackgroundColor(@NonNull View contextView, boolean dark) { + return ContextCompat.getColor( + contextView.getContext(), + dark ? R.color.dark_numpad_background : R.color.numpad_background + ); + } + + + private int getSeparatorColor(@NonNull View contextView, boolean dark) { + return ContextCompat.getColor( + contextView.getContext(), + dark ? R.color.dark_numpad_separator : R.color.numpad_separator + ); + } + @Override - public void setDarkTheme(boolean darkEnabled) { + void setDarkTheme(boolean dark) { if (view == null) { return; } // background - view.setBackground(ContextCompat.getDrawable( - view.getContext(), - darkEnabled ? R.color.dark_numpad_background : R.color.numpad_background - )); + view.setBackgroundColor(getBackgroundColor(view, dark)); // text for (SoftKey key : getKeys()) { - key.setDarkTheme(darkEnabled); + key.setDarkTheme(dark); } // separators - int separatorColor = ContextCompat.getColor( - view.getContext(), - darkEnabled ? R.color.dark_numpad_separator : R.color.numpad_separator - ); - + int separatorColor = getSeparatorColor(view, dark); for (View separator : getSeparators()) { if (separator != null) { separator.setBackgroundColor(separatorColor); @@ -48,7 +58,7 @@ class MainLayoutNumpad extends BaseMainLayout { } @Override - public void render() { + void render() { getView(); enableClickHandlers(); for (SoftKey key : getKeys()) { @@ -56,6 +66,7 @@ class MainLayoutNumpad extends BaseMainLayout { } } + @NonNull @Override protected ArrayList getKeys() { if (!keys.isEmpty()) { diff --git a/app/src/main/java/io/github/sspanak/tt9/ui/main/MainLayoutSmall.java b/app/src/main/java/io/github/sspanak/tt9/ui/main/MainLayoutSmall.java index f4782d52..1450713a 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ui/main/MainLayoutSmall.java +++ b/app/src/main/java/io/github/sspanak/tt9/ui/main/MainLayoutSmall.java @@ -1,9 +1,9 @@ package io.github.sspanak.tt9.ui.main; -import android.graphics.drawable.Drawable; +import android.view.View; import android.widget.LinearLayout; -import androidx.core.content.ContextCompat; +import androidx.annotation.NonNull; import java.util.ArrayList; @@ -23,34 +23,28 @@ class MainLayoutSmall extends MainLayoutTray { } } + @NonNull @Override protected ArrayList getKeys() { if (view != null && keys.isEmpty()) { - keys = getKeysFromContainer(view.findViewById(R.id.main_soft_keys)); + super.getKeys(); + keys.addAll(getKeysFromContainer(view.findViewById(R.id.main_soft_keys))); } return keys; } @Override - public void setDarkTheme(boolean darkEnabled) { - if (view == null) { - return; - } + protected ArrayList getSeparators() { + ArrayList separators = super.getSeparators(); + separators.add(view.findViewById(R.id.main_separator_left)); + separators.add(view.findViewById(R.id.main_separator_right)); - super.setDarkTheme(darkEnabled); + return separators; + } - // text - for (SoftKey key : getKeys()) { - key.setDarkTheme(darkEnabled); - } - - // separators - Drawable separatorColor = ContextCompat.getDrawable( - view.getContext(), - darkEnabled ? R.drawable.button_separator_dark : R.drawable.button_separator - ); - - view.findViewById(R.id.main_separator_left).setBackground(separatorColor); - view.findViewById(R.id.main_separator_right).setBackground(separatorColor); + @Override + void setDarkTheme(boolean dark) { + super.setDarkTheme(dark); + view.findViewById(R.id.main_soft_keys).setBackground(getBackgroundColor(view, dark)); } } diff --git a/app/src/main/java/io/github/sspanak/tt9/ui/main/MainLayoutStealth.java b/app/src/main/java/io/github/sspanak/tt9/ui/main/MainLayoutStealth.java index 7e4e3caa..3081977a 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ui/main/MainLayoutStealth.java +++ b/app/src/main/java/io/github/sspanak/tt9/ui/main/MainLayoutStealth.java @@ -1,15 +1,10 @@ package io.github.sspanak.tt9.ui.main; -import java.util.ArrayList; - import io.github.sspanak.tt9.R; import io.github.sspanak.tt9.ime.TraditionalT9; -import io.github.sspanak.tt9.ui.main.keys.SoftKey; class MainLayoutStealth extends BaseMainLayout { MainLayoutStealth(TraditionalT9 tt9) { super(tt9, R.layout.main_stealth); } - @Override public void render() {} - @Override public void setDarkTheme(boolean y) {} - @Override protected ArrayList getKeys() { return keys; } + @Override void render() {} } diff --git a/app/src/main/java/io/github/sspanak/tt9/ui/main/MainLayoutTray.java b/app/src/main/java/io/github/sspanak/tt9/ui/main/MainLayoutTray.java index 2b68dc17..cf9468bc 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ui/main/MainLayoutTray.java +++ b/app/src/main/java/io/github/sspanak/tt9/ui/main/MainLayoutTray.java @@ -1,10 +1,14 @@ package io.github.sspanak.tt9.ui.main; +import android.graphics.drawable.Drawable; +import android.view.View; import android.widget.LinearLayout; +import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; import java.util.ArrayList; +import java.util.Arrays; import io.github.sspanak.tt9.R; import io.github.sspanak.tt9.ime.TraditionalT9; @@ -21,26 +25,61 @@ class MainLayoutTray extends BaseMainLayout { } } - @Override - protected ArrayList getKeys() { - return keys; + void showCommandPalette() { + view.findViewById(R.id.main_command_keys).setVisibility(LinearLayout.VISIBLE); + view.findViewById(R.id.main_soft_keys).setVisibility(LinearLayout.GONE); + } + + void hideCommandPalette() { + view.findViewById(R.id.main_command_keys).setVisibility(LinearLayout.GONE); + if (this instanceof MainLayoutSmall) { + view.findViewById(R.id.main_soft_keys).setVisibility(LinearLayout.VISIBLE); + } + } + + boolean isCommandPaletteShown() { + return view.findViewById(R.id.main_command_keys).getVisibility() == LinearLayout.VISIBLE; + } + + protected Drawable getBackgroundColor(@NonNull View contextView, boolean dark) { + return ContextCompat.getDrawable( + contextView.getContext(), + dark ? R.drawable.button_background_dark : R.drawable.button_background + ); + } + + protected Drawable getSeparatorColor(@NonNull View contextView, boolean dark) { + return ContextCompat.getDrawable( + contextView.getContext(), + dark ? R.drawable.button_separator_dark : R.drawable.button_separator + ); } @Override - public void setDarkTheme(boolean darkEnabled) { + void setDarkTheme(boolean dark) { if (view == null) { return; } // background - view.findViewById(R.id.main_soft_keys).setBackground(ContextCompat.getDrawable( - view.getContext(), - darkEnabled ? R.drawable.button_background_dark : R.drawable.button_background - )); + view.findViewById(R.id.main_command_keys).setBackground(getBackgroundColor(view, dark)); + + // text + for (SoftKey key : getKeys()) { + key.setDarkTheme(dark); + } + + // separators + Drawable separatorColor = getSeparatorColor(view, dark); + for (View separator : getSeparators()) { + if (separator != null) { + separator.setBackground(separatorColor); + } + } } @Override - public void render() { + void render() { getView(); enableClickHandlers(); setSoftKeysVisibility(); @@ -48,4 +87,23 @@ class MainLayoutTray extends BaseMainLayout { key.render(); } } + + @NonNull + @Override + protected ArrayList getKeys() { + if (view != null && keys.isEmpty()) { + keys.addAll(getKeysFromContainer(view.findViewById(R.id.main_command_keys))); + } + return keys; + } + + @Override + protected ArrayList getSeparators() { + return new ArrayList<>(Arrays.asList( + view.findViewById(R.id.separator_2_1), + view.findViewById(R.id.separator_2_2), + view.findViewById(R.id.separator_3_1), + view.findViewById(R.id.separator_3_2) + )); + } } diff --git a/app/src/main/java/io/github/sspanak/tt9/ui/main/MainView.java b/app/src/main/java/io/github/sspanak/tt9/ui/main/MainView.java index 9e72ca5c..68bace7b 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ui/main/MainView.java +++ b/app/src/main/java/io/github/sspanak/tt9/ui/main/MainView.java @@ -13,10 +13,10 @@ public class MainView { public MainView(TraditionalT9 tt9) { this.tt9 = tt9; - forceCreateView(); + forceCreateInputView(); } - public boolean createView() { + public boolean createInputView() { SettingsStore settings = tt9.getSettings(); if (settings.isMainLayoutNumpad() && !(main instanceof MainLayoutNumpad)) { @@ -35,10 +35,9 @@ public class MainView { return true; } - - public void forceCreateView() { + public void forceCreateInputView() { main = null; - if (!createView()) { + if (!createInputView()) { Logger.w(getClass().getSimpleName(), "Invalid MainView setting. Creating default."); main = new MainLayoutSmall(tt9); } @@ -55,4 +54,20 @@ public class MainView { public void setDarkTheme(boolean darkEnabled) { main.setDarkTheme(darkEnabled); } + + public void showCommandPalette() { + if (main instanceof MainLayoutTray) { + ((MainLayoutTray) main).showCommandPalette(); + } + } + + public void hideCommandPalette() { + if (main instanceof MainLayoutTray) { + ((MainLayoutTray) main).hideCommandPalette(); + } + } + + public boolean isCommandPaletteShown() { + return main != null && main instanceof MainLayoutTray && ((MainLayoutTray) main).isCommandPaletteShown(); + } } diff --git a/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SoftCommandKey.java b/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SoftCommandKey.java new file mode 100644 index 00000000..2d17c1e9 --- /dev/null +++ b/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SoftCommandKey.java @@ -0,0 +1,43 @@ +package io.github.sspanak.tt9.ui.main.keys; + +import android.content.Context; +import android.util.AttributeSet; + +public class SoftCommandKey extends SoftNumberKey { + public SoftCommandKey(Context context) { + super(context); + } + + public SoftCommandKey(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public SoftCommandKey(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + protected String getTitle() { + return getNumber(getId()) + ""; + } + + @Override + protected String getSubTitle() { + int number = getNumber(getId()); + + switch (number) { + case 0: + return "⌨"; + case 1: + return "⚙"; + case 2: + return "+"; + case 3: + return "🎤"; +// case 5: +// return "✂"; + } + + return null; + } +} diff --git a/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SoftKey.java b/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SoftKey.java index 0a7e1814..d041497e 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SoftKey.java +++ b/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SoftKey.java @@ -146,13 +146,14 @@ public class SoftKey extends androidx.appcompat.widget.AppCompatButton implement int keyId = getId(); boolean multiplePress = lastPressedKey == keyId; - if (keyId == R.id.soft_key_add_word) return tt9.onKeyAddWord(false); + if (keyId == R.id.soft_key_add_word) { tt9.addWord(); return true; } + if (keyId == R.id.soft_key_command_palette) return tt9.onKeyCommandPalette(false); if (keyId == R.id.soft_key_filter_suggestions) return tt9.onKeyFilterSuggestions(false, multiplePress); if (keyId == R.id.soft_key_clear_filter) return tt9.onKeyFilterClear(false); if (keyId == R.id.soft_key_left_arrow) return tt9.onKeyScrollSuggestion(false, true); if (keyId == R.id.soft_key_right_arrow) return tt9.onKeyScrollSuggestion(false, false); if (keyId == R.id.soft_key_language) return tt9.onKeyNextLanguage(false); - if (keyId == R.id.soft_key_settings) return tt9.onKeyShowSettings(false); + if (keyId == R.id.soft_key_settings) { tt9.showSettings(); return true; } return false; } diff --git a/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SoftKeyInputMode.java b/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SoftKeyInputMode.java index cffc318b..e7c83fa6 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SoftKeyInputMode.java +++ b/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SoftKeyInputMode.java @@ -19,7 +19,13 @@ public class SoftKeyInputMode extends SoftKey { @Override protected boolean handleHold() { preventRepeat(); - return validateTT9Handler() && tt9.onKeyChangeKeyboard(false); + + if (validateTT9Handler()) { + tt9.changeKeyboard(); + return true; + } + + return false; } diff --git a/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SoftNumberKey.java b/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SoftNumberKey.java index 11d973ee..8c6b66f8 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SoftNumberKey.java +++ b/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SoftNumberKey.java @@ -131,7 +131,7 @@ public class SoftNumberKey extends SoftKey { return sb.toString(); } - private int getNumber(int keyId) { + protected int getNumber(int keyId) { if (keyId == R.id.soft_key_0) return 0; if (keyId == R.id.soft_key_1) return 1; if (keyId == R.id.soft_key_2) return 2; @@ -146,7 +146,7 @@ public class SoftNumberKey extends SoftKey { return -1; } - private int getUpsideDownNumber(int keyId) { + protected int getUpsideDownNumber(int keyId) { int number = getNumber(keyId); if (tt9 != null && tt9.getSettings().getUpsideDownKeys()) { diff --git a/app/src/main/java/io/github/sspanak/tt9/ui/tray/StatusBar.java b/app/src/main/java/io/github/sspanak/tt9/ui/tray/StatusBar.java index c1a77198..1412dbfa 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ui/tray/StatusBar.java +++ b/app/src/main/java/io/github/sspanak/tt9/ui/tray/StatusBar.java @@ -7,6 +7,7 @@ import android.widget.TextView; import androidx.core.content.ContextCompat; import io.github.sspanak.tt9.R; +import io.github.sspanak.tt9.ime.modes.InputMode; import io.github.sspanak.tt9.util.Logger; public class StatusBar { @@ -20,11 +21,16 @@ public class StatusBar { public void setText(String text) { - statusText = "[ " + text + " ]"; + statusText = text; this.render(); } + public void setText(InputMode inputMode) { + setText("[ " + inputMode.toString() + " ]"); + } + + public void setDarkTheme(boolean darkTheme) { if (statusView == null) { return; diff --git a/app/src/main/res/layout/main_numpad.xml b/app/src/main/res/layout/main_numpad.xml index 1c43a572..2ea75b6a 100644 --- a/app/src/main/res/layout/main_numpad.xml +++ b/app/src/main/res/layout/main_numpad.xml @@ -127,7 +127,6 @@ - + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml index c490b818..679efe88 100644 --- a/app/src/main/res/values-bg/strings.xml +++ b/app/src/main/res/values-bg/strings.xml @@ -13,6 +13,7 @@ Не може да се добави дума. Неразпознат език: \"%1$d\". „%1$s“ е добавена. Добавяне на дума + Изберете команда За приложението Цифрова клавиатура (БЕТА) Функционални клавиши @@ -64,18 +65,16 @@ Зареди Дарете Ако харесвате %1$s, подкрепете разработката му на: %2$s. - Добавяне на нова дума - Триене на текст - Избор на клавиатура + Триене на текст Речникови известия Получавайте известия за обновления на речника и за прогреса при зареждане. - Изчистване на филтър - Филтриране на думи - Предишна дума - Следваща дума - Следващ eзик - Режим на писане - Настройки + Списък с команди + Изчистване на филтър + Филтриране на думи + Предишна дума + Следваща дума + Следващ eзик + Режим на писане Възстанови стандартните бутони Възстановени са стандартните „бързи“ бутони. Състояние diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 386eea50..6a813555 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -14,6 +14,7 @@ \"%1$s\" hinzugefügt. Wort hinzufügen + Einen Befehl auswählen Über die Anwendung Ziffernblock (BETA) Funktionstasten @@ -54,8 +55,7 @@ Tastenkürzel Tastenfeld Leerzeichen - Rücktaste - Tastaturauswahl + Rücktaste Status Standardtastatur auswählen %1$s ist aktiviert @@ -108,4 +108,5 @@ Benachrichtigen über Wörterbuchaktualisierungen und den Ladevorgang. Schriftgröße der Einstellungen Standard + Befehlsliste anzeigen diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 5f557848..a34e3d5e 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -33,8 +33,7 @@ Tema oscuro Espacio Borrando… - Agregar palabra - Retroceso + Retroceso Estado Selecciona teclado predeterminado Nueva línea @@ -42,6 +41,7 @@ Cargar los seleccionados Cargando diccionario Cargando diccionario (%1$s)… + Seleccionar un comando Acerca de esta aplicación Falló al cargar. No se encontró el diccionario para \"%1$s\". Borrar todos @@ -71,16 +71,15 @@ Habilite la configuración si hay 7–8–9 en la primera fila, en lugar de 1–2–3. Configuración inicial Error - Cambiar el teclado Notificaciones del diccionario Recibir notificaciones sobre actualizaciones del diccionario y sobre el progreso de la carga. - Limpiar el filtro - Filtrar sugerencias - Sugerencia previa - Sugerencia siguiente - Idioma siguiente - Modo de ingreso - Mostrar configuración + Lista de comandos + Limpiar el filtro + Filtrar sugerencias + Sugerencia previa + Sugerencia siguiente + Idioma siguiente + Modo de ingreso Restaurar valores de teclas por defecto Valores de teclas por defecto restaurados %1$s está habilitado diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 9fb1ed0b..731eebd1 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -13,6 +13,7 @@ Impossible d\'ajouter un mot. Langue inconnue : « %1$d ». « %1$s » est ajouté Ajouter un mot + Sélectionner une commande À propos de l\'application Pavé numérique (BETA) Touches de fonction @@ -62,18 +63,16 @@ Commencer automatiquement les phrases avec une majuscule. Clavier Espace - Ajouter un mot - Retour arrière - Changer le clavier + Retour arrière Notifications du dictionnaire Recevoir des notifications sur les mises à jour du dictionnaire et sur la progression du chargement. - Supprimer le filtre - Filtrer les mots - Mot précédent - Mot suivant - Langue suivante - Mode de saisie suivant - Afficher les paramètres + Liste des commandes + Supprimer le filtre + Filtrer les mots + Mot précédent + Mot suivant + Langue suivante + Mode de saisie suivant Restaurer les paramètres par défaut Paramètres par défaut sont restaurés. État diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index dcc7dfc2..56f62f36 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -16,6 +16,7 @@ \"%1$s\" aggiunta. Aggiungi parola + Selezionare un comando Sull\'applicazione Tastierino numerico (BETA) Tasti di funzione @@ -56,8 +57,7 @@ Caricamento annullato. Tastiera Spazio - Backspace - Cambia la tastiera + Backspace Stato Seleziona la tastiera predefinita %1$s è abilitato @@ -110,5 +110,6 @@ Ricevere notifiche sugli aggiornamenti del dizionario e sul progresso del caricamento. Dimensione del carattere delle impostazioni Predefinita + Mostra elenco comandi diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index d00a35a9..a718b103 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -16,6 +16,7 @@ %1$s נוסף. הוסף מילה + לבחור פקודה אודות מצב אבג מילים שהוספו @@ -68,12 +69,9 @@ המילון נוקה בהצלחה המחיקה מתבצעת… - לחצן הוספת מילה - לחצן מחיקה - בחירת מקלדת - לחצן למעבר לשפה הבאה - לחצן מצב קלט - לחצן הצגת הגדרות + לחצן מחיקה + לחצן למעבר לשפה הבאה + לחצן מצב קלט שחזור לחצני ברירת מחדל הגדרות ברירת המחדל שוחזרו. @@ -125,4 +123,5 @@ לקבל התראות על עדכוני המילון ועל התקדמות הטעינה. גודל הגופן בהגדרות ברירת מחדל + הצג רשימת פקודות diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml index 37b7a139..48ce801e 100644 --- a/app/src/main/res/values-lt/strings.xml +++ b/app/src/main/res/values-lt/strings.xml @@ -18,6 +18,7 @@ Žodis \"%1$s\" pridėtas. Pridėti žodį + Pasirinkti komandą Apie programėlę ABC metodas Suderinamumas @@ -72,18 +73,16 @@ Žodynas sėkmingai ištrintas. Ištrinama… - Pridėti žodį - Trinti - Keisti klaviatūrą + Trinti Žodyno pranešimai Gaukite pranešimus apie žodynų atnaujinimus ir įkėlimo progresą. - Panaikinti filtrą - Filtruoti pasiūlymus - Ankstesnis pasiūlytas žodis - Sekantis pasiūlytas žodis - Rašymo kalba - Rašymo būdas - Rodyti nustatymus + Rodyti komandų sąrašą + Panaikinti filtrą + Filtruoti pasiūlymus + Ankstesnis pasiūlytas žodis + Sekantis pasiūlytas žodis + Rašymo kalba + Rašymo būdas Atkurti numatytąsias reikšmes Numatytosios reikšmės atkurtos. diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 62818761..8969345a 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -13,6 +13,7 @@ Kan geen woord toevoegen. Onbekende taal: \"%1$d\". \"%1$s\" toegevoegd. Woord toevoegen + Een commando selecteren Over de applicatie Numeriek toetsenbord (BETA) Functieknoppen @@ -55,8 +56,7 @@ Sneltoetsen Toetsenbord Spatie - Backspace - Toetsenbordkeuze + Backspace Status Standaardtoetsenbord selecteren %1$s is ingeschakeld @@ -106,4 +106,5 @@ Ontvang meldingen over woordenboekupdates en de voortgang van het laden. Instellingen lettergrootte Standaard + Toon opdrachtenlijst diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index d2dab58e..ee7bc975 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -16,6 +16,7 @@ \"%1$s\" adicionada. Adicionar Palavra + Selecionar um comando Sobre Modo ABC Palavras adicionadas @@ -65,12 +66,9 @@ Limpar Dicionário Dicionário apagado com sucesso. - Adicionar palavra - Backspace - Mude o teclado - Próximo Idioma - Modo de Entrada - Entrar em Configurações + Backspace + Próximo Idioma + Modo de Entrada Restaurar Atalhos Padrão Atalhos Restaurados. @@ -127,4 +125,5 @@ Receber notificações sobre atualizações do dicionário e sobre o progresso do carregamento. Tamanho da fonte das configurações Padrão + Lista de comandos diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 7788b5b4..f053e44a 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -13,6 +13,7 @@ Невозможно добавить слово. Неизвестный язык: \"%1$d\". « %1$s » добавлено Добавить слово + Выбрать команду О приложении Цифровая клавиатура (БЕТА) Функциональные клавиши @@ -61,18 +62,16 @@ Символ при двойном нажатии клавиши 0 Отправка с «ОК» в Messenger Не удалось загрузить словарь. Проблема в слове «%1$s» в строке %2$d для языка «%3$s». - Добавить новое слово - Стереть - Выбор клавиатуры + Стереть Уведомления словаря Получать уведомления о обновлениях словаря и о процессе загрузки. - Удалить фильтр - Фильтровать слова - Предыдущее слово - Следующее слово - Следующий язык - Режим ввода - Настройки + Список команд + Удалить фильтр + Фильтровать слова + Предыдущее слово + Следующее слово + Следующий язык + Режим ввода Вернуть кнопки по умолчанию Настройки кнопок по умолчанию восстановлены. Состояние diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index f88c2e8a..9d877bc5 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -14,6 +14,7 @@ \"%1$s\" başarıyla eklendi. Kelime Ekle + Bir komut seç Hakkında Sanal Tuş Takımı (BETA) İşlevsel Tuşlar @@ -56,8 +57,7 @@ Klavye Kısayolları Tuş Takımı Boşluk - Geri Tuşu - Klavye Seçimi + Geri Tuşu Durum Varsayılan Klavyeyi Seçin %1$s devrede @@ -114,14 +114,13 @@ Tuş Düzenini Tersine Çevir Eğer ilk satırda 1–2–3 yerine 7–8–9 kullanıyorsanız bunu aktif edin. - Kelime ekle - Filtre Temizle - Tahminleri Filtrele - Önceki Tahmin - Sonraki Tahmin - Sonraki Dil - Giriş Yöntemi - Ayarları Göster + Komut listesini göster + Filtre Temizle + Tahminleri Filtrele + Önceki Tahmin + Sonraki Tahmin + Sonraki Dil + Giriş Yöntemi Varsayılan Ayarlara Geri Dön Varsayılan tuş ayarlarına dönüldü. diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 484346d2..1ee7a9b4 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -18,6 +18,7 @@ \"%1$s\" додано. Додати слово + Вибрати команду Про програму Режим АБВ Додані слова @@ -99,18 +100,16 @@ Підтримати Якщо вам подобається %1$s, ви можете підтримати розробку по посиланню: %2$s. - Додати слово - Стерти - Змінити клавіатуру + Стерти Сповіщення словника Отримувати повідомлення про оновлення словника та процес завантаження. - Очистити фільтр - Фільтрувати пропозиції - Попередня пропозиція - Наступна пропозиція - Наступна мова - Режим вводу - Показати налаштування + Список команд + Очистити фільтр + Фільтрувати пропозиції + Попередня пропозиція + Наступна пропозиція + Наступна мова + Режим вводу Відновити стандартні клавіші Стандартні налаштування клавіш відновленно. diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 864796d8..9b81f962 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -21,6 +21,8 @@ \"%1$s\" added. Add Word + Select a Command + About ABC Mode Added Words @@ -118,16 +120,14 @@ https://www.buymeacoffee.com/sspanak www.buymeacoffee.com - Add Word - Backspace - Change Keyboard - Clear Filter - Filter Suggestions - Previous Suggestion - Next Suggestion - Next Language - Input Mode - Show Settings + Backspace + Show Command List + Clear Filter + Filter Suggestions + Previous Suggestion + Next Suggestion + Next Language + Input Mode Restore Default Keys Default key settings restored. diff --git a/app/src/main/res/xml/prefs_screen_hotkeys.xml b/app/src/main/res/xml/prefs_screen_hotkeys.xml index 84a70560..30334b60 100644 --- a/app/src/main/res/xml/prefs_screen_hotkeys.xml +++ b/app/src/main/res/xml/prefs_screen_hotkeys.xml @@ -3,44 +3,36 @@ app:orderingFromXml="true"> + app:key="key_backspace" + app:title="@string/function_backspace" /> + app:key="key_command_palette" + app:title="@string/function_show_command_palette" /> + app:title="@string/function_filter_clear" /> + app:title="@string/function_filter_suggestions" /> + app:title="@string/function_previous_suggestion" /> + app:title="@string/function_next_suggestion" /> + app:title="@string/function_next_language" /> - - - - + app:title="@string/function_next_mode" />