From 98c1b8db82c0da8f49eb12d18c9001a57009eca5 Mon Sep 17 00:00:00 2001 From: Jules Aguillon Date: Sun, 27 Jul 2025 22:09:45 +0200 Subject: Candidates view The `CandidatesView` is implemented as a `LinearLayout` that is divided horizontally with up to 3 `TextView`. It might in the future contain buttons on the sides. The candidate view is nested into the input view rather than using Android's `setCandidatesView` and callbacks as the API is unreliable and complicated. The first suggestion goes in the middle to be more accessible. The second suggestion goes on the right to be more accessible to the right-handed, because it must go somewhere. --- srcs/juloo.keyboard2/CandidatesView.java | 104 ++++++++++++++++++++++++++++++ srcs/juloo.keyboard2/Config.java | 3 + srcs/juloo.keyboard2/KeyEventHandler.java | 6 ++ srcs/juloo.keyboard2/Keyboard2.java | 30 +++++++-- srcs/juloo.keyboard2/Keyboard2View.java | 2 - srcs/juloo.keyboard2/Logs.java | 2 + 6 files changed, 139 insertions(+), 8 deletions(-) create mode 100644 srcs/juloo.keyboard2/CandidatesView.java (limited to 'srcs') diff --git a/srcs/juloo.keyboard2/CandidatesView.java b/srcs/juloo.keyboard2/CandidatesView.java new file mode 100644 index 0000000..232ed23 --- /dev/null +++ b/srcs/juloo.keyboard2/CandidatesView.java @@ -0,0 +1,104 @@ +package juloo.keyboard2; + +import android.content.Context; +import android.text.InputType; +import android.util.AttributeSet; +import android.view.View; +import android.view.inputmethod.EditorInfo; +import android.widget.LinearLayout; +import android.widget.TextView; +import java.util.ArrayList; +import java.util.List; + +public class CandidatesView extends LinearLayout +{ + static final int NUM_CANDIDATES = 3; + + Config _config; + + /** Candidates currently visible. Entries can be [null] when there are less + than [NUM_CANDIDATES] suggestions. */ + String[] _items = new String[NUM_CANDIDATES]; + + /** Text views showing the candidates in [_items]. Text views visibility is + set to [GONE] when there are less than [NUM_CANDIDATES] suggestions. */ + TextView[] _item_views = new TextView[NUM_CANDIDATES]; + + public CandidatesView(Context context, AttributeSet attrs) + { + super(context, attrs); + _config = Config.globalConfig(); + } + + @Override + protected void onFinishInflate() + { + super.onFinishInflate(); + setup_item_view(0, R.id.candidates_middle); + setup_item_view(1, R.id.candidates_right); + setup_item_view(2, R.id.candidates_left); + } + + public void set_candidates(List suggestions) + { + int s_count = suggestions.size(); + for (int i = 0; i < _item_views.length; i++) + { + TextView v = _item_views[i]; + if (i < s_count) + { + String it = suggestions.get(i); + _items[i] = it; + v.setText(it); + v.setVisibility(View.VISIBLE); + } + else + { + _items[i] = null; + v.setVisibility(View.GONE); + } + } + } + + private void setup_item_view(final int item_index, int item_id) + { + TextView v = (TextView)findViewById(item_id); + v.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View _v) + { + String it = _items[item_index]; + if (it != null) + _config.handler.suggestion_entered(it); + } + }); + v.setVisibility(View.GONE); + _item_views[item_index] = v; + } + + public static boolean should_show(EditorInfo info) + { + int variation = info.inputType & InputType.TYPE_MASK_VARIATION; + int flags = info.inputType & InputType.TYPE_MASK_FLAGS; + switch (info.inputType & InputType.TYPE_MASK_CLASS) + { + case InputType.TYPE_CLASS_TEXT: + switch (variation) + { + case InputType.TYPE_TEXT_VARIATION_PASSWORD: + case InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD: + case InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD: + return false; + default: + if ((flags & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) + return false; // Editor requested that we don't show suggestions + return true; + } + case InputType.TYPE_CLASS_NUMBER: + // Beware of TYPE_NUMBER_VARIATION_PASSWORD + return false; + default: return false; + } + } +} diff --git a/srcs/juloo.keyboard2/Config.java b/srcs/juloo.keyboard2/Config.java index 64e2d87..775c206 100644 --- a/srcs/juloo.keyboard2/Config.java +++ b/srcs/juloo.keyboard2/Config.java @@ -75,6 +75,7 @@ public final class Config // Dynamically set /** Configuration options implied by the connected editor. */ public EditorConfig editor_config; + public boolean should_show_candidates_view; public boolean shouldOfferVoiceTyping; public ExtraKeys extra_keys_subtype; public Map extra_keys_param; @@ -101,6 +102,7 @@ public final class Config // from prefs refresh(res, foldableUnfolded); // initialized later + should_show_candidates_view = false; shouldOfferVoiceTyping = false; extra_keys_subtype = null; handler = h; @@ -291,6 +293,7 @@ public final class Config public void key_down(KeyValue value, boolean is_swipe); public void key_up(KeyValue value, Pointers.Modifiers mods); public void mods_changed(Pointers.Modifiers mods); + public void suggestion_entered(String text); } /** Config migrations. */ diff --git a/srcs/juloo.keyboard2/KeyEventHandler.java b/srcs/juloo.keyboard2/KeyEventHandler.java index fc3a641..145acbe 100644 --- a/srcs/juloo.keyboard2/KeyEventHandler.java +++ b/srcs/juloo.keyboard2/KeyEventHandler.java @@ -110,6 +110,12 @@ public final class KeyEventHandler update_meta_state(mods); } + @Override + public void suggestion_entered(String text) + { + // TODO + } + @Override public void paste_from_clipboard_pane(String content) { diff --git a/srcs/juloo.keyboard2/Keyboard2.java b/srcs/juloo.keyboard2/Keyboard2.java index 1efe0f5..c7d7e3d 100644 --- a/srcs/juloo.keyboard2/Keyboard2.java +++ b/srcs/juloo.keyboard2/Keyboard2.java @@ -29,7 +29,10 @@ import juloo.keyboard2.prefs.LayoutsPreference; public class Keyboard2 extends InputMethodService implements SharedPreferences.OnSharedPreferenceChangeListener { + /** The view containing the keyboard and candidates view. */ + private ViewGroup _container_view; private Keyboard2View _keyboardView; + private CandidatesView _candidates_view; private KeyEventHandler _keyeventhandler; /** If not 'null', the layout to use instead of [_config.current_layout]. */ private KeyboardData _currentSpecialLayout; @@ -115,9 +118,8 @@ public class Keyboard2 extends InputMethodService Config.initGlobalConfig(prefs, getResources(), _keyeventhandler, _foldStateTracker.isUnfolded()); prefs.registerOnSharedPreferenceChangeListener(this); _config = Config.globalConfig(); - _keyboardView = (Keyboard2View)inflate_view(R.layout.keyboard); - _keyboardView.reset(); Logs.set_debug_logs(getResources().getBoolean(R.bool.debug_logs)); + create_keyboard_view(); ClipboardHistoryService.on_startup(this, _keyeventhandler); _foldStateTracker.setChangedCallback(() -> { refresh_config(); }); } @@ -129,6 +131,13 @@ public class Keyboard2 extends InputMethodService _foldStateTracker.close(); } + private void create_keyboard_view() + { + _container_view = (ViewGroup)inflate_view(R.layout.keyboard); + _keyboardView = (Keyboard2View)_container_view.findViewById(R.id.keyboard_view); + _candidates_view = (CandidatesView)_container_view.findViewById(R.id.candidates_view); + } + private List getEnabledSubtypes(InputMethodManager imm) { String pkg = getPackageName(); @@ -198,6 +207,13 @@ public class Keyboard2 extends InputMethodService _localeTextLayout = default_layout; } + private void refresh_candidates_view(EditorInfo info) + { + boolean should_show = CandidatesView.should_show(info); + _config.should_show_candidates_view = should_show; + _candidates_view.setVisibility(should_show ? View.VISIBLE : View.GONE); + } + /** Might re-create the keyboard view. [_keyboardView.setKeyboard()] and [setInputView()] must be called soon after. */ private void refresh_config() @@ -208,11 +224,13 @@ public class Keyboard2 extends InputMethodService // Refreshing the theme config requires re-creating the views if (prev_theme != _config.theme) { - _keyboardView = (Keyboard2View)inflate_view(R.layout.keyboard); + create_keyboard_view(); _emojiPane = null; _clipboard_pane = null; - setInputView(_keyboardView); + setInputView(_container_view); } + // Set keyboard background opacity + _container_view.getBackground().setAlpha(_config.keyboardOpacity); _keyboardView.reset(); } @@ -234,10 +252,11 @@ public class Keyboard2 extends InputMethodService { _config.editor_config.refresh(info, getResources()); refresh_config(); + refresh_candidates_view(info); _currentSpecialLayout = refresh_special_layout(); _keyboardView.setKeyboard(current_layout()); _keyeventhandler.started(_config); - setInputView(_keyboardView); + setInputView(_container_view); Logs.debug_startup_input_view(info, _config); } @@ -252,7 +271,6 @@ public class Keyboard2 extends InputMethodService v.requestApplyInsets(); } - @Override public void updateFullscreenMode() { super.updateFullscreenMode(); diff --git a/srcs/juloo.keyboard2/Keyboard2View.java b/srcs/juloo.keyboard2/Keyboard2View.java index 58c689d..068ef67 100644 --- a/srcs/juloo.keyboard2/Keyboard2View.java +++ b/srcs/juloo.keyboard2/Keyboard2View.java @@ -344,8 +344,6 @@ public class Keyboard2View extends View @Override protected void onDraw(Canvas canvas) { - // Set keyboard background opacity - getBackground().setAlpha(_config.keyboardOpacity); float y = _tc.margin_top; for (KeyboardData.Row row : _keyboard.rows) { diff --git a/srcs/juloo.keyboard2/Logs.java b/srcs/juloo.keyboard2/Logs.java index 1bef51c..a956305 100644 --- a/srcs/juloo.keyboard2/Logs.java +++ b/srcs/juloo.keyboard2/Logs.java @@ -26,6 +26,8 @@ public final class Logs _debug_logs.println("swapEnterActionKey: " +conf.editor_config.swapEnterActionKey); _debug_logs.println("actionLabel: "+conf.editor_config.actionLabel); + _debug_logs.println("should_show_candidates_view: " + +conf.should_show_candidates_view); } public static void debug_config_migration(int from_version, int to_version) -- cgit v1.2.3