1
0
Fork 0

fixed inconsistencies between the current text case the status icon and the virtual Shift key icon

This commit is contained in:
sspanak 2025-06-03 11:55:48 +03:00 committed by Dimo Karaivanov
parent e66e7f7c61
commit c9e5573b58
10 changed files with 63 additions and 37 deletions

View file

@ -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());

View file

@ -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();
} }

View file

@ -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 {

View file

@ -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; }

View file

@ -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; }

View file

@ -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() {

View file

@ -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;
} }

View file

@ -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

View file

@ -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;