package juloo.keyboard2.suggestions; import android.content.Context; import android.os.Build.VERSION; import android.text.InputType; import android.util.AttributeSet; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; import android.widget.LinearLayout; import android.widget.TextView; import java.util.ArrayList; import java.util.List; import juloo.keyboard2.Config; import juloo.keyboard2.R; public class CandidatesView extends LinearLayout { static final int NUM_CANDIDATES = 4; /** Candidates currently visible. Entries can be [null] when there are less than [NUM_CANDIDATES] suggestions. - Entries at indexes [0] to [2] are word suggestions. - Entry at index [3] is the emoji suggestion. */ 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]; /** Optional view showing a message to the user. Visible when no candidates are shown. Might be [null]. */ View _status_no_dict = null; // Dictionary not installed public CandidatesView(Context context, AttributeSet attrs) { super(context, attrs); } @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); setup_item_view(3, R.id.candidates_emoji); } public void set_candidates(Suggestions s) { int s_count = s.count; for (int i = 0; i < Suggestions.MAX_COUNT; i++) _items[i] = (i < s_count) ? s.suggestions[i] : null; _items[3] = s.emoji_suggestion; // Hide the status message when showing candidates. if (s_count != 0 && _status_no_dict != null) _status_no_dict.setVisibility(View.GONE); for (int i = 0; i < _item_views.length; i++) { TextView v = _item_views[i]; if (_items[i] != null) { v.setText(_items[i]); v.setVisibility(View.VISIBLE); } else { v.setVisibility(View.GONE); } } } public void clear_candidates() { for (int i = 0; i < _item_views.length; i++) { _items[i] = null; _item_views[i].setVisibility(View.GONE); } } public void refresh_config(Config config) { clear_candidates(); // The status message indicates whether the dictionaries should be // installed. _status_no_dict = inflate_and_show(_status_no_dict, (config.current_dictionary == null), R.layout.candidates_status_no_dict); set_sizes(config); } /** Set the height of the suggestion row and the text size. */ void set_sizes(Config config) { // Make the candidates view about as high as a keyboard row. int height = (int)(config.keyboard_rows_height_pixels * (1 - config.key_vertical_margin)); // Match the size of labels on the keyboard, increased by 15%. float text_size = height * config.characterSize * config.labelTextSize * 1.15f; for (int i = 0; i < NUM_CANDIDATES; i++) { TextView v = _item_views[i]; // Set view height ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams)v.getLayoutParams(); p.height = height; v.setLayoutParams(p); // Set text size and enable auto size if supported. if (VERSION.SDK_INT < 26) v.setTextSize(TypedValue.COMPLEX_UNIT_PX, text_size); else v.setAutoSizeTextTypeUniformWithConfiguration( (int)(text_size / 2.), (int)text_size, 1, TypedValue.COMPLEX_UNIT_PX); } } /** Show or hide a status view and inflate it if needed. */ View inflate_and_show(View v, boolean show, int layout_id) { if (!show) { if (v != null) v.setVisibility(View.GONE); } else { if (v == null) { v = View.inflate(getContext(), layout_id, null); addView(v); } v.setVisibility(View.VISIBLE); } return v; } 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.globalConfig().handler.suggestion_entered(it); } }); v.setVisibility(View.GONE); _item_views[item_index] = v; } /** Whether the candidates view should be shown for a given editor. */ 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: /* Editor requested that we don't show suggestions. Enable suggestions anyway when the flags [NO_SUGGESTIONS] and [AUTO_CORRECT] are present at the same time. This happens with Google Keep. */ if ((flags & (InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT)) == InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) return false; return true; } case InputType.TYPE_CLASS_NUMBER: // Beware of TYPE_NUMBER_VARIATION_PASSWORD return false; default: return false; } } }