1
0
Fork 0

Copy pasta (#566)

This commit is contained in:
Dimo Karaivanov 2024-07-19 18:03:20 +03:00 committed by GitHub
parent 4bb42424e1
commit 47c846ca39
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
92 changed files with 1778 additions and 548 deletions

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:tools="http://schemas.android.com/tools"
android:versionCode="599"
android:versionName="35.0"
android:versionCode="611"
android:versionName="35.12"
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> <!-- allows displaying notifications on Android >= 13 -->

View file

@ -8,6 +8,7 @@ import androidx.annotation.NonNull;
import io.github.sspanak.tt9.ime.helpers.CursorOps;
import io.github.sspanak.tt9.ime.helpers.SuggestionOps;
import io.github.sspanak.tt9.ime.helpers.TextField;
import io.github.sspanak.tt9.ime.helpers.TextSelection;
import io.github.sspanak.tt9.ime.modes.InputMode;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
@ -16,13 +17,15 @@ public class AppHacks {
private final InputType inputType;
private final SettingsStore settings;
private final TextField textField;
private final TextSelection textSelection;
public AppHacks(SettingsStore settings, InputConnection inputConnection, InputType inputType, TextField textField) {
public AppHacks(SettingsStore settings, InputConnection inputConnection, InputType inputType, TextField textField, TextSelection textSelection) {
this.inputConnection = inputConnection;
this.inputType = inputType;
this.settings = settings;
this.textField = textField;
this.textSelection = textSelection;
}
@ -51,8 +54,12 @@ public class AppHacks {
return false;
}
// When there is no text, allow double function keys to function normally (e.g. "Back" navigates back)
return inputMode.getSuggestions().isEmpty() && textField.getStringBeforeCursor(1).isEmpty();
// When no text is selected and the cursor is at the beginning,
// allow double function keys to function normally (e.g. "Back" navigates back)
return
inputMode.getSuggestions().isEmpty()
&& textSelection.isEmpty()
&& textField.getStringBeforeCursor(1).isEmpty();
}
@ -63,7 +70,7 @@ public class AppHacks {
*/
public boolean onAction(int action) {
if (inputType.isSonimSearchField(action)) {
return sendDownUpKeyEvents(KeyEvent.KEYCODE_ENTER);
return textField.sendDownUpKeyEvents(KeyEvent.KEYCODE_ENTER);
}
return false;
@ -76,7 +83,7 @@ public class AppHacks {
*/
public boolean onMoveCursor(boolean backward) {
if (inputType.isRustDesk() || inputType.isTermux()) {
return sendDownUpKeyEvents(backward ? KeyEvent.KEYCODE_DPAD_LEFT : KeyEvent.KEYCODE_DPAD_RIGHT);
return textField.sendDownUpKeyEvents(backward ? KeyEvent.KEYCODE_DPAD_LEFT : KeyEvent.KEYCODE_DPAD_RIGHT);
}
return false;
@ -119,7 +126,7 @@ public class AppHacks {
// Termux supports only ENTER, so we convert DPAD_CENTER for it.
// Any extra installed apps are likely not designed for hardware keypads, so again,
// we don't want to send DPAD_CENTER to them.
return sendDownUpKeyEvents(KeyEvent.KEYCODE_ENTER);
return textField.sendDownUpKeyEvents(KeyEvent.KEYCODE_ENTER);
}
// The rest of the cases are probably system apps or numeric fields, which should
@ -138,30 +145,14 @@ public class AppHacks {
return false;
}
sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB);
sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB);
sendDownUpKeyEvents(KeyEvent.KEYCODE_ENTER);
sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB, true);
sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB, true);
sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB, true);
sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB, true);
textField.sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB);
textField.sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB);
textField.sendDownUpKeyEvents(KeyEvent.KEYCODE_ENTER);
textField.sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB, true, false);
textField.sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB, true, false);
textField.sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB, true, false);
textField.sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB, true, false);
return true;
}
private boolean sendDownUpKeyEvents(int keyCode) {
return sendDownUpKeyEvents(keyCode, false);
}
private boolean sendDownUpKeyEvents(int keyCode, boolean shift) {
if (inputConnection != null) {
KeyEvent downEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, keyCode, 0, shift ? KeyEvent.META_SHIFT_ON : 0);
KeyEvent upEvent = new KeyEvent(0, 0, KeyEvent.ACTION_UP, keyCode, 0, shift ? KeyEvent.META_SHIFT_ON : 0);
return inputConnection.sendKeyEvent(downEvent) && inputConnection.sendKeyEvent(upEvent);
}
return false;
}
}

View file

@ -6,10 +6,11 @@ import android.view.inputmethod.InputConnection;
import io.github.sspanak.tt9.ime.helpers.SuggestionOps;
import io.github.sspanak.tt9.ime.modes.InputMode;
import io.github.sspanak.tt9.util.Ternary;
abstract public class AbstractHandler extends InputMethodService {
// hardware key handlers
abstract protected boolean onBack();
abstract protected Ternary onBack();
abstract public boolean onBackspace();
abstract public boolean onHotkey(int keyCode, boolean repeat, boolean validateOnly);
abstract protected boolean onNumber(int key, boolean hold, int repeat);

View file

@ -7,17 +7,17 @@ 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;
import io.github.sspanak.tt9.util.Clipboard;
import io.github.sspanak.tt9.util.Ternary;
abstract public class CommandHandler extends VoiceHandler {
abstract public class CommandHandler extends TextEditingHandler {
@Override
protected boolean onBack() {
return super.onBack() || hideCommandPalette();
}
@Override
public boolean onBackspace() {
return hideCommandPalette() || super.onBackspace();
protected Ternary onBack() {
if (hideCommandPalette()) {
return Ternary.TRUE;
} else {
return super.onBack();
}
}
@ -44,9 +44,6 @@ abstract public class CommandHandler extends VoiceHandler {
private void onCommand(int key) {
switch (key) {
case 0:
changeKeyboard();
break;
case 1:
showSettings();
break;
@ -56,6 +53,12 @@ abstract public class CommandHandler extends VoiceHandler {
case 3:
toggleVoiceInput();
break;
case 5:
showTextEditingPalette();
break;
case 8:
changeKeyboard();
break;
}
}
@ -63,6 +66,9 @@ abstract public class CommandHandler extends VoiceHandler {
protected void resetStatus() {
if (mainView.isCommandPaletteShown()) {
statusBar.setText(R.string.commands_select_command);
} if (mainView.isTextEditingPaletteShown()) {
String preview = Clipboard.getPreview(this);
statusBar.setText(preview.isEmpty() ? getString(R.string.commands_select_command) : "[ \"" + preview + "\" ]");
} else {
statusBar.setText(mInputMode);
}

View file

@ -1,21 +1,15 @@
package io.github.sspanak.tt9.ime;
import android.view.KeyEvent;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import io.github.sspanak.tt9.db.DictionaryLoader;
import io.github.sspanak.tt9.ime.helpers.TextField;
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.util.Ternary;
public abstract class HotkeyHandler extends CommandHandler {
private boolean isSystemRTL;
@Override
protected void onInit() {
super.onInit();
@ -26,15 +20,14 @@ public abstract class HotkeyHandler extends CommandHandler {
@Override
protected boolean onStart(InputConnection connection, EditorInfo field) {
isSystemRTL = LanguageKind.isRTL(LanguageCollection.getDefault(this));
return super.onStart(connection, field);
}
@Override
public boolean onBack() {
return super.onBack() || settings.isMainLayoutNumpad();
public Ternary onBack() {
if (super.onBack() == Ternary.TRUE) {
return Ternary.TRUE;
} else if (settings.isMainLayoutNumpad()) {
return Ternary.ALTERNATIVE;
} else {
return Ternary.FALSE;
}
}
@ -102,7 +95,12 @@ public abstract class HotkeyHandler extends CommandHandler {
public boolean onKeyMoveCursor(boolean backward) {
return appHacks.onMoveCursor(backward) || textField.moveCursor(backward);
if (textSelection.isEmpty()) {
return appHacks.onMoveCursor(backward) || textField.moveCursor(backward);
} else {
textSelection.clear(backward);
return true;
}
}

View file

@ -76,8 +76,13 @@ abstract class KeyPadHandler extends UiHandler {
event.startTracking();
}
// on many devices there is a default back handler, so we must fall back to it when we don't
// perform any operation
if (Key.isBack(keyCode)) {
return onBack() && super.onKeyDown(keyCode, event);
Key.setHandled(keyCode, onBack());
return Key.isHandledInSuper(keyCode) ? super.onKeyDown(keyCode, event) : Key.isHandled(keyCode);
} else {
Key.setHandled(KeyEvent.KEYCODE_BACK, false);
}
return
@ -169,11 +174,11 @@ abstract class KeyPadHandler extends UiHandler {
}
if (Key.isBack(keyCode)) {
return onBack() && super.onKeyUp(keyCode, event);
return Key.isHandledInSuper(keyCode) ? super.onKeyUp(keyCode, event) : Key.isHandled(keyCode);
}
return
(Key.isOK(KeyEvent.KEYCODE_ENTER) && Key.isHandled(keyCode))
(Key.isOK(keyCode) && Key.isHandled(KeyEvent.KEYCODE_ENTER))
|| handleHotkey(keyCode, false, keyRepeatCounter > 0, false)
|| Key.isPoundOrStar(keyCode) && onText(String.valueOf((char) event.getUnicodeChar()), false)
|| super.onKeyUp(keyCode, event); // let the system handle the keys we don't care about (usually, the touch "buttons")

View file

@ -29,6 +29,10 @@ abstract public class MainViewHandler extends HotkeyHandler {
return mInputMode.getTextCase();
}
public boolean isInputLimited() {
return inputType.isLimited();
}
public boolean isInputModeABC() {
return mInputMode.getClass().equals(ModeABC.class);
}
@ -49,6 +53,10 @@ abstract public class MainViewHandler extends HotkeyHandler {
return mInputMode.is123() && inputType.isPhoneNumber();
}
public boolean isTextEditingActive() {
return mainView != null && mainView.isTextEditingPaletteShown();
}
public boolean isVoiceInputActive() {
return voiceInputOps != null && voiceInputOps.isListening();
}

View file

@ -0,0 +1,111 @@
package io.github.sspanak.tt9.ime;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import io.github.sspanak.tt9.languages.LanguageCollection;
import io.github.sspanak.tt9.languages.LanguageKind;
import io.github.sspanak.tt9.util.Clipboard;
import io.github.sspanak.tt9.util.Ternary;
abstract public class TextEditingHandler extends VoiceHandler {
protected boolean isSystemRTL;
@Override
protected boolean onStart(InputConnection connection, EditorInfo field) {
isSystemRTL = LanguageKind.isRTL(LanguageCollection.getDefault(this));
return super.onStart(connection, field);
}
protected boolean onNumber(int key, boolean hold, int repeat) {
if (!shouldBeOff() && mainView.isTextEditingPaletteShown()) {
onCommand(key);
return true;
}
return super.onNumber(key, hold, repeat);
}
@Override
protected Ternary onBack() {
if (hideTextEditingPalette()) {
return Ternary.TRUE;
} else {
return super.onBack();
}
}
private void onCommand(int key) {
switch (key) {
case 0:
if (!mInputMode.isNumeric()) {
textField.setText(" ");
}
break;
case 1:
textSelection.selectNextChar(!isSystemRTL);
break;
case 2:
textSelection.clear();
break;
case 3:
textSelection.selectNextChar(isSystemRTL);
break;
case 4:
textSelection.selectNextWord(!isSystemRTL);
break;
case 5:
textSelection.selectAll();
break;
case 6:
textSelection.selectNextWord(isSystemRTL);
break;
case 7:
textSelection.cut(textField);
break;
case 8:
textSelection.copy();
break;
case 9:
textSelection.paste(textField);
break;
}
}
public void showTextEditingPalette() {
if (inputType.isLimited() || mainView.isTextEditingPaletteShown()) {
return;
}
suggestionOps.cancelDelayedAccept();
suggestionOps.acceptIncomplete();
mInputMode.reset();
stopVoiceInput();
mainView.showTextEditingPalette();
Clipboard.setOnChangeListener(this, this::resetStatus);
resetStatus();
}
public boolean hideTextEditingPalette() {
if (!mainView.isTextEditingPaletteShown()) {
return false;
}
if (settings.isMainLayoutNumpad() || settings.isMainLayoutStealth()) {
mainView.hideTextEditingPalette();
} else {
mainView.showCommandPalette();
}
Clipboard.setOnChangeListener(this, null);
resetStatus();
return true;
}
}

View file

@ -16,6 +16,7 @@ import io.github.sspanak.tt9.ime.helpers.CursorOps;
import io.github.sspanak.tt9.ime.helpers.InputModeValidator;
import io.github.sspanak.tt9.ime.helpers.SuggestionOps;
import io.github.sspanak.tt9.ime.helpers.TextField;
import io.github.sspanak.tt9.ime.helpers.TextSelection;
import io.github.sspanak.tt9.ime.modes.InputMode;
import io.github.sspanak.tt9.ime.modes.ModePredictive;
import io.github.sspanak.tt9.languages.Language;
@ -26,10 +27,11 @@ import io.github.sspanak.tt9.util.Text;
public abstract class TypingHandler extends KeyPadHandler {
// internal settings/data
@NonNull protected AppHacks appHacks = new AppHacks(null,null, null, null);
@NonNull protected AppHacks appHacks = new AppHacks(null,null, null, null, null);
protected InputConnection currentInputConnection = null;
@NonNull protected InputType inputType = new InputType(null, null);
@NonNull protected TextField textField = new TextField(null, null);
@NonNull protected TextSelection textSelection = new TextSelection(this,null);
protected SuggestionOps suggestionOps;
boolean isEnabled = false;
@ -94,9 +96,10 @@ public abstract class TypingHandler extends KeyPadHandler {
currentInputConnection = connection;
inputType = new InputType(currentInputConnection, field);
textField = new TextField(currentInputConnection, field);
textSelection = new TextSelection(this, currentInputConnection);
// changing the TextField and notifying all interested classes is an atomic operation
appHacks = new AppHacks(settings, connection, inputType, textField);
appHacks = new AppHacks(settings, connection, inputType, textField, textSelection);
suggestionOps.setTextField(textField);
}
@ -288,6 +291,7 @@ public abstract class TypingHandler extends KeyPadHandler {
// Logger.d("onUpdateSelection", "oldSelStart: " + oldSelStart + " oldSelEnd: " + oldSelEnd + " newSelStart: " + newSelStart + " oldSelEnd: " + oldSelEnd + " candidatesStart: " + candidatesStart + " candidatesEnd: " + candidatesEnd);
super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, candidatesStart, candidatesEnd);
textSelection.onSelectionUpdate(newSelStart, newSelEnd);
// in case the app has modified the InputField and moved the cursor without notifiying us...
if (appHacks.onUpdateSelection(mInputMode, suggestionOps, oldSelStart, oldSelEnd, newSelStart, newSelEnd, candidatesStart, candidatesEnd)) {

View file

@ -5,6 +5,7 @@ import io.github.sspanak.tt9.ime.voice.VoiceInputError;
import io.github.sspanak.tt9.ime.voice.VoiceInputOps;
import io.github.sspanak.tt9.ui.dialogs.RequestPermissionDialog;
import io.github.sspanak.tt9.util.Logger;
import io.github.sspanak.tt9.util.Ternary;
abstract class VoiceHandler extends TypingHandler {
private final static String LOG_TAG = VoiceHandler.class.getSimpleName();
@ -24,9 +25,9 @@ abstract class VoiceHandler extends TypingHandler {
}
@Override
protected boolean onBack() {
protected Ternary onBack() {
stopVoiceInput();
return false; // we don't want to abort other operations, we just silently stop voice input
return Ternary.FALSE; // we don't want to abort other operations, we just silently stop voice input
}
@Override

View file

@ -5,19 +5,30 @@ import android.view.KeyEvent;
import java.util.HashMap;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.util.Ternary;
public class Key {
private static final HashMap<Integer, Boolean> handledKeys = new HashMap<>();
private static final HashMap<Integer, Ternary> handledKeys = new HashMap<>();
public static void setHandled(int keyCode, Ternary handled) {
handledKeys.put(keyCode, handled);
}
public static boolean setHandled(int keyCode, boolean handled) {
handledKeys.put(keyCode, handled);
handledKeys.put(keyCode, handled ? Ternary.TRUE : Ternary.FALSE);
return handled;
}
public static boolean isHandled(int keyCode) {
return Boolean.TRUE.equals(handledKeys.get(keyCode));
return handledKeys.containsKey(keyCode) && handledKeys.get(keyCode) == Ternary.TRUE;
}
public static boolean isHandledInSuper(int keyCode) {
return handledKeys.containsKey(keyCode) && handledKeys.get(keyCode) == Ternary.ALTERNATIVE;
}

View file

@ -1,36 +1,35 @@
package io.github.sspanak.tt9.ime.helpers;
import android.content.Context;
import android.content.res.Configuration;
import androidx.annotation.NonNull;
public class OrientationListener extends android.view.OrientationEventListener {
private static final short ORIENTATION_LANDSCAPE = 1;
private static final short ORIENTATION_UNKNOWN = 0;
private static final short ORIENTATION_PORTRAIT = -1;
private short previousOrientation = ORIENTATION_UNKNOWN;
private final Configuration configuration;
private final Runnable onChange;
private int previousOrientation = Configuration.ORIENTATION_UNDEFINED;
public OrientationListener(@NonNull Context context, @NonNull Runnable onChange) {
super(context);
configuration = context.getResources().getConfiguration();
this.onChange = onChange;
}
@Override
public void onOrientationChanged(int orientation) {
short currentOrientation;
if (orientation > 345 || orientation < 15 || (orientation > 165 && orientation < 195)) {
currentOrientation = ORIENTATION_PORTRAIT;
} else if ((orientation > 75 && orientation < 105) || (orientation > 255 && orientation < 285)) {
currentOrientation = ORIENTATION_LANDSCAPE;
} else {
if (
(orientation > 15 && orientation < 75)
|| (orientation > 105 && orientation < 165)
|| (orientation > 195 && orientation < 255)
|| (orientation > 285 && orientation < 345)
) {
return;
}
if (currentOrientation != previousOrientation) {
previousOrientation = currentOrientation;
if (previousOrientation != configuration.orientation) {
previousOrientation = configuration.orientation;
onChange.run();
}
}

View file

@ -245,10 +245,26 @@ public class TextField extends InputField {
return false;
}
int keyCode = backward ? KeyEvent.KEYCODE_DPAD_LEFT : KeyEvent.KEYCODE_DPAD_RIGHT;
connection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
connection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keyCode));
sendDownUpKeyEvents(backward ? KeyEvent.KEYCODE_DPAD_LEFT : KeyEvent.KEYCODE_DPAD_RIGHT);
return true;
}
public boolean sendDownUpKeyEvents(int keyCode) {
return sendDownUpKeyEvents(keyCode, false, false);
}
public boolean sendDownUpKeyEvents(int keyCode, boolean shift, boolean ctrl) {
if (connection != null) {
int metaState = shift ? KeyEvent.META_SHIFT_ON : 0;
metaState |= ctrl ? KeyEvent.META_CTRL_ON : 0;
KeyEvent downEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, keyCode, 0, metaState);
KeyEvent upEvent = new KeyEvent(0, 0, KeyEvent.ACTION_UP, keyCode, 0, metaState);
return connection.sendKeyEvent(downEvent) && connection.sendKeyEvent(upEvent);
}
return false;
}
}

View file

@ -0,0 +1,160 @@
package io.github.sspanak.tt9.ime.helpers;
import android.content.Context;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.github.sspanak.tt9.util.Clipboard;
public class TextSelection {
@Nullable private final InputConnection connection;
private final Context context;
private int currentStart = 0;
private int currentEnd = 0;
public TextSelection(Context context, @Nullable InputConnection connection) {
this.context = context;
this.connection = connection;
detectCursorPosition();
}
public void onSelectionUpdate(int start, int end) {
currentStart = start;
currentEnd = end;
}
public boolean isEmpty() {
return currentStart == currentEnd;
}
public void clear() {
if (connection != null) {
connection.setSelection(currentEnd, currentEnd);
}
}
public void clear(boolean backward) {
if (connection != null) {
connection.setSelection(
backward ? Math.min(currentStart, currentEnd) : Math.max(currentStart, currentEnd),
backward ? Math.min(currentStart, currentEnd) : Math.max(currentStart, currentEnd)
);
}
}
public void selectAll() {
if (connection != null) {
connection.performContextMenuAction(android.R.id.selectAll);
}
}
public void selectNextChar(boolean backward) {
if (connection != null) {
connection.setSelection(currentStart, currentEnd + (backward ? -1 : 1));
}
}
public void selectNextWord(boolean backward) {
if (connection == null) {
return;
}
connection.setSelection(currentStart, getNextWordPosition(backward));
}
public boolean copy() {
CharSequence selectedText = getSelectedText();
if (selectedText.length() == 0) {
return false;
}
Clipboard.copy(context, selectedText);
return true;
}
public void cut(@NonNull TextField textField) {
if (copy()) {
textField.setText("");
}
}
public void paste(@NonNull TextField textField) {
String clipboardText = Clipboard.paste(context);
if (!clipboardText.isEmpty()) {
textField.setText(clipboardText);
}
}
private int getNextWordPosition(boolean backward) {
if (connection == null) {
return currentEnd + (backward ? -1 : 1);
}
ExtractedText extractedText = connection.getExtractedText(new ExtractedTextRequest(), 0);
if (extractedText == null) {
return currentEnd + (backward ? -1 : 1);
}
int increment = backward ? -1 : 1;
int textLength = extractedText.text.length();
for (int ch = currentEnd + increment; ch >= 0 && ch < textLength; ch += increment) {
if (!Character.isWhitespace(extractedText.text.charAt(ch))) {
continue;
}
if (ch >= currentStart) {
return ch;
} else if (ch + 1 != currentEnd) {
return ch + 1;
}
}
return backward ? 0 : textLength;
}
private void detectCursorPosition() {
if (connection == null) {
return;
}
ExtractedText extractedText = connection.getExtractedText(new ExtractedTextRequest(), 0);
if (extractedText != null) {
currentStart = extractedText.startOffset + extractedText.selectionStart;
currentEnd = extractedText.startOffset + extractedText.selectionEnd;
}
}
private CharSequence getSelectedText() {
if (connection == null) {
return "";
}
ExtractedText extractedText = connection.getExtractedText(new ExtractedTextRequest(), 0);
if (extractedText == null) {
return "";
}
int start = Math.min(extractedText.selectionStart, extractedText.selectionEnd);
int end = Math.max(extractedText.selectionStart, extractedText.selectionEnd);
return extractedText.text.subSequence(start, end);
}
}

View file

@ -1,8 +1,5 @@
package io.github.sspanak.tt9.preferences.items;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.os.Build;
import androidx.preference.Preference;
@ -10,6 +7,7 @@ import androidx.preference.Preference;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.preferences.PreferencesActivity;
import io.github.sspanak.tt9.ui.UI;
import io.github.sspanak.tt9.util.Clipboard;
public class ItemText extends ItemClickable {
private final PreferencesActivity activity;
@ -21,16 +19,18 @@ public class ItemText extends ItemClickable {
@Override
protected boolean onClick(Preference p) {
if (activity == null) {
if (activity == null || p.getSummary() == null) {
return false;
}
ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE);
String label = activity.getString(R.string.app_name_short) + " / " + item.getTitle();
clipboard.setPrimaryClip(ClipData.newPlainText(label , p.getSummary()));
Clipboard.copy(
activity,
activity.getString(R.string.app_name_short) + " / " + item.getTitle(),
p.getSummary()
);
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) {
UI.toast(activity, "Text copied.");
UI.toast(activity, "\"" + Clipboard.getPreview(activity) + "\" copied.");
}
return true;
@ -43,6 +43,4 @@ public class ItemText extends ItemClickable {
return this;
}
}

View file

@ -6,7 +6,8 @@ import android.content.Context;
public class SettingsStore extends SettingsUI {
public SettingsStore(Context context) { super(context); }
/************* internal settings *************/
/************* internal settings *************/
public final static int CLIPBOARD_PREVIEW_LENGTH = 20;
public final static int DELETE_WORDS_SEARCH_DELAY = 500; // ms
public final static int DICTIONARY_AUTO_LOAD_COOLDOWN_TIME = 1200000; // 20 minutes in ms
public final static int DICTIONARY_DOWNLOAD_CONNECTION_TIMEOUT = 10000; // ms

View file

@ -77,15 +77,23 @@ abstract class BaseMainLayout {
}
int getHeight() {
int getHeight(boolean forceRecalculate) {
return 0;
}
void resetHeight() {}
int getHeight() {
return getHeight(false);
}
abstract void showCommandPalette();
abstract void hideCommandPalette();
abstract boolean isCommandPaletteShown();
abstract void showTextEditingPalette();
abstract void hideTextEditingPalette();
abstract boolean isTextEditingPaletteShown();
/**
* render

View file

@ -15,10 +15,14 @@ import java.util.Arrays;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.hacks.DeviceInfo;
import io.github.sspanak.tt9.ime.TraditionalT9;
import io.github.sspanak.tt9.ui.main.keys.SoftCommandKey;
import io.github.sspanak.tt9.ui.main.keys.SoftKey;
import io.github.sspanak.tt9.ui.main.keys.SoftKeySettings;
import io.github.sspanak.tt9.ui.main.keys.SoftNumberKey;
import io.github.sspanak.tt9.ui.main.keys.SoftPunctuationKey;
class MainLayoutNumpad extends BaseMainLayout {
private boolean isTextEditingShown = false;
private int height;
@ -82,6 +86,80 @@ class MainLayoutNumpad extends BaseMainLayout {
@Override boolean isCommandPaletteShown() { return false; }
@Override
void showTextEditingPalette() {
isTextEditingShown = true;
for (SoftKey key : getKeys()) {
int keyId = key.getId();
if (keyId == R.id.soft_key_0) {
key.setEnabled(tt9 != null && !tt9.isInputModeNumeric());
} else if (key.getClass().equals(SoftNumberKey.class)) {
key.setVisibility(View.GONE);
}
if (key.getClass().equals(SoftPunctuationKey.class)) {
key.setVisibility(View.INVISIBLE);
}
if (key.getClass().equals(SoftCommandKey.class)) {
key.setVisibility(View.VISIBLE);
}
if (keyId == R.id.soft_key_rf3) {
key.render();
}
if (
keyId == R.id.soft_key_add_word
|| keyId == R.id.soft_key_input_mode
|| keyId == R.id.soft_key_language
|| keyId == R.id.soft_key_filter_suggestions
) {
key.setEnabled(false);
}
}
}
@Override
void hideTextEditingPalette() {
isTextEditingShown = false;
for (SoftKey key : getKeys()) {
if (key.getClass().equals(SoftNumberKey.class) || key.getClass().equals(SoftPunctuationKey.class)) {
key.setVisibility(View.VISIBLE);
key.setEnabled(true);
}
if (key.getClass().equals(SoftCommandKey.class)) {
key.setVisibility(View.GONE);
}
int keyId = key.getId();
if (keyId == R.id.soft_key_rf3) {
key.render();
}
if (
keyId == R.id.soft_key_add_word
|| keyId == R.id.soft_key_input_mode
|| keyId == R.id.soft_key_language
|| keyId == R.id.soft_key_filter_suggestions
) {
key.setEnabled(true);
}
}
}
@Override
boolean isTextEditingPaletteShown() {
return isTextEditingShown;
}
/**
* Uses the key height from the settings, but if it takes up too much of the screen, it will
* be adjusted so that the entire Main View would take up around 50% of the screen in landscape mode
@ -120,8 +198,8 @@ class MainLayoutNumpad extends BaseMainLayout {
}
int getHeight() {
if (height <= 0) {
int getHeight(boolean forceRecalculate) {
if (height <= 0 || forceRecalculate) {
Resources resources = tt9.getResources();
height = getKeyHeightCompat() * 4
+ resources.getDimensionPixelSize(R.dimen.numpad_candidate_height)
@ -132,11 +210,6 @@ class MainLayoutNumpad extends BaseMainLayout {
}
void resetHeight() {
height = 0;
}
@Override
void render() {
getView();
@ -178,8 +251,7 @@ class MainLayoutNumpad extends BaseMainLayout {
}
}
ViewGroup statusBarContainer = view.findViewById(R.id.status_bar_container);
keys.addAll(getKeysFromContainer(statusBarContainer));
keys.addAll(getKeysFromContainer(view.findViewById(R.id.status_bar_container)));
return keys;
}

View file

@ -1,6 +1,5 @@
package io.github.sspanak.tt9.ui.main;
import android.content.res.Resources;
import android.view.View;
import android.widget.LinearLayout;
@ -14,19 +13,20 @@ import io.github.sspanak.tt9.ui.main.keys.SoftKey;
import io.github.sspanak.tt9.ui.main.keys.SoftKeyCommandPalette;
class MainLayoutSmall extends MainLayoutTray {
private int height;
MainLayoutSmall(TraditionalT9 tt9) {
super(tt9);
}
int getHeight() {
if (height <= 0) {
Resources resources = tt9.getResources();
height =
resources.getDimensionPixelSize(R.dimen.soft_key_height) +
resources.getDimensionPixelSize(R.dimen.candidate_height);
@Override
int getHeight(boolean forceRecalculate) {
if (height <= 0 || forceRecalculate) {
height = super.getHeight(forceRecalculate);
if (!isCommandPaletteShown() && !isTextEditingPaletteShown()) {
height += tt9.getResources().getDimensionPixelSize(R.dimen.soft_key_height);
}
}
return height;
}

View file

@ -5,11 +5,23 @@ import io.github.sspanak.tt9.ime.TraditionalT9;
class MainLayoutStealth extends BaseMainLayout {
private boolean isCommandPaletteShown = false;
private boolean isTextEditingPaletteShown = false;
MainLayoutStealth(TraditionalT9 tt9) { super(tt9, R.layout.main_stealth); }
@Override void showCommandPalette() { isCommandPaletteShown = true; }
@Override void showCommandPalette() {
isCommandPaletteShown = true;
isTextEditingPaletteShown = false;
}
@Override void hideCommandPalette() { isCommandPaletteShown = false; }
@Override boolean isCommandPaletteShown() { return isCommandPaletteShown; }
@Override void showTextEditingPalette() {
isTextEditingPaletteShown = true;
isCommandPaletteShown = false;
}
@Override void hideTextEditingPalette() { isTextEditingPaletteShown = false; }
@Override boolean isTextEditingPaletteShown() { return isTextEditingPaletteShown; }
@Override void render() {}
}

View file

@ -16,17 +16,22 @@ import io.github.sspanak.tt9.ime.TraditionalT9;
import io.github.sspanak.tt9.ui.main.keys.SoftKey;
class MainLayoutTray extends BaseMainLayout {
private int height;
protected int height;
MainLayoutTray(TraditionalT9 tt9) {
super(tt9, R.layout.main_small);
}
int getHeight() {
if (height <= 0) {
int getHeight(boolean forceRecalculate) {
if (height <= 0 || forceRecalculate) {
Resources resources = tt9.getResources();
height = resources.getDimensionPixelSize(R.dimen.candidate_height);
if (isCommandPaletteShown() || isTextEditingPaletteShown()) {
height += resources.getDimensionPixelSize(R.dimen.numpad_key_height);
}
}
return height;
}
@ -37,16 +42,46 @@ class MainLayoutTray extends BaseMainLayout {
}
void showCommandPalette() {
view.findViewById(R.id.main_command_keys).setVisibility(LinearLayout.VISIBLE);
view.findViewById(R.id.text_editing_container).setVisibility(LinearLayout.GONE);
view.findViewById(R.id.main_soft_keys).setVisibility(LinearLayout.GONE);
view.findViewById(R.id.main_command_keys).setVisibility(LinearLayout.VISIBLE);
height = 0;
getHeight();
}
void hideCommandPalette() {
view.findViewById(R.id.main_command_keys).setVisibility(LinearLayout.GONE);
height = 0;
getHeight();
}
boolean isCommandPaletteShown() {
return view.findViewById(R.id.main_command_keys).getVisibility() == LinearLayout.VISIBLE;
return view != null && view.findViewById(R.id.main_command_keys).getVisibility() == LinearLayout.VISIBLE;
}
@Override
void showTextEditingPalette() {
view.findViewById(R.id.main_command_keys).setVisibility(LinearLayout.GONE);
view.findViewById(R.id.main_soft_keys).setVisibility(LinearLayout.GONE);
view.findViewById(R.id.text_editing_container).setVisibility(LinearLayout.VISIBLE);
height = 0;
getHeight();
}
@Override
void hideTextEditingPalette() {
view.findViewById(R.id.text_editing_container).setVisibility(LinearLayout.GONE);
height = 0;
getHeight();
}
@Override
boolean isTextEditingPaletteShown() {
return view != null && view.findViewById(R.id.text_editing_container).getVisibility() == LinearLayout.VISIBLE;
}
protected Drawable getBackgroundColor(@NonNull View contextView, boolean dark) {
@ -71,6 +106,7 @@ class MainLayoutTray extends BaseMainLayout {
// background
view.findViewById(R.id.main_command_keys).setBackground(getBackgroundColor(view, dark));
view.findViewById(R.id.text_editing_container).setBackground(getBackgroundColor(view, dark));
// text
for (SoftKey key : getKeys()) {
@ -100,6 +136,7 @@ class MainLayoutTray extends BaseMainLayout {
protected ArrayList<SoftKey> getKeys() {
if (view != null && keys.isEmpty()) {
keys.addAll(getKeysFromContainer(view.findViewById(R.id.main_command_keys)));
keys.addAll(getKeysFromContainer(view.findViewById(R.id.text_editing_keys_small)));
}
return keys;
}
@ -108,9 +145,19 @@ class MainLayoutTray extends BaseMainLayout {
return new ArrayList<>(Arrays.asList(
view.findViewById(R.id.separator_top),
view.findViewById(R.id.separator_candidates_bottom),
view.findViewById(R.id.separator_1_1),
view.findViewById(R.id.separator_1_2),
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_10_1),
view.findViewById(R.id.separator_10_2),
view.findViewById(R.id.separator_10_2),
view.findViewById(R.id.separator_10_3),
view.findViewById(R.id.separator_10_4),
view.findViewById(R.id.separator_10_5),
view.findViewById(R.id.separator_10_6),
view.findViewById(R.id.separator_10_7),
view.findViewById(R.id.separator_10_8)
));
}
}

View file

@ -50,6 +50,8 @@ public class MainView {
}
public void render() {
main.hideCommandPalette();
main.hideTextEditingPalette();
main.render();
}
@ -72,4 +74,20 @@ public class MainView {
public boolean isCommandPaletteShown() {
return main != null && main.isCommandPaletteShown();
}
public void showTextEditingPalette() {
if (main != null) {
main.showTextEditingPalette();
}
}
public void hideTextEditingPalette() {
if (main != null) {
main.hideTextEditingPalette();
}
}
public boolean isTextEditingPaletteShown() {
return main != null && main.isTextEditingPaletteShown();
}
}

View file

@ -24,7 +24,7 @@ public class ResizableMainView extends MainView implements View.OnAttachStateCha
public ResizableMainView(TraditionalT9 tt9) {
super(tt9);
resetHeight();
calculateSnapHeights();
}
@ -35,27 +35,9 @@ public class ResizableMainView extends MainView implements View.OnAttachStateCha
}
private void calculateInitialHeight() {
if (main == null) {
return;
}
if (tt9.getSettings().isMainLayoutNumpad()) {
height = heightNumpad;
} else if (tt9.getSettings().isMainLayoutSmall()) {
height = heightSmall;
} else {
height = heightTray;
}
}
@Override
public boolean createInputView() {
if (!super.createInputView()) {
// recalculate the total height in case the user has changed the key height in the settings
resetHeight();
return false;
}
@ -79,8 +61,6 @@ public class ResizableMainView extends MainView implements View.OnAttachStateCha
public void onOrientationChanged() {
calculateSnapHeights();
calculateInitialHeight();
hideCommandPalette();
render();
}
@ -211,14 +191,51 @@ public class ResizableMainView extends MainView implements View.OnAttachStateCha
return true;
}
private void fitMain() {
calculateSnapHeights();
int heightLow, heightHigh, heightMain = main.getHeight(true);
private void resetHeight() {
if (main != null) {
main.resetHeight();
if (main instanceof MainLayoutNumpad) {
heightLow = heightSmall;
heightHigh = heightNumpad;
} else if (main instanceof MainLayoutSmall) {
heightLow = 0;
heightHigh = Math.max(heightSmall, heightMain); // make room for the command palette
} else {
heightLow = 0;
heightHigh = Math.max(heightTray, heightMain); // make room for the command palette
}
calculateSnapHeights();
calculateInitialHeight();
setHeight(height, heightSmall, heightNumpad);
setHeight(heightMain, heightLow, heightHigh);
}
@Override
public void showCommandPalette() {
super.showCommandPalette();
fitMain();
}
@Override
public void hideCommandPalette() {
super.hideCommandPalette();
fitMain();
}
@Override
public void showTextEditingPalette() {
super.showTextEditingPalette();
fitMain();
}
@Override
public void hideTextEditingPalette() {
super.hideTextEditingPalette();
fitMain();
}
@Override
public void render() {
super.render();
fitMain();
}
}

View file

@ -1,8 +1,14 @@
package io.github.sspanak.tt9.ui.main.keys;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.core.widget.TextViewCompat;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.util.Characters;
@ -12,46 +18,73 @@ public class SoftCommandKey extends SoftNumberKey {
public SoftCommandKey(Context context, AttributeSet attrs) { super(context, attrs);}
public SoftCommandKey(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr);}
@Override protected void handleHold() {}
@Override
public void setDarkTheme(boolean darkEnabled) {
super.setDarkTheme(darkEnabled);
final int color = darkEnabled ? R.color.dark_button_text : R.color.button_text;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
TextViewCompat.setCompoundDrawableTintList(this, ColorStateList.valueOf(getContext().getColor(color)));
} else {
setDarkThemeLegacy(color);
}
}
private void setDarkThemeLegacy(int color) {
Drawable[] icons = getCompoundDrawables();
if (icons.length >= 4 && icons[3] != null) {
Drawable icon = DrawableCompat.wrap(icons[3]);
DrawableCompat.setTint(icon, getResources().getColor(color));
setCompoundDrawables(null, null, null, icon);
}
}
protected String getTextSubTitle(int resId) {
setTextSize(SettingsStore.SOFT_KEY_TITLE_SIZE);
return getContext().getString(resId);
}
@Override
protected String getTitle() {
return getNumber(getId()) + "";
}
private String getTextSubTitle(int resId) {
setTextSize(SettingsStore.SOFT_KEY_TITLE_SIZE);
return getContext().getString(resId);
}
@Override
protected String getSubTitle() {
int number = getNumber(getId());
boolean noIconSupport = Characters.noEmojiSupported();
int keyId = getId();
switch (number) {
case 0:
return noIconSupport ? getTextSubTitle(R.string.virtual_key_change_keyboard) : "";
case 1:
return noIconSupport ? getTextSubTitle(R.string.virtual_key_settings) : "";
case 2:
return "";
case 3:
return "🎤";
// case 5:
// return "";
}
// command palette
if (keyId == R.id.soft_key_1) return noIconSupport ? getTextSubTitle(R.string.virtual_key_settings) : "";
if (keyId == R.id.soft_key_2) return "";
if (keyId == R.id.soft_key_8) return noIconSupport ? getTextSubTitle(R.string.virtual_key_change_keyboard) : "";
return null;
}
@Override
public void render() {
if (tt9 != null && tt9.isVoiceInputMissing() && getNumber(getId()) == 3) {
setVisibility(GONE);
} else {
super.render();
}
protected int getNumber(int keyId) {
if (keyId == R.id.soft_key_101) return 1;
if (keyId == R.id.soft_key_102) return 2;
if (keyId == R.id.soft_key_103) return 3;
if (keyId == R.id.soft_key_104) return 4;
if (keyId == R.id.soft_key_105) return 5;
if (keyId == R.id.soft_key_106) return 6;
if (keyId == R.id.soft_key_107) return 7;
if (keyId == R.id.soft_key_108) return 8;
if (keyId == R.id.soft_key_109) return 9;
return super.getNumber(keyId);
}
}

View file

@ -155,13 +155,6 @@ public class SoftKey extends androidx.appcompat.widget.AppCompatButton implement
protected boolean handleRelease() {
if (!validateTT9Handler()) {
return false;
}
int keyId = getId();
if (keyId == R.id.soft_key_voice_input) { tt9.toggleVoiceInput(); return true; }
return false;
}

View file

@ -0,0 +1,29 @@
package io.github.sspanak.tt9.ui.main.keys;
import android.content.Context;
import android.util.AttributeSet;
public class SoftKeyF3 extends SoftCommandKey {
public SoftKeyF3(Context context) {
super(context);
}
public SoftKeyF3(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SoftKeyF3(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected String getSubTitle() {
return "🎤";
}
@Override
public void render() {
setVisibility(tt9 != null && tt9.isVoiceInputMissing() ? GONE : VISIBLE);
super.render();
}
}

View file

@ -0,0 +1,32 @@
package io.github.sspanak.tt9.ui.main.keys;
import android.content.Context;
import android.util.AttributeSet;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.util.Characters;
public class SoftKeyF5 extends SoftCommandKey {
public SoftKeyF5(Context context) {
super(context);
}
public SoftKeyF5(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SoftKeyF5(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected String getSubTitle() {
return Characters.noEmojiSupported() ? getTextSubTitle(R.string.virtual_key_text_editing) : "";
}
@Override
public void render() {
setVisibility(tt9 != null && tt9.isInputLimited() ? GONE : VISIBLE);
super.render();
}
}

View file

@ -0,0 +1,88 @@
package io.github.sspanak.tt9.ui.main.keys;
import android.content.Context;
import android.util.AttributeSet;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
public class SoftKeyRF3 extends SoftKey {
public SoftKeyRF3(Context context) { super(context); setFontSize(); }
public SoftKeyRF3(Context context, AttributeSet attrs) { super(context, attrs); setFontSize(); }
public SoftKeyRF3(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); setFontSize(); }
private void setFontSize() {
complexLabelTitleSize = SettingsStore.SOFT_KEY_COMPLEX_LABEL_TITLE_RELATIVE_SIZE / 0.85f;
complexLabelSubTitleSize = SettingsStore.SOFT_KEY_COMPLEX_LABEL_SUB_TITLE_RELATIVE_SIZE / 0.85f;
}
private boolean isVoiceInputMissing() {
return tt9 != null && tt9.isVoiceInputMissing();
}
private boolean isTextEditingMissing() {
return tt9 != null && tt9.isInputLimited();
}
private boolean isTextEdtingActive() {
return tt9 != null && tt9.isTextEditingActive();
}
@Override
protected void handleHold() {
if (!validateTT9Handler() || isTextEdtingActive()) {
return;
}
preventRepeat();
if (tt9.isVoiceInputActive()) {
tt9.toggleVoiceInput();
} else {
tt9.showTextEditingPalette();
}
}
@Override
protected boolean handleRelease() {
if (!validateTT9Handler()) {
return false;
}
if (isTextEdtingActive()) {
tt9.hideTextEditingPalette();
} else {
tt9.toggleVoiceInput();
}
return true;
}
@Override
protected String getTitle() {
if (isTextEdtingActive()) {
if (tt9 == null) {
return "ABC";
} else if (tt9.isInputModeNumeric()) {
return "123";
} else if (tt9.getLanguage() != null) {
return tt9.getLanguage().getAbcString().toUpperCase(tt9.getLanguage().getLocale());
}
}
return isTextEditingMissing() && !isVoiceInputMissing() ? "🎤" : getContext().getString(R.string.virtual_key_text_editing).toUpperCase();
}
@Override
protected String getSubTitle() {
return isTextEdtingActive() || (!isVoiceInputMissing() && isTextEditingMissing()) ? null : "🎤";
}
@Override
public void render() {
if (isVoiceInputMissing() && isTextEditingMissing()) {
setVisibility(INVISIBLE);
} else {
super.render();
}
}
}

View file

@ -0,0 +1,59 @@
package io.github.sspanak.tt9.ui.main.keys;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.core.widget.TextViewCompat;
import io.github.sspanak.tt9.R;
public class SoftKeyTextEdit extends SoftNumberKey {
public SoftKeyTextEdit(Context context) {
super(context);
}
public SoftKeyTextEdit(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SoftKeyTextEdit(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public void setDarkTheme(boolean darkEnabled) {
super.setDarkTheme(darkEnabled);
final int color = darkEnabled ? R.color.dark_button_text : R.color.button_text;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
TextViewCompat.setCompoundDrawableTintList(this, ColorStateList.valueOf(getContext().getColor(color)));
} else {
setDarkThemeLegacy(color);
}
}
private void setDarkThemeLegacy(int color) {
Drawable[] icons = getCompoundDrawables();
if (icons.length >= 4 && icons[3] != null) {
Drawable icon = DrawableCompat.wrap(icons[3]);
DrawableCompat.setTint(icon, getResources().getColor(color));
setCompoundDrawables(null, null, null, icon);
}
}
private Drawable getIcon(int resId) {
return getResources().getDrawable(resId);
}
@Override
protected String getSubTitle() {
return super.getSubTitle();
}
}

View file

@ -1,24 +0,0 @@
package io.github.sspanak.tt9.ui.main.keys;
import android.content.Context;
import android.util.AttributeSet;
public class SoftVoiceInputKey extends SoftKey {
public SoftVoiceInputKey(Context context) { super(context); }
public SoftVoiceInputKey(Context context, AttributeSet attrs) { super(context, attrs); }
public SoftVoiceInputKey(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); }
@Override
protected String getTitle() {
return "🎤";
}
@Override
public void render() {
if (tt9 != null && tt9.isVoiceInputMissing()) {
setVisibility(INVISIBLE);
} else {
super.render();
}
}
}

View file

@ -0,0 +1,75 @@
package io.github.sspanak.tt9.util;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import androidx.annotation.NonNull;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
public class Clipboard {
private static Runnable externalChangeListener;
private static boolean ignoreNextChange = false;
@NonNull private static CharSequence lastText = "";
public static void copy(@NonNull Context context, @NonNull CharSequence label, @NonNull CharSequence text) {
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
clipboard.setPrimaryClip(ClipData.newPlainText(label, text));
// Android clipboard works unreliably on all versions from 5 to 14, even when invoked from
// the context menu. So, just in case, we keep a backup of the text.
lastText = text;
ignoreNextChange = true;
}
public static void copy(@NonNull Context context, @NonNull CharSequence text) {
String label = context.getString(R.string.app_name_short) + " / text";
copy(context, label, text);
}
@NonNull public static String paste(@NonNull Context context) {
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = clipboard.getPrimaryClip();
// Try using the shared clipboard, but if Android has failed preserving it, use our backup.
CharSequence text = clip != null && clip.getItemCount() > 0 ? clip.getItemAt(0).getText() : "";
text = text == null || text.length() == 0 ? lastText : text;
return text.toString();
}
@NonNull public static String getPreview(@NonNull Context context) {
String text = paste(context);
if (text.length() > SettingsStore.CLIPBOARD_PREVIEW_LENGTH) {
return text.substring(0, SettingsStore.CLIPBOARD_PREVIEW_LENGTH) + "...";
}
return text;
}
public static void setOnChangeListener(Context context, Runnable newListener) {
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
if (newListener != null) {
clipboard.addPrimaryClipChangedListener(Clipboard::changeListener);
} else if (externalChangeListener != null) {
clipboard.removePrimaryClipChangedListener(Clipboard::changeListener);
}
externalChangeListener = newListener;
}
private static void changeListener() {
if (ignoreNextChange) {
ignoreNextChange = false;
} else if (externalChangeListener != null) {
externalChangeListener.run();
}
}
}

View file

@ -0,0 +1,7 @@
package io.github.sspanak.tt9.util;
public enum Ternary {
FALSE,
TRUE,
ALTERNATIVE
}

View file

@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFF"
android:autoMirrored="true">
<group android:scaleX="2.208"
android:scaleY="2.208"
android:translateX="-13.392"
android:translateY="-14.496">
<path
android:fillColor="@android:color/white"
android:pathData="M14,7l-5,5 5,5V7z"/>
</group>
</vector>

View file

@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFF"
android:autoMirrored="true">
<group android:scaleX="2.208"
android:scaleY="2.208"
android:translateX="-15.6"
android:translateY="-14.496">
<path
android:fillColor="@android:color/white"
android:pathData="M10,17l5,-5 -5,-5v10z"/>
</group>
</vector>

View file

@ -0,0 +1,15 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFF">
<group android:scaleX="1.0036364"
android:scaleY="1.0036364"
android:translateX="0.45818183"
android:translateY="-0.043636363">
<path
android:fillColor="@android:color/white"
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z"/>
</group>
</vector>

View file

@ -0,0 +1,15 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFF">
<group android:scaleX="1.104"
android:scaleY="1.104"
android:translateX="-1.248"
android:translateY="-1.248">
<path
android:fillColor="@android:color/white"
android:pathData="M9.64,7.64c0.23,-0.5 0.36,-1.05 0.36,-1.64 0,-2.21 -1.79,-4 -4,-4S2,3.79 2,6s1.79,4 4,4c0.59,0 1.14,-0.13 1.64,-0.36L10,12l-2.36,2.36C7.14,14.13 6.59,14 6,14c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4c0,-0.59 -0.13,-1.14 -0.36,-1.64L12,14l7,7h3v-1L9.64,7.64zM6,8c-1.1,0 -2,-0.89 -2,-2s0.9,-2 2,-2 2,0.89 2,2 -0.9,2 -2,2zM6,20c-1.1,0 -2,-0.89 -2,-2s0.9,-2 2,-2 2,0.89 2,2 -0.9,2 -2,2zM12,12.5c-0.28,0 -0.5,-0.22 -0.5,-0.5s0.22,-0.5 0.5,-0.5 0.5,0.22 0.5,0.5 -0.22,0.5 -0.5,0.5zM19,3l-6,6 2,2 7,-7L22,3z"/>
</group>
</vector>

View file

@ -0,0 +1,15 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFF">
<group android:scaleX="1.0036364"
android:scaleY="1.0036364"
android:translateX="-0.043636363"
android:translateY="0.96">
<path
android:fillColor="@android:color/white"
android:pathData="M19,2h-4.18C14.4,0.84 13.3,0 12,0c-1.3,0 -2.4,0.84 -2.82,2L5,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,4c0,-1.1 -0.9,-2 -2,-2zM12,2c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM19,20L5,20L5,4h2v3h10L17,4h2v16z"/>
</group>
</vector>

View file

@ -0,0 +1,15 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFF">
<group android:scaleX="1.2266667"
android:scaleY="1.2266667"
android:translateX="-2.72"
android:translateY="-2.72">
<path
android:fillColor="@android:color/white"
android:pathData="M3,5h2L5,3c-1.1,0 -2,0.9 -2,2zM3,13h2v-2L3,11v2zM7,21h2v-2L7,19v2zM3,9h2L5,7L3,7v2zM13,3h-2v2h2L13,3zM19,3v2h2c0,-1.1 -0.9,-2 -2,-2zM5,21v-2L3,19c0,1.1 0.9,2 2,2zM3,17h2v-2L3,15v2zM9,3L7,3v2h2L9,3zM11,21h2v-2h-2v2zM19,13h2v-2h-2v2zM19,21c1.1,0 2,-0.9 2,-2h-2v2zM19,9h2L21,7h-2v2zM19,17h2v-2h-2v2zM15,21h2v-2h-2v2zM15,5h2L17,3h-2v2zM7,17h10L17,7L7,7v10zM9,9h6v6L9,15L9,9z"/>
</group>
</vector>

View file

@ -0,0 +1,15 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFF">
<group android:scaleX="1.0514286"
android:scaleY="1.0514286"
android:translateX="-0.09142857"
android:translateY="-1.1428572">
<path
android:fillColor="@android:color/white"
android:pathData="M3,13h2v-2H3V13zM7,21h2v-2H7V21zM13,3h-2v2h2V3zM19,3v2h2C21,3.9 20.1,3 19,3zM5,21v-2H3C3,20.1 3.9,21 5,21zM3,17h2v-2H3V17zM11,21h2v-2h-2V21zM19,13h2v-2h-2V13zM19,9h2V7h-2V9zM15,5h2V3h-2V5zM7.83,5L7,4.17V3h2v2H7.83zM19.83,17L19,16.17V15h2v2H19.83zM21.19,21.19L2.81,2.81L1.39,4.22L4.17,7H3v2h2V7.83l2,2V17h7.17l2,2H15v2h2v-1.17l2.78,2.78L21.19,21.19zM9,15v-3.17L12.17,15H9zM15,12.17V9h-3.17l-2,-2H17v7.17L15,12.17z"/>
</group>
</vector>

View file

@ -0,0 +1,15 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFF">
<group android:scaleX="1.2266667"
android:scaleY="1.2266667"
android:translateX="-1.4933333"
android:translateY="-2.72">
<path
android:fillColor="@android:color/white"
android:pathData="M11,18L11,6l-8.5,6 8.5,6zM11.5,12l8.5,6L20,6l-8.5,6z"/>
</group>
</vector>

View file

@ -0,0 +1,15 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFF">
<group android:scaleX="1.2266667"
android:scaleY="1.2266667"
android:translateX="-3.9466667"
android:translateY="-2.72">
<path
android:fillColor="@android:color/white"
android:pathData="M4,18l8.5,-6L4,6v12zM13,6v12l8.5,-6L13,6z"/>
</group>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 613 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 493 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 809 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 735 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 532 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 475 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 443 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 654 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 679 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 853 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 785 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 812 B

View file

@ -86,248 +86,10 @@
android:id="@+id/separator_candidates_bottom"
style="@style/numRowSeparator" />
<!-- Keypad Wrapper -->
<LinearLayout
<include
layout="@layout/panel_numpad"
android:id="@+id/main_soft_keys"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="@dimen/numpad_padding_bottom">
<!-- Row 1 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/numpad_key_height"
android:layoutDirection="ltr"
tools:ignore="HardcodedText,KeyboardInaccessibleWidget">
<io.github.sspanak.tt9.ui.main.keys.SoftKeySettings
android:id="@+id/soft_key_settings"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="@dimen/numpad_control_key_layout_weight"
android:text="⚙"
android:textSize="@dimen/soft_key_icon_size" />
<View
android:id="@+id/separator_1_1"
style="@style/numSeparator" />
<!-- Digits 1-3 -->
<io.github.sspanak.tt9.ui.main.keys.SoftNumberKey
android:id="@+id/soft_key_1"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<io.github.sspanak.tt9.ui.main.keys.SoftNumberKey
android:id="@+id/soft_key_2"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<io.github.sspanak.tt9.ui.main.keys.SoftNumberKey
android:id="@+id/soft_key_3"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<View
android:id="@+id/separator_1_2"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftBackspaceKey
android:id="@+id/soft_key_backspace"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="@dimen/numpad_control_key_layout_weight"
android:textSize="@dimen/soft_key_icon_size" />
</LinearLayout>
<!-- Row 2 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/numpad_key_height"
android:layoutDirection="ltr"
tools:ignore="HardcodedText">
<io.github.sspanak.tt9.ui.main.keys.SoftKeyAddWord
android:id="@+id/soft_key_add_word"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="@dimen/numpad_control_key_layout_weight"
android:text=""
android:textStyle="bold" />
<View
android:id="@+id/separator_2_1"
style="@style/numSeparator" />
<!-- Digits 4-6 -->
<io.github.sspanak.tt9.ui.main.keys.SoftNumberKey
android:id="@+id/soft_key_4"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<io.github.sspanak.tt9.ui.main.keys.SoftNumberKey
android:id="@+id/soft_key_5"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<io.github.sspanak.tt9.ui.main.keys.SoftNumberKey
android:id="@+id/soft_key_6"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<View
android:id="@+id/separator_2_2"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftFilterKey
android:id="@+id/soft_key_filter_suggestions"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="@dimen/numpad_control_key_layout_weight" />
</LinearLayout>
<!-- Row 3 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/numpad_key_height"
android:layoutDirection="ltr"
tools:ignore="HardcodedText">
<io.github.sspanak.tt9.ui.main.keys.SoftInputModeKey
android:id="@+id/soft_key_input_mode"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="@dimen/numpad_control_key_layout_weight"
android:text="⌨"
android:textSize="@dimen/soft_key_icon_size" />
<View
android:id="@+id/separator_3_1"
style="@style/numSeparator" />
<!-- Digits 7-9 -->
<io.github.sspanak.tt9.ui.main.keys.SoftNumberKey
android:id="@+id/soft_key_7"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<io.github.sspanak.tt9.ui.main.keys.SoftNumberKey
android:id="@+id/soft_key_8"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<io.github.sspanak.tt9.ui.main.keys.SoftNumberKey
android:id="@+id/soft_key_9"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<View
android:id="@+id/separator_3_2"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftVoiceInputKey
android:id="@+id/soft_key_voice_input"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="@dimen/numpad_control_key_layout_weight" />
</LinearLayout>
<!-- Row 4 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/numpad_key_height"
android:layoutDirection="ltr"
tools:ignore="HardcodedText">
<io.github.sspanak.tt9.ui.main.keys.SoftKeyNextLanguage
android:id="@+id/soft_key_language"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="@dimen/numpad_control_key_layout_weight"
android:text="🌐" />
<View
android:id="@+id/separator_4_1"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftPunctuationKey
android:id="@+id/soft_key_punctuation_1"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<io.github.sspanak.tt9.ui.main.keys.SoftNumberKey
android:id="@+id/soft_key_0"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<io.github.sspanak.tt9.ui.main.keys.SoftPunctuationKey
android:id="@+id/soft_key_punctuation_2"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<View
android:id="@+id/separator_4_2"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftOkKey
android:id="@+id/soft_key_ok"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="@dimen/numpad_control_key_layout_weight"
android:text="OK"
tools:ignore="ButtonOrder" />
</LinearLayout>
</LinearLayout>
android:paddingBottom="@dimen/numpad_padding_bottom"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -23,9 +24,9 @@
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/suggestions_bar"
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="horizontal"
android:scrollbars="none" />
@ -35,105 +36,18 @@
android:id="@+id/separator_candidates_bottom"
style="@style/numRowSeparator" />
<LinearLayout
android:id="@+id/main_soft_keys"
android:layout_width="match_parent"
android:layout_height="@dimen/soft_key_height"
android:baselineAligned="true"
android:orientation="horizontal"
tools:ignore="HardcodedText,KeyboardInaccessibleWidget">
<include
layout="@layout/panel_small_function_keys"
android:id="@+id/main_soft_keys" />
<io.github.sspanak.tt9.ui.main.keys.SoftKeyCommandPalette
android:id="@+id/soft_key_command_palette"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:focusable="false"
android:text="🛠"
android:textSize="@dimen/soft_key_icon_size" />
<View
android:id="@+id/main_separator_left"
style="@style/hSeparator"
android:background="@drawable/button_separator_dark" />
<io.github.sspanak.tt9.ui.main.keys.SoftOkKey
android:id="@+id/soft_key_ok"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="5"
android:focusable="false"
android:text="@android:string/ok" />
<View
android:id="@+id/main_separator_right"
android:background="@drawable/button_separator_dark"
style="@style/hSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftBackspaceKey
style="@android:style/Widget.Holo.Button.Borderless"
android:id="@+id/soft_key_backspace"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:focusable="false"
android:text="⌫"
android:textSize="@dimen/soft_key_icon_size" />
</LinearLayout>
<LinearLayout
<include
layout="@layout/panel_command_palette"
android:id="@+id/main_command_keys"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="gone">
android:visibility="gone" />
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
android:id="@+id/soft_key_1"
style="@android:style/Widget.Holo.Button.Borderless"
android:textSize="@dimen/soft_key_icon_size"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<View
android:id="@+id/separator_2_1"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
android:id="@+id/soft_key_2"
style="@android:style/Widget.Holo.Button.Borderless"
android:textSize="@dimen/soft_key_icon_size"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<View
android:id="@+id/separator_2_2"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
android:id="@+id/soft_key_3"
style="@android:style/Widget.Holo.Button.Borderless"
android:textSize="@dimen/soft_key_icon_size"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<View
android:id="@+id/separator_3_1"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
android:id="@+id/soft_key_0"
style="@android:style/Widget.Holo.Button.Borderless"
android:textSize="@dimen/soft_key_icon_size"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
<include
layout="@layout/panel_small_text_editing"
android:id="@+id/text_editing_container"
android:visibility="gone" />
</LinearLayout>

View file

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="@layout/main_small"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
android:id="@+id/soft_key_1"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="@dimen/numpad_key_height"
android:layout_weight="1"
android:textSize="@dimen/soft_key_icon_size" />
<View
android:id="@+id/separator_1_1"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
android:id="@+id/soft_key_2"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="@dimen/numpad_key_height"
android:layout_weight="1"
android:textSize="@dimen/soft_key_icon_size" />
<View
android:id="@+id/separator_1_2"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftKeyF3
android:id="@+id/soft_key_3"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="@dimen/numpad_key_height"
android:layout_weight="1"
android:textSize="@dimen/soft_key_icon_size" />
<View
android:id="@+id/separator_2_1"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftKeyF5
android:id="@+id/soft_key_5"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="@dimen/numpad_key_height"
android:layout_weight="1"
android:textSize="@dimen/soft_key_icon_size" />
<View
android:id="@+id/separator_2_2"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
android:id="@+id/soft_key_8"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="@dimen/numpad_key_height"
android:layout_weight="1"
android:textSize="@dimen/soft_key_icon_size" />
</LinearLayout>

View file

@ -0,0 +1,175 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="@layout/main_numpad"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- Row 1 -->
<LinearLayout
tools:ignore="HardcodedText,KeyboardInaccessibleWidget"
android:layout_width="match_parent"
android:layout_height="@dimen/numpad_key_height"
android:layoutDirection="ltr">
<io.github.sspanak.tt9.ui.main.keys.SoftKeySettings
android:id="@+id/soft_key_settings"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="@dimen/numpad_control_key_layout_weight"
android:text="⚙"
android:textSize="@dimen/soft_key_icon_size" />
<View
android:id="@+id/separator_1_1"
style="@style/numSeparator" />
<include
android:id="@+id/numpad_row_1"
layout="@layout/panel_numpad_row_1" />
<include
layout="@layout/panel_numpad_text_editing_row_1"
android:id="@+id/text_editing_row_1"
android:visibility="gone" />
<View
android:id="@+id/separator_1_2"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftBackspaceKey
android:id="@+id/soft_key_backspace"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="@dimen/numpad_control_key_layout_weight"
android:textSize="@dimen/soft_key_icon_size" />
</LinearLayout>
<!-- Row 2 -->
<LinearLayout
tools:ignore="HardcodedText"
android:layout_width="match_parent"
android:layout_height="@dimen/numpad_key_height"
android:layoutDirection="ltr">
<io.github.sspanak.tt9.ui.main.keys.SoftKeyAddWord
android:id="@+id/soft_key_add_word"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="@dimen/numpad_control_key_layout_weight"
android:text=""
android:textStyle="bold" />
<View
android:id="@+id/separator_2_1"
style="@style/numSeparator" />
<include
android:id="@+id/numpad_row_2"
layout="@layout/panel_numpad_row_2" />
<include
layout="@layout/panel_numpad_text_editing_row_2"
android:id="@+id/text_editing_row_2"
android:visibility="gone" />
<View
android:id="@+id/separator_2_2"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftFilterKey
android:id="@+id/soft_key_filter_suggestions"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="@dimen/numpad_control_key_layout_weight" />
</LinearLayout>
<!-- Row 3 -->
<LinearLayout
tools:ignore="HardcodedText"
android:layout_width="match_parent"
android:layout_height="@dimen/numpad_key_height"
android:layoutDirection="ltr">
<io.github.sspanak.tt9.ui.main.keys.SoftInputModeKey
android:id="@+id/soft_key_input_mode"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="@dimen/numpad_control_key_layout_weight"
android:text="⌨"
android:textSize="@dimen/soft_key_icon_size" />
<View
android:id="@+id/separator_3_1"
style="@style/numSeparator" />
<include
android:id="@+id/numpad_row_3"
layout="@layout/panel_numpad_row_3" />
<include
layout="@layout/panel_numpad_text_editing_row_3"
android:id="@+id/text_editing_row_3"
android:visibility="gone" />
<View
android:id="@+id/separator_3_2"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftKeyRF3
android:id="@+id/soft_key_rf3"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="@dimen/numpad_control_key_layout_weight" />
</LinearLayout>
<!-- Row 4 -->
<LinearLayout
tools:ignore="HardcodedText"
android:layout_width="match_parent"
android:layout_height="@dimen/numpad_key_height"
android:layoutDirection="ltr">
<io.github.sspanak.tt9.ui.main.keys.SoftKeyNextLanguage
android:id="@+id/soft_key_language"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="@dimen/numpad_control_key_layout_weight"
android:text="🌐" />
<View
android:id="@+id/separator_4_1"
style="@style/numSeparator" />
<include
android:id="@+id/numpad_row_4"
layout="@layout/panel_numpad_row_4" />
<View
android:id="@+id/separator_4_2"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftOkKey
android:id="@+id/soft_key_ok"
style="@android:style/Widget.Holo.Button.Borderless"
tools:ignore="ButtonOrder"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="@dimen/numpad_control_key_layout_weight"
android:text="OK" />
</LinearLayout>
</LinearLayout>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<io.github.sspanak.tt9.ui.main.keys.SoftNumberKey
android:id="@+id/soft_key_1"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<io.github.sspanak.tt9.ui.main.keys.SoftNumberKey
android:id="@+id/soft_key_2"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<io.github.sspanak.tt9.ui.main.keys.SoftNumberKey
android:id="@+id/soft_key_3"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
</merge>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<io.github.sspanak.tt9.ui.main.keys.SoftNumberKey
android:id="@+id/soft_key_4"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<io.github.sspanak.tt9.ui.main.keys.SoftNumberKey
android:id="@+id/soft_key_5"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<io.github.sspanak.tt9.ui.main.keys.SoftNumberKey
android:id="@+id/soft_key_6"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
</merge>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<io.github.sspanak.tt9.ui.main.keys.SoftNumberKey
android:id="@+id/soft_key_7"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<io.github.sspanak.tt9.ui.main.keys.SoftNumberKey
android:id="@+id/soft_key_8"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<io.github.sspanak.tt9.ui.main.keys.SoftNumberKey
android:id="@+id/soft_key_9"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
</merge>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<io.github.sspanak.tt9.ui.main.keys.SoftPunctuationKey
android:id="@+id/soft_key_punctuation_1"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<io.github.sspanak.tt9.ui.main.keys.SoftNumberKey
android:id="@+id/soft_key_0"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<io.github.sspanak.tt9.ui.main.keys.SoftPunctuationKey
android:id="@+id/soft_key_punctuation_2"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
</merge>

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
android:id="@+id/soft_key_101"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawableBottom="@drawable/ic_dpad_left"
android:paddingBottom="@dimen/soft_key_drawable_bottom_padding"
android:textSize="@dimen/soft_key_drawable_title_size"
android:visibility="gone" />
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
android:id="@+id/soft_key_102"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawableBottom="@drawable/ic_txt_select_none"
android:paddingBottom="@dimen/soft_key_drawable_bottom_padding"
android:textSize="@dimen/soft_key_drawable_title_size"
android:visibility="gone" />
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
android:id="@+id/soft_key_103"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawableBottom="@drawable/ic_dpad_right"
android:paddingBottom="@dimen/soft_key_drawable_bottom_padding"
android:textSize="@dimen/soft_key_drawable_title_size"
android:visibility="gone" />
</merge>

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
android:id="@+id/soft_key_104"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawableBottom="@drawable/ic_txt_word_back"
android:paddingBottom="@dimen/soft_key_drawable_bottom_padding"
android:textSize="@dimen/soft_key_drawable_title_size"
android:visibility="gone" />
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
android:id="@+id/soft_key_105"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawableBottom="@drawable/ic_txt_select_all"
android:paddingBottom="@dimen/soft_key_drawable_bottom_padding"
android:textSize="@dimen/soft_key_drawable_title_size"
android:visibility="gone" />
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
android:id="@+id/soft_key_106"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawableBottom="@drawable/ic_txt_word_forward"
android:paddingBottom="@dimen/soft_key_drawable_bottom_padding"
android:textSize="@dimen/soft_key_drawable_title_size"
android:visibility="gone" />
</merge>

View file

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
android:id="@+id/soft_key_107"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawableBottom="@drawable/ic_txt_cut"
android:paddingBottom="@dimen/soft_key_drawable_bottom_padding"
android:textSize="@dimen/soft_key_drawable_title_size"
android:visibility="gone" />
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
android:id="@+id/soft_key_108"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawableBottom="@drawable/ic_txt_copy"
android:paddingBottom="@dimen/soft_key_drawable_bottom_padding"
android:textSize="@dimen/soft_key_drawable_title_size"
android:visibility="gone" />
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
android:id="@+id/soft_key_109"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawableBottom="@drawable/ic_txt_paste"
android:paddingBottom="@dimen/soft_key_drawable_bottom_padding"
android:textSize="@dimen/soft_key_drawable_title_size"
android:visibility="gone" />
</merge>

View file

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="HardcodedText,KeyboardInaccessibleWidget"
tools:showIn="@layout/main_small"
android:layout_width="match_parent"
android:layout_height="@dimen/soft_key_height"
android:baselineAligned="true"
android:orientation="horizontal">
<io.github.sspanak.tt9.ui.main.keys.SoftKeyCommandPalette
android:id="@+id/soft_key_command_palette"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:focusable="false"
android:text="🛠"
android:textSize="@dimen/soft_key_icon_size" />
<View
android:id="@+id/main_separator_left"
style="@style/hSeparator"
android:background="@drawable/button_separator_dark" />
<io.github.sspanak.tt9.ui.main.keys.SoftOkKey
android:id="@+id/soft_key_ok"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="5"
android:focusable="false"
android:text="@android:string/ok" />
<View
android:id="@+id/main_separator_right"
style="@style/hSeparator"
android:background="@drawable/button_separator_dark" />
<io.github.sspanak.tt9.ui.main.keys.SoftBackspaceKey
android:id="@+id/soft_key_backspace"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:focusable="false"
android:text="⌫"
android:textSize="@dimen/soft_key_icon_size" />
</LinearLayout>

View file

@ -0,0 +1,138 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="@layout/main_small"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/text_editing_keys_small"
android:layout_width="match_parent"
android:layout_height="@dimen/numpad_key_height">
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
style="@android:style/Widget.Holo.Button.Borderless"
android:id="@+id/soft_key_101"
android:drawableBottom="@drawable/ic_dpad_left"
android:paddingBottom="@dimen/soft_key_drawable_bottom_padding"
android:textSize="@dimen/soft_key_drawable_title_size"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<View
android:id="@+id/separator_10_1"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
style="@android:style/Widget.Holo.Button.Borderless"
android:id="@+id/soft_key_102"
android:drawableBottom="@drawable/ic_txt_select_none"
android:paddingBottom="@dimen/soft_key_drawable_bottom_padding"
android:textSize="@dimen/soft_key_drawable_title_size"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<View
android:id="@+id/separator_10_2"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
style="@android:style/Widget.Holo.Button.Borderless"
android:id="@+id/soft_key_103"
android:drawableBottom="@drawable/ic_dpad_right"
android:paddingBottom="@dimen/soft_key_drawable_bottom_padding"
android:textSize="@dimen/soft_key_drawable_title_size"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<View
android:id="@+id/separator_10_3"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
style="@android:style/Widget.Holo.Button.Borderless"
android:id="@+id/soft_key_104"
android:drawableBottom="@drawable/ic_txt_word_back"
android:paddingBottom="@dimen/soft_key_drawable_bottom_padding"
android:textSize="@dimen/soft_key_drawable_title_size"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<View
android:id="@+id/separator_10_4"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
style="@android:style/Widget.Holo.Button.Borderless"
android:id="@+id/soft_key_105"
android:drawableBottom="@drawable/ic_txt_select_all"
android:paddingBottom="@dimen/soft_key_drawable_bottom_padding"
android:textSize="@dimen/soft_key_drawable_title_size"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<View
android:id="@+id/separator_10_5"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
style="@android:style/Widget.Holo.Button.Borderless"
android:id="@+id/soft_key_106"
android:drawableBottom="@drawable/ic_txt_word_forward"
android:paddingBottom="@dimen/soft_key_drawable_bottom_padding"
android:textSize="@dimen/soft_key_drawable_title_size"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<View
android:id="@+id/separator_10_6"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
style="@android:style/Widget.Holo.Button.Borderless"
android:id="@+id/soft_key_107"
android:drawableBottom="@drawable/ic_txt_cut"
android:paddingBottom="@dimen/soft_key_drawable_bottom_padding"
android:layout_width="0dp"
android:textSize="@dimen/soft_key_drawable_title_size"
android:layout_height="match_parent"
android:layout_weight="1" />
<View
android:id="@+id/separator_10_7"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
style="@android:style/Widget.Holo.Button.Borderless"
android:id="@+id/soft_key_108"
android:drawableBottom="@drawable/ic_txt_copy"
android:paddingBottom="@dimen/soft_key_drawable_bottom_padding"
android:layout_width="0dp"
android:textSize="@dimen/soft_key_drawable_title_size"
android:layout_height="match_parent"
android:layout_weight="1" />
<View
android:id="@+id/separator_10_8"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
style="@android:style/Widget.Holo.Button.Borderless"
android:id="@+id/soft_key_109"
android:drawableBottom="@drawable/ic_txt_paste"
android:paddingBottom="@dimen/soft_key_drawable_bottom_padding"
android:layout_width="0dp"
android:textSize="@dimen/soft_key_drawable_title_size"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>

View file

@ -6,6 +6,8 @@
<dimen name="soft_key_height">44dp</dimen>
<dimen name="soft_key_icon_size">24sp</dimen>
<dimen name="soft_key_drawable_bottom_padding">6dp</dimen>
<dimen name="soft_key_drawable_title_size">12sp</dimen>
<!-- Large font size -->
<dimen name="pref_large_category_padding_top">30dp</dimen>

View file

@ -179,6 +179,7 @@
<string name="virtual_key_del" translatable="false">Del</string>
<string name="virtual_key_input_mode" translatable="false">Mode</string>
<string name="virtual_key_settings" translatable="false">Cfg</string>
<string name="virtual_key_text_editing" translatable="false">Copy</string>
<string name="voice_input_listening">Speak</string>
<string name="voice_input_stopping">Turning off the microphone…</string>