fixed inconsistencies between the current text case the status icon and the virtual Shift key icon
This commit is contained in:
parent
e66e7f7c61
commit
c9e5573b58
10 changed files with 63 additions and 37 deletions
|
|
@ -217,27 +217,26 @@ abstract public class CommandHandler extends TextEditingHandler {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When there are no suggestions, there is no need to execute the code below for adjusting their text case.
|
// if there are no suggestions or they are special chars, we don't need to adjust their text case
|
||||||
if (mInputMode.getSuggestions().isEmpty()) {
|
final String before = suggestionOps.getCurrent();
|
||||||
|
boolean beforeStartsWithLetter = !before.isEmpty() && Character.isAlphabetic(before.charAt(0));
|
||||||
|
if (!beforeStartsWithLetter) {
|
||||||
settings.saveTextCase(mInputMode.getTextCase());
|
settings.saveTextCase(mInputMode.getTextCase());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When we are in AUTO mode and current dictionary word is in uppercase,
|
// When we are in AUTO mode and current dictionary word is in uppercase,
|
||||||
// the mode would switch to UPPERCASE, but visually, the word would not change.
|
// the mode would switch to UPPERCASE, but visually, the word would not change.
|
||||||
// This is why we retry, until there is a visual change.
|
// This is why we retry using the code below, until there is a visual change.
|
||||||
String before = suggestionOps.get(0);
|
int currentSuggestionIndex = suggestionOps.getCurrentIndex();
|
||||||
boolean beforeStartsWithLetter = !before.isEmpty() && Character.isAlphabetic(before.charAt(0));
|
currentSuggestionIndex = suggestionOps.containsStem() ? currentSuggestionIndex - 1 : currentSuggestionIndex;
|
||||||
for (int retries = 0; beforeStartsWithLetter && retries < 2 && mInputMode.nextTextCase(); retries++) {
|
|
||||||
String after = mInputMode.getSuggestions().get(0);
|
for (int retries = 0; retries <= 2; retries++) {
|
||||||
if (!after.equals(before)) {
|
if (!before.equals(mInputMode.getSuggestions().get(currentSuggestionIndex)) || !mInputMode.nextTextCase()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int currentSuggestionIndex = suggestionOps.getCurrentIndex();
|
|
||||||
currentSuggestionIndex = suggestionOps.containsStem() ? currentSuggestionIndex - 1 : currentSuggestionIndex;
|
|
||||||
|
|
||||||
suggestionOps.set(mInputMode.getSuggestions(), currentSuggestionIndex, mInputMode.containsGeneratedSuggestions());
|
suggestionOps.set(mInputMode.getSuggestions(), currentSuggestionIndex, mInputMode.containsGeneratedSuggestions());
|
||||||
textField.setComposingText(suggestionOps.getCurrent());
|
textField.setComposingText(suggestionOps.getCurrent());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -150,11 +150,14 @@ public abstract class TypingHandler extends KeyPadHandler {
|
||||||
mInputMode.reset();
|
mInputMode.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setStatusIcon(mInputMode, mLanguage);
|
||||||
|
|
||||||
if (!mainView.isTextEditingPaletteShown() && !mainView.isCommandPaletteShown()) {
|
if (!mainView.isTextEditingPaletteShown() && !mainView.isCommandPaletteShown()) {
|
||||||
statusBar.setText(mInputMode);
|
statusBar.setText(mInputMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this updates Shift and Filter, so we can't do it only when recomposing
|
||||||
if (settings.isMainLayoutNumpad()) {
|
if (settings.isMainLayoutNumpad()) {
|
||||||
mainView.renderKeys();
|
mainView.renderKeys();
|
||||||
}
|
}
|
||||||
|
|
@ -190,14 +193,11 @@ public abstract class TypingHandler extends KeyPadHandler {
|
||||||
String lastWord = suggestionOps.acceptIncompleteAndKeepList();
|
String lastWord = suggestionOps.acceptIncompleteAndKeepList();
|
||||||
mInputMode.onAcceptSuggestion(lastWord);
|
mInputMode.onAcceptSuggestion(lastWord);
|
||||||
autoCorrectSpace(lastWord, false, key);
|
autoCorrectSpace(lastWord, false, key);
|
||||||
if (settings.isMainLayoutNumpad()) {
|
|
||||||
mainView.renderKeys();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auto-adjust the text case before each word, if the InputMode supports it.
|
// Auto-adjust the text case before each word, if the InputMode supports it.
|
||||||
if (mInputMode.getSuggestions().isEmpty()) {
|
if (mInputMode.getSuggestions().isEmpty()) {
|
||||||
mInputMode.determineNextWordTextCase();
|
mInputMode.determineNextWordTextCase(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mInputMode.onNumber(key, hold, repeat)) {
|
if (!mInputMode.onNumber(key, hold, repeat)) {
|
||||||
|
|
@ -379,7 +379,7 @@ public abstract class TypingHandler extends KeyPadHandler {
|
||||||
protected void onAcceptSuggestionAutomatically(String word) {
|
protected void onAcceptSuggestionAutomatically(String word) {
|
||||||
mInputMode.onAcceptSuggestion(word, true);
|
mInputMode.onAcceptSuggestion(word, true);
|
||||||
autoCorrectSpace(word, false, mInputMode.getSequence().isEmpty() ? -1 : mInputMode.getSequence().charAt(0) - '0');
|
autoCorrectSpace(word, false, mInputMode.getSequence().isEmpty() ? -1 : mInputMode.getSequence().charAt(0) - '0');
|
||||||
mInputMode.determineNextWordTextCase();
|
mInputMode.determineNextWordTextCase(-1);
|
||||||
if (settings.isMainLayoutNumpad()) {
|
if (settings.isMainLayoutNumpad()) {
|
||||||
mainView.renderKeys();
|
mainView.renderKeys();
|
||||||
}
|
}
|
||||||
|
|
@ -444,6 +444,11 @@ public abstract class TypingHandler extends KeyPadHandler {
|
||||||
String trimmedWord = suggestionOps.getCurrent(mLanguage, mInputMode.getSequenceLength());
|
String trimmedWord = suggestionOps.getCurrent(mLanguage, mInputMode.getSequenceLength());
|
||||||
appHacks.setComposingTextWithHighlightedStem(trimmedWord, mInputMode);
|
appHacks.setComposingTextWithHighlightedStem(trimmedWord, mInputMode);
|
||||||
|
|
||||||
|
setStatusIcon(mInputMode, mLanguage);
|
||||||
|
if (settings.isMainLayoutNumpad()) {
|
||||||
|
mainView.renderKeys();
|
||||||
|
}
|
||||||
|
|
||||||
forceShowWindow();
|
forceShowWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||||
import io.github.sspanak.tt9.ui.StatusIcon;
|
import io.github.sspanak.tt9.ui.StatusIcon;
|
||||||
import io.github.sspanak.tt9.ui.main.ResizableMainView;
|
import io.github.sspanak.tt9.ui.main.ResizableMainView;
|
||||||
import io.github.sspanak.tt9.ui.tray.StatusBar;
|
import io.github.sspanak.tt9.ui.tray.StatusBar;
|
||||||
|
import io.github.sspanak.tt9.util.Text;
|
||||||
import io.github.sspanak.tt9.util.sys.DeviceInfo;
|
import io.github.sspanak.tt9.util.sys.DeviceInfo;
|
||||||
import io.github.sspanak.tt9.util.sys.SystemSettings;
|
import io.github.sspanak.tt9.util.sys.SystemSettings;
|
||||||
|
|
||||||
|
|
@ -55,8 +56,23 @@ abstract class UiHandler extends AbstractHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int getDisplayTextCase(Language language, int modeTextCase) {
|
||||||
|
boolean hasUpperCase = language != null && language.hasUpperCase();
|
||||||
|
if (!hasUpperCase) {
|
||||||
|
return InputMode.CASE_UNDEFINED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modeTextCase == InputMode.CASE_UPPER) {
|
||||||
|
return InputMode.CASE_UPPER;
|
||||||
|
}
|
||||||
|
|
||||||
|
int wordTextCase = new Text(language, getSuggestionOps().getCurrent()).getTextCase();
|
||||||
|
return wordTextCase == InputMode.CASE_UPPER ? InputMode.CASE_CAPITALIZE : wordTextCase;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected void setStatusIcon(InputMode mode, Language language) {
|
protected void setStatusIcon(InputMode mode, Language language) {
|
||||||
int resId = new StatusIcon(settings, mode, language).resourceId;
|
int resId = new StatusIcon(settings, mode, language, getDisplayTextCase(language, mode.getTextCase())).resourceId;
|
||||||
if (resId == 0) {
|
if (resId == 0) {
|
||||||
hideStatusIcon();
|
hideStatusIcon();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -198,7 +198,7 @@ abstract public class InputMode {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void determineNextWordTextCase() {}
|
public void determineNextWordTextCase(int nextDigit) {}
|
||||||
|
|
||||||
// Based on the internal logic of the mode (punctuation or grammar rules), re-adjust the text case for when getSuggestions() is called.
|
// Based on the internal logic of the mode (punctuation or grammar rules), re-adjust the text case for when getSuggestions() is called.
|
||||||
protected String adjustSuggestionTextCase(String word, int newTextCase) { return word; }
|
protected String adjustSuggestionTextCase(String word, int newTextCase) { return word; }
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ public class ModeIdeograms extends ModeWords {
|
||||||
|
|
||||||
|
|
||||||
@Override protected String adjustSuggestionTextCase(String word, int newTextCase) { return word; }
|
@Override protected String adjustSuggestionTextCase(String word, int newTextCase) { return word; }
|
||||||
@Override public void determineNextWordTextCase() {}
|
@Override public void determineNextWordTextCase(int nextDigit) {}
|
||||||
@Override public boolean nextTextCase() { return false; }
|
@Override public boolean nextTextCase() { return false; }
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,8 @@ class ModeWords extends ModeCheonjiin {
|
||||||
protected ModeWords(SettingsStore settings, Language lang, InputType inputType, TextField textField) {
|
protected ModeWords(SettingsStore settings, Language lang, InputType inputType, TextField textField) {
|
||||||
super(settings, inputType, textField);
|
super(settings, inputType, textField);
|
||||||
|
|
||||||
autoTextCase = new AutoTextCase(settings, inputType);
|
|
||||||
seq = new Sequences();
|
seq = new Sequences();
|
||||||
|
autoTextCase = new AutoTextCase(settings, seq, inputType);
|
||||||
|
|
||||||
setLanguage(lang);
|
setLanguage(lang);
|
||||||
defaultTextCase();
|
defaultTextCase();
|
||||||
|
|
@ -343,8 +343,8 @@ class ModeWords extends ModeCheonjiin {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void determineNextWordTextCase() {
|
public void determineNextWordTextCase(int nextDigit) {
|
||||||
textCase = autoTextCase.determineNextWordTextCase(textCase, textFieldTextCase, textField.getStringBeforeCursor(), digitSequence);
|
textCase = autoTextCase.determineNextWordTextCase(language, textCase, textFieldTextCase, textField.getStringBeforeCursor(), digitSequence + nextDigit);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void determineTextFieldTextCase() {
|
private void determineTextFieldTextCase() {
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,18 @@ import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import io.github.sspanak.tt9.hacks.InputType;
|
import io.github.sspanak.tt9.hacks.InputType;
|
||||||
import io.github.sspanak.tt9.ime.modes.InputMode;
|
import io.github.sspanak.tt9.ime.modes.InputMode;
|
||||||
|
import io.github.sspanak.tt9.languages.Language;
|
||||||
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||||
import io.github.sspanak.tt9.util.Text;
|
import io.github.sspanak.tt9.util.Text;
|
||||||
|
|
||||||
public class AutoTextCase {
|
public class AutoTextCase {
|
||||||
|
@NonNull private final Sequences sequences;
|
||||||
@NonNull private final SettingsStore settings;
|
@NonNull private final SettingsStore settings;
|
||||||
private final boolean isUs;
|
private final boolean isUs;
|
||||||
|
|
||||||
|
|
||||||
public AutoTextCase(@NonNull SettingsStore settingsStore, @Nullable InputType inputType) {
|
public AutoTextCase(@NonNull SettingsStore settingsStore, @NonNull Sequences sequences, @Nullable InputType inputType) {
|
||||||
|
this.sequences = sequences;
|
||||||
settings = settingsStore;
|
settings = settingsStore;
|
||||||
isUs = inputType != null && inputType.isUs();
|
isUs = inputType != null && inputType.isUs();
|
||||||
}
|
}
|
||||||
|
|
@ -44,7 +47,7 @@ public class AutoTextCase {
|
||||||
* For example, this function will return CASE_LOWER by default, but CASE_UPPER at the beginning
|
* For example, this function will return CASE_LOWER by default, but CASE_UPPER at the beginning
|
||||||
* of a sentence.
|
* of a sentence.
|
||||||
*/
|
*/
|
||||||
public int determineNextWordTextCase(int currentTextCase, int textFieldTextCase, String beforeCursor, String digitSequence) {
|
public int determineNextWordTextCase(Language language, int currentTextCase, int textFieldTextCase, String beforeCursor, String digitSequence) {
|
||||||
if (
|
if (
|
||||||
// When the setting is off, don't do any changes.
|
// When the setting is off, don't do any changes.
|
||||||
!settings.getAutoTextCase()
|
!settings.getAutoTextCase()
|
||||||
|
|
@ -56,7 +59,6 @@ public class AutoTextCase {
|
||||||
return currentTextCase;
|
return currentTextCase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (textFieldTextCase != InputMode.CASE_UNDEFINED) {
|
if (textFieldTextCase != InputMode.CASE_UNDEFINED) {
|
||||||
return textFieldTextCase;
|
return textFieldTextCase;
|
||||||
}
|
}
|
||||||
|
|
@ -77,10 +79,8 @@ public class AutoTextCase {
|
||||||
return InputMode.CASE_CAPITALIZE;
|
return InputMode.CASE_CAPITALIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is mostly for English "I", inserted in the middle of a word. However, we don't want to
|
// Prevent English "I", inserted in the middle of a word, from being uppercase.
|
||||||
// enforce lowercase for words like "-ROM" in "CD-ROM". We have to use the digitSequence here,
|
if (sequences.isEnglishI(language, digitSequence) && Text.isNextToWord(beforeCursor)) {
|
||||||
// because the composing text is not yet set in some cases, when this is called.
|
|
||||||
if (Text.isNextToWord(beforeCursor) && !digitSequence.startsWith("1")) {
|
|
||||||
return InputMode.CASE_LOWER;
|
return InputMode.CASE_LOWER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,9 @@ package io.github.sspanak.tt9.ime.modes.helpers;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import io.github.sspanak.tt9.languages.Language;
|
||||||
|
import io.github.sspanak.tt9.languages.LanguageKind;
|
||||||
|
|
||||||
public class Sequences {
|
public class Sequences {
|
||||||
public static final int CHARS_0_KEY = 0;
|
public static final int CHARS_0_KEY = 0;
|
||||||
public static final int CHARS_0_CODE = CHARS_0_KEY + '0';
|
public static final int CHARS_0_CODE = CHARS_0_KEY + '0';
|
||||||
|
|
@ -73,4 +76,8 @@ public class Sequences {
|
||||||
|| sequence.startsWith(CHARS_GROUP_0_SEQUENCE)
|
|| sequence.startsWith(CHARS_GROUP_0_SEQUENCE)
|
||||||
|| sequence.startsWith(CHARS_GROUP_1_SEQUENCE);
|
|| sequence.startsWith(CHARS_GROUP_1_SEQUENCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isEnglishI(@Nullable Language language, @NonNull String digitSequence) {
|
||||||
|
return LanguageKind.isEnglish(language) && digitSequence.equals("4");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -20,7 +20,7 @@ public class SoftKeyShift extends BaseSoftKeyWithIcons {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override protected int getCentralIcon() {
|
@Override protected int getCentralIcon() {
|
||||||
final int textCase = tt9 != null ? tt9.getTextCase() : InputMode.CASE_UNDEFINED;
|
final int textCase = tt9 != null ? tt9.getDisplayTextCase(tt9.getLanguage(), tt9.getTextCase()) : InputMode.CASE_UNDEFINED;
|
||||||
return switch (textCase) {
|
return switch (textCase) {
|
||||||
case InputMode.CASE_CAPITALIZE -> R.drawable.ic_fn_shift_caps;
|
case InputMode.CASE_CAPITALIZE -> R.drawable.ic_fn_shift_caps;
|
||||||
case InputMode.CASE_UPPER -> R.drawable.ic_fn_shift_up;
|
case InputMode.CASE_UPPER -> R.drawable.ic_fn_shift_up;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue