UI resize
This commit is contained in:
parent
2bfabd2ec8
commit
867b3be578
31 changed files with 602 additions and 59 deletions
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:tools="http://schemas.android.com/tools"
|
||||
android:versionCode="573"
|
||||
android:versionName="34.0"
|
||||
android:versionCode="580"
|
||||
android:versionName="34.7"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> <!-- allows displaying notifications on Android >= 13 -->
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package io.github.sspanak.tt9.ime;
|
||||
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
|
||||
|
|
@ -24,7 +23,7 @@ abstract public class AbstractHandler extends InputMethodService {
|
|||
abstract protected void setInputField(InputConnection inputConnection, EditorInfo inputField);
|
||||
|
||||
// UI
|
||||
abstract protected void createSuggestionBar(View mainView);
|
||||
abstract protected void createSuggestionBar();
|
||||
abstract protected void resetStatus();
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import io.github.sspanak.tt9.ime.modes.ModeABC;
|
|||
import io.github.sspanak.tt9.ime.voice.VoiceInputOps;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||
import io.github.sspanak.tt9.ui.main.ResizableMainView;
|
||||
|
||||
abstract public class MainViewHandler extends HotkeyHandler {
|
||||
/**** Informational methods for the on-screen keyboard ****/
|
||||
|
|
@ -46,6 +47,10 @@ abstract public class MainViewHandler extends HotkeyHandler {
|
|||
return mLanguage;
|
||||
}
|
||||
|
||||
public ResizableMainView getMainView() {
|
||||
return mainView;
|
||||
}
|
||||
|
||||
public SettingsStore getSettings() {
|
||||
return settings;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package io.github.sspanak.tt9.ime;
|
||||
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
|
||||
|
|
@ -42,8 +41,8 @@ public abstract class TypingHandler extends KeyPadHandler {
|
|||
protected Language mLanguage;
|
||||
|
||||
|
||||
protected void createSuggestionBar(View mainView) {
|
||||
suggestionOps = new SuggestionOps(settings, mainView, this::onAcceptSuggestionsDelayed, this::onOK);
|
||||
protected void createSuggestionBar() {
|
||||
suggestionOps = new SuggestionOps(settings, mainView, textField, this::onAcceptSuggestionsDelayed, this::onOK);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,19 +7,19 @@ import io.github.sspanak.tt9.R;
|
|||
import io.github.sspanak.tt9.hacks.DeviceInfo;
|
||||
import io.github.sspanak.tt9.ime.modes.InputMode;
|
||||
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||
import io.github.sspanak.tt9.ui.main.MainView;
|
||||
import io.github.sspanak.tt9.ui.main.ResizableMainView;
|
||||
import io.github.sspanak.tt9.ui.tray.StatusBar;
|
||||
|
||||
abstract class UiHandler extends AbstractHandler {
|
||||
protected SettingsStore settings;
|
||||
protected MainView mainView = null;
|
||||
protected ResizableMainView mainView = null;
|
||||
protected StatusBar statusBar = null;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onInit() {
|
||||
if (mainView == null) {
|
||||
mainView = new MainView(getFinalContext());
|
||||
mainView = new ResizableMainView(getFinalContext());
|
||||
initTray();
|
||||
}
|
||||
}
|
||||
|
|
@ -27,12 +27,12 @@ abstract class UiHandler extends AbstractHandler {
|
|||
|
||||
protected void initTray() {
|
||||
setInputView(mainView.getView());
|
||||
createSuggestionBar(mainView.getView());
|
||||
createSuggestionBar();
|
||||
statusBar = new StatusBar(mainView.getView());
|
||||
}
|
||||
|
||||
|
||||
protected void initUi() {
|
||||
public void initUi() {
|
||||
if (mainView.createInputView()) {
|
||||
initTray();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ package io.github.sspanak.tt9.ime.helpers;
|
|||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||
import io.github.sspanak.tt9.ui.main.ResizableMainView;
|
||||
import io.github.sspanak.tt9.ui.tray.SuggestionsBar;
|
||||
import io.github.sspanak.tt9.util.ConsumerCompat;
|
||||
|
||||
|
|
@ -19,12 +19,12 @@ public class SuggestionOps {
|
|||
@NonNull private TextField textField;
|
||||
|
||||
|
||||
public SuggestionOps(@NonNull SettingsStore settings, View mainView, @NonNull ConsumerCompat<String> onDelayedAccept, @NonNull Runnable onSuggestionClick) {
|
||||
public SuggestionOps(@NonNull SettingsStore settings, @NonNull ResizableMainView mainView, @NonNull TextField textField, @NonNull ConsumerCompat<String> onDelayedAccept, @NonNull Runnable onSuggestionClick) {
|
||||
delayedAcceptHandler = new Handler(Looper.getMainLooper());
|
||||
this.onDelayedAccept = onDelayedAccept;
|
||||
|
||||
suggestionBar = new SuggestionsBar(settings, mainView, onSuggestionClick);
|
||||
textField = new TextField(null, null);
|
||||
this.textField = textField;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import java.util.LinkedHashMap;
|
|||
import io.github.sspanak.tt9.util.Logger;
|
||||
|
||||
abstract public class ItemDropDown {
|
||||
private final DropDownPreference item;
|
||||
protected final DropDownPreference item;
|
||||
private LinkedHashMap<String, String> values;
|
||||
|
||||
public ItemDropDown(DropDownPreference item) {
|
||||
|
|
|
|||
|
|
@ -26,10 +26,18 @@ public class AppearanceScreen extends BaseScreenFragment {
|
|||
(new ItemStatusIcon(findPreference(ItemStatusIcon.NAME), activity.getSettings())).populate();
|
||||
ItemHapticFeedback hapticFeedback = (new ItemHapticFeedback(findPreference(ItemHapticFeedback.NAME), activity.getSettings())).populate();
|
||||
|
||||
ItemNumpadKeyHeight numpadKeyHeight = new ItemNumpadKeyHeight(findPreference(ItemNumpadKeyHeight.NAME), activity.getSettings());
|
||||
ItemDropDown[] items = {
|
||||
new ItemSelectTheme(findPreference(ItemSelectTheme.NAME), activity),
|
||||
new ItemSelectLayoutType(findPreference(ItemSelectLayoutType.NAME), activity, hapticFeedback::populate),
|
||||
new ItemSelectSettingsFontSize(findPreference(ItemSelectSettingsFontSize.NAME), this)
|
||||
new ItemSelectLayoutType(
|
||||
findPreference(ItemSelectLayoutType.NAME),
|
||||
activity,
|
||||
(layout) -> {
|
||||
hapticFeedback.onLayoutChange(layout);
|
||||
numpadKeyHeight.onLayoutChange(layout);
|
||||
}),
|
||||
new ItemSelectSettingsFontSize(findPreference(ItemSelectSettingsFontSize.NAME), this),
|
||||
numpadKeyHeight
|
||||
};
|
||||
|
||||
for (ItemDropDown item : items) {
|
||||
|
|
|
|||
|
|
@ -22,16 +22,14 @@ class ItemHapticFeedback extends ItemClickable {
|
|||
}
|
||||
|
||||
ItemHapticFeedback populate() {
|
||||
return populate(settings.getMainViewLayout());
|
||||
onLayoutChange(settings.getMainViewLayout());
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
ItemHapticFeedback populate(int mainViewLayout) {
|
||||
void onLayoutChange(int mainViewLayout) {
|
||||
if (item != null) {
|
||||
item.setEnabled(mainViewLayout == SettingsStore.LAYOUT_NUMPAD || mainViewLayout == SettingsStore.LAYOUT_SMALL);
|
||||
((SwitchPreferenceCompat) item).setChecked(settings.getHapticFeedback());
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
package io.github.sspanak.tt9.preferences.screens.appearance;
|
||||
|
||||
import androidx.preference.DropDownPreference;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
import io.github.sspanak.tt9.preferences.items.ItemDropDown;
|
||||
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||
|
||||
public class ItemNumpadKeyHeight extends ItemDropDown {
|
||||
public static final String NAME = "pref_numpad_key_height";
|
||||
|
||||
private final SettingsStore settings;
|
||||
|
||||
public ItemNumpadKeyHeight(DropDownPreference item, SettingsStore settings) {
|
||||
super(item);
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemDropDown populate() {
|
||||
int baseSize = settings.getNumpadKeyDefaultHeight();
|
||||
|
||||
LinkedHashMap<Integer, String> options = new LinkedHashMap<>();
|
||||
options.put((int) Math.round(baseSize * 0.7), "70 %");
|
||||
options.put((int) Math.round(baseSize * 0.75), "75 %");
|
||||
options.put((int) Math.round(baseSize * 0.8), "80 %");
|
||||
options.put((int) Math.round(baseSize * 0.85), "85 %");
|
||||
options.put((int) Math.round(baseSize * 0.9), "90 %");
|
||||
options.put((int) Math.round(baseSize * 0.95), "95 %");
|
||||
options.put(baseSize, "100 %");
|
||||
options.put((int) Math.round(baseSize * 1.1), "110 %");
|
||||
options.put((int) Math.round(baseSize * 1.2), "120 %");
|
||||
options.put((int) Math.round(baseSize * 1.33), "133 %");
|
||||
|
||||
super.populateIntegers(options);
|
||||
super.setValue(settings.getNumpadKeyHeight() + "");
|
||||
onLayoutChange(settings.getMainViewLayout());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
void onLayoutChange(int mainViewLayout) {
|
||||
if (item != null) {
|
||||
item.setEnabled(mainViewLayout == SettingsStore.LAYOUT_NUMPAD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,9 @@ public class SettingsStore extends SettingsUI {
|
|||
public final static int DICTIONARY_DOWNLOAD_READ_TIMEOUT = 10000; // ms
|
||||
public final static int DICTIONARY_IMPORT_BATCH_SIZE = 5000; // words
|
||||
public final static int DICTIONARY_IMPORT_PROGRESS_UPDATE_TIME = 250; // ms
|
||||
public final static int RESIZE_THROTTLING_TIME = 60; // ms
|
||||
public final static byte SLOW_QUERY_TIME = 50; // ms
|
||||
public final static int SOFT_KEY_DOUBLE_CLICK_DELAY = 500; // ms
|
||||
public final static int SOFT_KEY_REPEAT_DELAY = 40; // ms
|
||||
public final static int SOFT_KEY_TITLE_SIZE = 18; // sp
|
||||
public final static float SOFT_KEY_COMPLEX_LABEL_TITLE_RELATIVE_SIZE = 0.55f;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@ import android.content.res.Configuration;
|
|||
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.hacks.DeviceInfo;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
|
||||
public class SettingsUI extends SettingsTyping {
|
||||
public final static int FONT_SIZE_DEFAULT = 0;
|
||||
|
|
@ -36,6 +38,14 @@ public class SettingsUI extends SettingsTyping {
|
|||
return prefs.getBoolean("pref_haptic_feedback", true);
|
||||
}
|
||||
|
||||
public int getNumpadKeyDefaultHeight() {
|
||||
return context.getResources().getDimensionPixelSize(R.dimen.numpad_key_height);
|
||||
}
|
||||
|
||||
public int getNumpadKeyHeight() {
|
||||
return getStringifiedInt("pref_numpad_key_height", getNumpadKeyDefaultHeight());
|
||||
}
|
||||
|
||||
public int getSettingsFontSize() {
|
||||
int defaultSize = DeviceInfo.isQinF21() || DeviceInfo.isLgX100S() ? FONT_SIZE_LARGE : FONT_SIZE_DEFAULT;
|
||||
return getStringifiedInt("pref_font_size", defaultSize);
|
||||
|
|
@ -45,6 +55,16 @@ public class SettingsUI extends SettingsTyping {
|
|||
return getStringifiedInt("pref_theme", AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
|
||||
}
|
||||
|
||||
public void setMainViewLayout(int layout) {
|
||||
if (layout != LAYOUT_STEALTH && layout != LAYOUT_TRAY && layout != LAYOUT_SMALL && layout != LAYOUT_NUMPAD) {
|
||||
Logger.w(getClass().getSimpleName(), "Ignoring invalid main view layout: " + layout);
|
||||
return;
|
||||
}
|
||||
|
||||
prefsEditor.putString("pref_layout_type", Integer.toString(layout));
|
||||
prefsEditor.apply();
|
||||
}
|
||||
|
||||
public int getMainViewLayout() {
|
||||
int defaultLayout = LAYOUT_SMALL;
|
||||
if (DeviceInfo.noTouchScreen(context)) {
|
||||
|
|
|
|||
|
|
@ -77,6 +77,12 @@ abstract class BaseMainLayout {
|
|||
}
|
||||
|
||||
|
||||
int getHeight() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void resetHeight() {}
|
||||
|
||||
/**
|
||||
* render
|
||||
* Do all the necessary stuff to display the View.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package io.github.sspanak.tt9.ui.main;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
|
|
@ -12,8 +13,12 @@ import java.util.Arrays;
|
|||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.ime.TraditionalT9;
|
||||
import io.github.sspanak.tt9.ui.main.keys.SoftKey;
|
||||
import io.github.sspanak.tt9.ui.main.keys.SoftKeySettings;
|
||||
|
||||
class MainLayoutNumpad extends BaseMainLayout {
|
||||
private int height;
|
||||
|
||||
|
||||
MainLayoutNumpad(TraditionalT9 tt9) {
|
||||
super(tt9, R.layout.main_numpad);
|
||||
}
|
||||
|
|
@ -34,6 +39,7 @@ class MainLayoutNumpad extends BaseMainLayout {
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
void setDarkTheme(boolean dark) {
|
||||
if (view == null) {
|
||||
|
|
@ -57,15 +63,66 @@ class MainLayoutNumpad extends BaseMainLayout {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void setKeyHeight(int height) {
|
||||
if (view == null || height <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ViewGroup table = view.findViewById(R.id.main_soft_keys);
|
||||
int tableRowsCount = table.getChildCount();
|
||||
|
||||
for (int rowId = 0; rowId < tableRowsCount; rowId++) {
|
||||
View row = table.getChildAt(rowId);
|
||||
ViewGroup.LayoutParams layout = row.getLayoutParams();
|
||||
if (layout != null) {
|
||||
layout.height = height;
|
||||
row.setLayoutParams(layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int getHeight() {
|
||||
if (height <= 0) {
|
||||
Resources resources = tt9.getResources();
|
||||
height = tt9.getSettings().getNumpadKeyHeight() * 4
|
||||
+ resources.getDimensionPixelSize(R.dimen.numpad_candidate_height)
|
||||
+ resources.getDimensionPixelSize(R.dimen.numpad_padding_bottom) * 4;
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
|
||||
void resetHeight() {
|
||||
height = 0;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
void render() {
|
||||
getView();
|
||||
setKeyHeight(tt9 != null ? tt9.getSettings().getNumpadKeyHeight() : -1);
|
||||
enableClickHandlers();
|
||||
for (SoftKey key : getKeys()) {
|
||||
key.render();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void enableClickHandlers() {
|
||||
super.enableClickHandlers();
|
||||
|
||||
for (SoftKey key : getKeys()) {
|
||||
if (key instanceof SoftKeySettings) {
|
||||
((SoftKeySettings) key).setMainView(tt9.getMainView());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected ArrayList<SoftKey> getKeys() {
|
||||
|
|
@ -89,6 +146,7 @@ class MainLayoutNumpad extends BaseMainLayout {
|
|||
return keys;
|
||||
}
|
||||
|
||||
|
||||
protected ArrayList<View> getSeparators() {
|
||||
// it's fine... it's shorter, faster and easier to read than searching with 3 nested loops
|
||||
return new ArrayList<>(Arrays.asList(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package io.github.sspanak.tt9.ui.main;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
|
|
@ -10,12 +11,25 @@ import java.util.ArrayList;
|
|||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.ime.TraditionalT9;
|
||||
import io.github.sspanak.tt9.ui.main.keys.SoftKey;
|
||||
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);
|
||||
}
|
||||
return height;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setSoftKeysVisibility() {
|
||||
if (view != null) {
|
||||
|
|
@ -23,6 +37,17 @@ class MainLayoutSmall extends MainLayoutTray {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void enableClickHandlers() {
|
||||
super.enableClickHandlers();
|
||||
|
||||
for (SoftKey key : getKeys()) {
|
||||
if (key instanceof SoftKeyCommandPalette) {
|
||||
((SoftKeyCommandPalette) key).setMainView(tt9.getMainView());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected ArrayList<SoftKey> getKeys() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package io.github.sspanak.tt9.ui.main;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
|
|
@ -15,10 +16,20 @@ import io.github.sspanak.tt9.ime.TraditionalT9;
|
|||
import io.github.sspanak.tt9.ui.main.keys.SoftKey;
|
||||
|
||||
class MainLayoutTray extends BaseMainLayout {
|
||||
private int height;
|
||||
|
||||
MainLayoutTray(TraditionalT9 tt9) {
|
||||
super(tt9, R.layout.main_small);
|
||||
}
|
||||
|
||||
int getHeight() {
|
||||
if (height <= 0) {
|
||||
Resources resources = tt9.getResources();
|
||||
height = resources.getDimensionPixelSize(R.dimen.candidate_height);
|
||||
}
|
||||
return height;
|
||||
}
|
||||
|
||||
protected void setSoftKeysVisibility() {
|
||||
if (view != null) {
|
||||
view.findViewById(R.id.main_soft_keys).setVisibility(LinearLayout.GONE);
|
||||
|
|
|
|||
|
|
@ -7,10 +7,11 @@ import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
|||
import io.github.sspanak.tt9.util.Logger;
|
||||
|
||||
public class MainView {
|
||||
private final TraditionalT9 tt9;
|
||||
private BaseMainLayout main;
|
||||
protected final TraditionalT9 tt9;
|
||||
protected BaseMainLayout main;
|
||||
|
||||
public MainView(TraditionalT9 tt9) {
|
||||
|
||||
protected MainView(TraditionalT9 tt9) {
|
||||
this.tt9 = tt9;
|
||||
|
||||
forceCreateInputView();
|
||||
|
|
@ -32,6 +33,7 @@ public class MainView {
|
|||
}
|
||||
|
||||
main.render();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,200 @@
|
|||
package io.github.sspanak.tt9.ui.main;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import io.github.sspanak.tt9.ime.TraditionalT9;
|
||||
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||
|
||||
public class ResizableMainView extends MainView implements View.OnAttachStateChangeListener {
|
||||
private int height;
|
||||
private float resizeStartY;
|
||||
private long lastResizeTime;
|
||||
|
||||
private int heightNumpad;
|
||||
private int heightSmall;
|
||||
private int heightTray;
|
||||
|
||||
|
||||
public ResizableMainView(TraditionalT9 tt9) {
|
||||
super(tt9);
|
||||
resetHeight();
|
||||
}
|
||||
|
||||
|
||||
private void calculateSnapHeights() {
|
||||
heightNumpad = new MainLayoutNumpad(tt9).getHeight();
|
||||
heightSmall = new MainLayoutSmall(tt9).getHeight();
|
||||
heightTray = new MainLayoutTray(tt9).getHeight();
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
main.getView().removeOnAttachStateChangeListener(this);
|
||||
main.getView().addOnAttachStateChangeListener(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private void onCreateAdjustHeight() {
|
||||
if (tt9.getSettings().isMainLayoutNumpad() && height > heightSmall && height <= heightNumpad) {
|
||||
setHeight(height, heightSmall, heightNumpad);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void onResizeStart(float startY) {
|
||||
resizeStartY = startY;
|
||||
}
|
||||
|
||||
|
||||
public void onResize(float currentY) {
|
||||
int resizeDelta = (int) (resizeStartY - currentY);
|
||||
resizeStartY = currentY;
|
||||
|
||||
if (resizeDelta < 0) {
|
||||
shrink(resizeDelta);
|
||||
} else if (resizeDelta > 0) {
|
||||
expand(resizeDelta);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void onSnap() {
|
||||
SettingsStore settings = tt9.getSettings();
|
||||
|
||||
if (settings.isMainLayoutTray()) {
|
||||
expand(1);
|
||||
} else if (settings.isMainLayoutSmall()) {
|
||||
expand(heightNumpad);
|
||||
} else {
|
||||
shrink(-heightNumpad);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void onResizeThrottled(float currentY) {
|
||||
long now = System.currentTimeMillis();
|
||||
if (now - lastResizeTime > SettingsStore.RESIZE_THROTTLING_TIME) {
|
||||
lastResizeTime = now;
|
||||
onResize(currentY);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void expand(int delta) {
|
||||
SettingsStore settings = tt9.getSettings();
|
||||
|
||||
if (settings.isMainLayoutTray()) {
|
||||
settings.setMainViewLayout(SettingsStore.LAYOUT_SMALL);
|
||||
height = heightSmall;
|
||||
tt9.onCreateInputView();
|
||||
vibrate();
|
||||
} else if (settings.isMainLayoutSmall()) {
|
||||
settings.setMainViewLayout(SettingsStore.LAYOUT_NUMPAD);
|
||||
height = (int) Math.max(Math.max(heightNumpad * 0.6, heightSmall * 1.1), height + delta);
|
||||
tt9.onCreateInputView();
|
||||
vibrate();
|
||||
} else {
|
||||
changeHeight(delta, heightSmall, heightNumpad);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void shrink(int delta) {
|
||||
SettingsStore settings = tt9.getSettings();
|
||||
|
||||
if (settings.isMainLayoutTray()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (settings.isMainLayoutSmall()) {
|
||||
settings.setMainViewLayout(SettingsStore.LAYOUT_TRAY);
|
||||
height = heightTray;
|
||||
tt9.onCreateInputView();
|
||||
vibrate();
|
||||
} else if (!changeHeight(delta, heightSmall, heightNumpad)) {
|
||||
settings.setMainViewLayout(SettingsStore.LAYOUT_SMALL);
|
||||
height = heightSmall;
|
||||
tt9.onCreateInputView();
|
||||
vibrate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean changeHeight(int delta, int minHeight, int maxHeight) {
|
||||
if (main == null || main.getView() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return setHeight(main.getView().getMeasuredHeight() + delta, minHeight, maxHeight);
|
||||
}
|
||||
|
||||
|
||||
private boolean setHeight(int height, int minHeight, int maxHeight) {
|
||||
if (main == null || main.getView() == null || height < minHeight) {
|
||||
return false;
|
||||
}
|
||||
|
||||
height = Math.min(height, maxHeight);
|
||||
|
||||
ViewGroup.LayoutParams params = main.getView().getLayoutParams();
|
||||
if (params == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
params.height = height;
|
||||
main.getView().setLayoutParams(params);
|
||||
this.height = height;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private void resetHeight() {
|
||||
if (main != null) {
|
||||
main.resetHeight();
|
||||
}
|
||||
|
||||
calculateSnapHeights();
|
||||
calculateInitialHeight();
|
||||
setHeight(height, heightSmall, heightNumpad);
|
||||
}
|
||||
|
||||
|
||||
private void vibrate() {
|
||||
if (tt9.getSettings().getHapticFeedback() && main != null && main.getView() != null) {
|
||||
main.getView().performHapticFeedback(Vibration.getPressVibration(null));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override public void onViewAttachedToWindow(@NonNull View v) { onCreateAdjustHeight(); }
|
||||
@Override public void onViewDetachedFromWindow(@NonNull View v) {}
|
||||
}
|
||||
|
|
@ -1,18 +1,21 @@
|
|||
package io.github.sspanak.tt9.ui.main.keys;
|
||||
package io.github.sspanak.tt9.ui.main;
|
||||
|
||||
import android.os.Build;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
|
||||
class Vibration {
|
||||
static int getNoVibration() {
|
||||
import io.github.sspanak.tt9.ui.main.keys.SoftKey;
|
||||
import io.github.sspanak.tt9.ui.main.keys.SoftNumberKey;
|
||||
|
||||
public class Vibration {
|
||||
public static int getNoVibration() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int getPressVibration(SoftKey key) {
|
||||
public static int getPressVibration(SoftKey key) {
|
||||
return key instanceof SoftNumberKey ? HapticFeedbackConstants.KEYBOARD_TAP : HapticFeedbackConstants.VIRTUAL_KEY;
|
||||
}
|
||||
|
||||
static int getHoldVibration() {
|
||||
public static int getHoldVibration() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
return HapticFeedbackConstants.CONFIRM;
|
||||
} else {
|
||||
|
|
@ -20,8 +23,7 @@ class Vibration {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static int getReleaseVibration() {
|
||||
public static int getReleaseVibration() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
||||
return HapticFeedbackConstants.KEYBOARD_RELEASE;
|
||||
} else {
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
package io.github.sspanak.tt9.ui.main.keys;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.ui.main.ResizableMainView;
|
||||
|
||||
public class ResizeHandle implements View.OnTouchListener {
|
||||
@NonNull private final Runnable onClick;
|
||||
private ResizableMainView mainView;
|
||||
|
||||
private final float RESIZE_THRESHOLD;
|
||||
private boolean dragging;
|
||||
private float startY;
|
||||
|
||||
|
||||
ResizeHandle(@NonNull Context context, @NonNull Runnable onClick) {
|
||||
RESIZE_THRESHOLD = context.getResources().getDimensionPixelSize(R.dimen.numpad_key_height) / 4.0f;
|
||||
this.onClick = onClick;
|
||||
}
|
||||
|
||||
public void setMainView(ResizableMainView mainView) {
|
||||
this.mainView = mainView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
switch(event.getAction() & MotionEvent.ACTION_MASK) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
handlePress(event);
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
handleDrag(event);
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
handleRelease(event);
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void handlePress(MotionEvent event) {
|
||||
startY = event.getRawY();
|
||||
}
|
||||
|
||||
private void handleDrag(MotionEvent event) {
|
||||
if (mainView == null) {
|
||||
dragging = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dragging && Math.abs(event.getRawY() - startY) >= RESIZE_THRESHOLD) {
|
||||
mainView.onResizeStart(event.getRawY());
|
||||
dragging = true;
|
||||
} else if (dragging) {
|
||||
mainView.onResizeThrottled(event.getRawY());
|
||||
}
|
||||
}
|
||||
|
||||
private void handleRelease(MotionEvent event) {
|
||||
if (mainView != null && dragging) {
|
||||
mainView.onResize(event.getRawY());
|
||||
dragging = false;
|
||||
} else {
|
||||
onClick.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import android.view.KeyEvent;
|
|||
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.languages.LanguageKind;
|
||||
import io.github.sspanak.tt9.ui.main.Vibration;
|
||||
|
||||
public class SoftBackspaceKey extends SoftKey {
|
||||
private boolean hold;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.content.Context;
|
|||
import android.util.AttributeSet;
|
||||
|
||||
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||
import io.github.sspanak.tt9.ui.main.Vibration;
|
||||
|
||||
public class SoftFilterKey extends SoftKey {
|
||||
public SoftFilterKey(Context context) { super(context); setFontSize(); }
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.content.Context;
|
|||
import android.util.AttributeSet;
|
||||
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.ui.main.Vibration;
|
||||
|
||||
public class SoftInputModeKey extends SoftKey {
|
||||
public SoftInputModeKey(Context context) {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import androidx.core.content.ContextCompat;
|
|||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.ime.TraditionalT9;
|
||||
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||
import io.github.sspanak.tt9.ui.main.Vibration;
|
||||
import io.github.sspanak.tt9.util.Characters;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
|
||||
|
|
@ -38,16 +39,22 @@ public class SoftKey extends androidx.appcompat.widget.AppCompatButton implement
|
|||
public SoftKey(Context context) {
|
||||
super(context);
|
||||
setHapticFeedbackEnabled(false);
|
||||
setOnTouchListener(this);
|
||||
setOnLongClickListener(this);
|
||||
}
|
||||
|
||||
public SoftKey(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
setHapticFeedbackEnabled(false);
|
||||
setOnTouchListener(this);
|
||||
setOnLongClickListener(this);
|
||||
}
|
||||
|
||||
public SoftKey(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
setHapticFeedbackEnabled(false);
|
||||
setOnTouchListener(this);
|
||||
setOnLongClickListener(this);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -66,19 +73,6 @@ public class SoftKey extends androidx.appcompat.widget.AppCompatButton implement
|
|||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
View keyView = findViewById(getId());
|
||||
if (keyView != null) {
|
||||
keyView.setOnTouchListener(this);
|
||||
keyView.setOnLongClickListener(this);
|
||||
} else {
|
||||
Logger.e(LOG_TAG, "Failed settings touch listeners. Cannot find SoftKey with ID: " + getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View view, MotionEvent event) {
|
||||
super.onTouchEvent(event);
|
||||
|
|
@ -164,7 +158,6 @@ public class SoftKey extends androidx.appcompat.widget.AppCompatButton implement
|
|||
}
|
||||
|
||||
int keyId = getId();
|
||||
if (keyId == R.id.soft_key_command_palette) return tt9.onKeyCommandPalette(false);
|
||||
if (keyId == R.id.soft_key_voice_input) { tt9.toggleVoiceInput(); return true; }
|
||||
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.content.Context;
|
|||
import android.util.AttributeSet;
|
||||
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.ui.main.Vibration;
|
||||
|
||||
public class SoftKeyArrow extends SoftKey {
|
||||
private boolean hold;
|
||||
|
|
|
|||
|
|
@ -2,14 +2,35 @@ package io.github.sspanak.tt9.ui.main.keys;
|
|||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.ui.main.ResizableMainView;
|
||||
|
||||
public class SoftKeyCommandPalette extends SoftKey {
|
||||
private final ResizeHandle resizeHandle = new ResizeHandle(getContext(), this::showCommandPalette);
|
||||
|
||||
public SoftKeyCommandPalette(Context context) { super(context); }
|
||||
public SoftKeyCommandPalette(Context context, AttributeSet attrs) { super(context, attrs); }
|
||||
public SoftKeyCommandPalette(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); }
|
||||
|
||||
public void setMainView(ResizableMainView mainView) {
|
||||
resizeHandle.setMainView(mainView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View view, MotionEvent event) {
|
||||
resizeHandle.onTouch(view, event);
|
||||
return super.onTouch(view, event);
|
||||
}
|
||||
|
||||
protected void showCommandPalette() {
|
||||
if (validateTT9Handler()) {
|
||||
tt9.onKeyCommandPalette(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getNoEmojiTitle() {
|
||||
return R.string.virtual_key_command_palette;
|
||||
|
|
|
|||
|
|
@ -2,22 +2,44 @@ package io.github.sspanak.tt9.ui.main.keys;
|
|||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.ui.main.ResizableMainView;
|
||||
|
||||
public class SoftKeySettings extends SoftKey {
|
||||
public SoftKeySettings(Context context) { super(context); }
|
||||
public SoftKeySettings(Context context, AttributeSet attrs) { super(context, attrs); }
|
||||
public SoftKeySettings(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); }
|
||||
private final ResizeHandle resizeHandle = new ResizeHandle(getContext(), this::showSettings);
|
||||
|
||||
@Override
|
||||
protected boolean handleRelease() {
|
||||
if (validateTT9Handler()) {
|
||||
tt9.showSettings();
|
||||
return true;
|
||||
public SoftKeySettings(Context context) {
|
||||
super(context);
|
||||
setOnLongClickListener(null);
|
||||
}
|
||||
|
||||
return false;
|
||||
public SoftKeySettings(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
setOnLongClickListener(null);
|
||||
}
|
||||
|
||||
public SoftKeySettings(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
setOnLongClickListener(null);
|
||||
}
|
||||
|
||||
public void setMainView(ResizableMainView mainView) {
|
||||
resizeHandle.setMainView(mainView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View view, MotionEvent event) {
|
||||
resizeHandle.onTouch(view, event);
|
||||
return super.onTouch(view, event);
|
||||
}
|
||||
|
||||
protected void showSettings() {
|
||||
if (validateTT9Handler()) {
|
||||
tt9.showSettings();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import io.github.sspanak.tt9.ime.modes.InputMode;
|
|||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.languages.LanguageKind;
|
||||
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||
import io.github.sspanak.tt9.ui.main.Vibration;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
|
||||
public class SoftNumberKey extends SoftKey {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import android.content.Context;
|
|||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Handler;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
|
@ -19,12 +20,15 @@ import java.util.List;
|
|||
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||
import io.github.sspanak.tt9.ui.main.ResizableMainView;
|
||||
|
||||
public class SuggestionsBar {
|
||||
private double lastClickTime = 0;
|
||||
private final List<String> suggestions = new ArrayList<>();
|
||||
protected int selectedIndex = 0;
|
||||
private boolean isDarkThemeEnabled = false;
|
||||
|
||||
private final ResizableMainView mainView;
|
||||
private final Runnable onItemClick;
|
||||
private final RecyclerView mView;
|
||||
private final SettingsStore settings;
|
||||
|
|
@ -33,17 +37,23 @@ public class SuggestionsBar {
|
|||
private final Handler alternativeScrollingHandler = new Handler();
|
||||
|
||||
|
||||
public SuggestionsBar(@NonNull SettingsStore settings, @NonNull View mainView, @NonNull Runnable onItemClick) {
|
||||
public SuggestionsBar(@NonNull SettingsStore settings, @NonNull ResizableMainView mainView, @NonNull Runnable onItemClick) {
|
||||
this.onItemClick = onItemClick;
|
||||
this.settings = settings;
|
||||
|
||||
mView = mainView.findViewById(R.id.suggestions_bar);
|
||||
this.mainView = mainView;
|
||||
mView = mainView.getView() != null ? mainView.getView().findViewById(R.id.suggestions_bar) : null;
|
||||
if (mView != null) {
|
||||
mView.setLayoutManager(new LinearLayoutManager(mainView.getContext(), RecyclerView.HORIZONTAL, false));
|
||||
Context context = mainView.getView().getContext();
|
||||
|
||||
initDataAdapter(mainView.getContext());
|
||||
initSeparator(mainView.getContext());
|
||||
mView.setLayoutManager(new LinearLayoutManager(context, RecyclerView.HORIZONTAL, false));
|
||||
mView.setOnTouchListener(this::onTouch);
|
||||
|
||||
initDataAdapter(context);
|
||||
initSeparator(context);
|
||||
configureAnimation();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -251,4 +261,35 @@ public class SuggestionsBar {
|
|||
selectedIndex = position;
|
||||
onItemClick.run();
|
||||
}
|
||||
|
||||
|
||||
private boolean onTouch(View view, MotionEvent event) {
|
||||
if (!isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int action = event.getAction();
|
||||
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mainView.onResizeStart(event.getRawY());
|
||||
return true;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
mainView.onResizeThrottled(event.getRawY());
|
||||
return true;
|
||||
case MotionEvent.ACTION_UP:
|
||||
long now = System.currentTimeMillis();
|
||||
if (now - lastClickTime < SettingsStore.SOFT_KEY_DOUBLE_CLICK_DELAY) {
|
||||
mainView.onSnap();
|
||||
} else {
|
||||
mainView.onResize(event.getRawY());
|
||||
}
|
||||
|
||||
lastClickTime = now;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@
|
|||
<string name="pref_layout_small">Function keys</string>
|
||||
<string name="pref_layout_stealth">Invisible</string>
|
||||
<string name="pref_layout_tray">Suggestion list only</string>
|
||||
<string name="pref_numpad_key_height">Virtual Numpad Key Size</string>
|
||||
<string name="pref_font_size">Settings Font Size</string>
|
||||
<string name="pref_font_size_default">Default</string>
|
||||
<string name="pref_font_size_large">Large</string>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,10 @@
|
|||
app:title="@string/pref_haptic_feedback"
|
||||
app:summary="@string/pref_haptic_feedback_summary"/>
|
||||
|
||||
<DropDownPreference
|
||||
app:key="pref_numpad_key_height"
|
||||
app:title="@string/pref_numpad_key_height" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
app:key="pref_status_icon"
|
||||
app:title="@string/pref_status_icon"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue