From 78c39fb7153967de4947ababc46c9001c0e96492 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Sun, 14 Oct 2018 12:53:14 +0300 Subject: [PATCH] allow touches when emoji keyboard is visible; internal overhaul --- .../create_content/CreateContentActivity.java | 24 +------ .../activities/topic/TopicActivity.java | 31 +-------- .../mthmmy/activities/topic/TopicAdapter.java | 39 ++++------- .../thmmy/mthmmy/editorview/EditorView.java | 69 ++++++++++++------- .../mthmmy/editorview/EmojiInputField.java | 8 +++ .../mthmmy/editorview/EmojiKeyboard.java | 46 +++++++++++-- .../mthmmy/editorview/IEmojiKeyboard.java | 32 +++++++++ 7 files changed, 141 insertions(+), 108 deletions(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiInputField.java create mode 100644 app/src/main/java/gr/thmmy/mthmmy/editorview/IEmojiKeyboard.java diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java index b0b6a11b..877df6b9 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java @@ -8,7 +8,6 @@ import android.support.design.widget.TextInputLayout; import android.text.InputType; import android.view.View; import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputConnection; import android.widget.Toast; import gr.thmmy.mthmmy.R; @@ -20,8 +19,7 @@ import gr.thmmy.mthmmy.session.SessionManager; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import timber.log.Timber; -public class CreateContentActivity extends BaseActivity implements EmojiKeyboard.EmojiKeyboardOwner, - NewTopicTask.NewTopicTaskCallbacks { +public class CreateContentActivity extends BaseActivity implements NewTopicTask.NewTopicTaskCallbacks { public final static String EXTRA_NEW_TOPIC_URL = "new-topic-extra"; @@ -56,8 +54,7 @@ public class CreateContentActivity extends BaseActivity implements EmojiKeyboard subjectInput.getEditText().setImeOptions(EditorInfo.IME_ACTION_DONE); contentEditor = findViewById(R.id.main_content_editorview); - setEmojiKeyboardInputConnection(contentEditor.getInputConnection()); - contentEditor.setEmojiKeyboardOwner(this); + contentEditor.setEmojiKeyboard(emojiKeyboard); contentEditor.setOnSubmitListener(v -> { if (newTopicUrl != null) { boolean includeAppSignature = true; @@ -72,27 +69,10 @@ public class CreateContentActivity extends BaseActivity implements EmojiKeyboard } }); } - - @Override - public void setEmojiKeyboardVisible(boolean visible) { - emojiKeyboard.setVisibility(visible ? View.VISIBLE : View.GONE); - } - - @Override - public boolean isEmojiKeyboardVisible() { - return emojiKeyboard.getVisibility() == View.VISIBLE; - } - - @Override - public void setEmojiKeyboardInputConnection(InputConnection ic) { - emojiKeyboard.setInputConnection(ic); - } - @Override public void onBackPressed() { if (emojiKeyboard.getVisibility() == View.VISIBLE) { emojiKeyboard.setVisibility(View.GONE); - contentEditor.updateEmojiKeyboardVisibility(); } else { super.onBackPressed(); } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java index 12b79165..4d03649d 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java @@ -27,7 +27,6 @@ import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; -import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import android.widget.ImageButton; import android.widget.LinearLayout; @@ -67,8 +66,7 @@ import static gr.thmmy.mthmmy.services.NotificationService.NEW_POST_TAG; * key {@link #BUNDLE_TOPIC_TITLE} for faster title rendering. */ @SuppressWarnings("unchecked") -public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFocusChangeListener, - EmojiKeyboard.EmojiKeyboardOwner { +public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFocusChangeListener { //Activity's variables /** * The key to use when putting topic's url String to {@link TopicActivity}'s Bundle. @@ -180,7 +178,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo getApplicationContext(), topicPageUrl); recyclerView.setLayoutManager(layoutManager); - topicAdapter = new TopicAdapter(this, topicItems); + topicAdapter = new TopicAdapter(this, emojiKeyboard, topicItems); recyclerView.setAdapter(topicAdapter); replyFAB = findViewById(R.id.topic_fab); @@ -269,16 +267,6 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo return; } else if (emojiKeyboard.getVisibility() == View.VISIBLE) { emojiKeyboard.setVisibility(View.GONE); - if (viewModel.isEditingPost()) { - TopicAdapter.EditMessageViewHolder vh = (TopicAdapter.EditMessageViewHolder) - recyclerView.findViewHolderForAdapterPosition(viewModel.getPostBeingEditedPosition()); - vh.editEditor.updateEmojiKeyboardVisibility(); - } - if (viewModel.isWritingReply()) { - TopicAdapter.QuickReplyViewHolder vh = (TopicAdapter.QuickReplyViewHolder) - recyclerView.findViewHolderForAdapterPosition(viewModel.postCount()); - vh.replyEditor.updateEmojiKeyboardVisibility(); - } return; } else if (viewModel.isWritingReply()) { topicItems.remove(topicItems.size() - 1); @@ -319,21 +307,6 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo recyclerView.scrollToPosition(position); } - @Override - public void setEmojiKeyboardVisible(boolean visible) { - emojiKeyboard.setVisibility(visible ? View.VISIBLE : View.GONE); - } - - @Override - public boolean isEmojiKeyboardVisible() { - return emojiKeyboard.getVisibility() == View.VISIBLE; - } - - @Override - public void setEmojiKeyboardInputConnection(InputConnection ic) { - emojiKeyboard.setInputConnection(ic); - } - //--------------------------------------BOTTOM NAV BAR METHODS---------------------------------- /** diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java index 820c7770..bfc26961 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java @@ -26,7 +26,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import android.webkit.WebResourceRequest; import android.webkit.WebView; @@ -59,7 +58,7 @@ import gr.thmmy.mthmmy.activities.board.BoardActivity; import gr.thmmy.mthmmy.activities.profile.ProfileActivity; import gr.thmmy.mthmmy.base.BaseActivity; import gr.thmmy.mthmmy.editorview.EditorView; -import gr.thmmy.mthmmy.editorview.EmojiKeyboard; +import gr.thmmy.mthmmy.editorview.IEmojiKeyboard; import gr.thmmy.mthmmy.model.Poll; import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyFile; @@ -91,7 +90,7 @@ class TopicAdapter extends RecyclerView.Adapter { private static int THUMBNAIL_SIZE; private final Context context; private final OnPostFocusChangeListener postFocusListener; - private final EmojiKeyboard.EmojiKeyboardOwner emojiKeyboardOwner; + private final IEmojiKeyboard emojiKeyboard; private final List topicItems; private TopicViewModel viewModel; @@ -99,11 +98,11 @@ class TopicAdapter extends RecyclerView.Adapter { * @param context the context of the {@link RecyclerView} * @param topicItems List of {@link Post} objects to use */ - TopicAdapter(TopicActivity context, List topicItems) { + TopicAdapter(TopicActivity context, IEmojiKeyboard emojiKeyboard, List topicItems) { this.context = context; this.topicItems = topicItems; this.postFocusListener = context; - this.emojiKeyboardOwner = context; + this.emojiKeyboard = emojiKeyboard; viewModel = ViewModelProviders.of(context).get(TopicViewModel.class); @@ -590,15 +589,9 @@ class TopicAdapter extends RecyclerView.Adapter { holder.quickReplySubject.setRawInputType(InputType.TYPE_CLASS_TEXT); holder.quickReplySubject.setImeOptions(EditorInfo.IME_ACTION_DONE); - holder.replyEditor.setEmojiKeyboardOwner(emojiKeyboardOwner); - InputConnection ic = holder.replyEditor.getInputConnection(); - emojiKeyboardOwner.setEmojiKeyboardInputConnection(ic); - holder.replyEditor.updateEmojiKeyboardVisibility(); - holder.replyEditor.getEditText().setOnFocusChangeListener((v, hasFocus) -> { - InputConnection ic12 = holder.replyEditor.getInputConnection(); - emojiKeyboardOwner.setEmojiKeyboardInputConnection(ic12); - holder.replyEditor.updateEmojiKeyboardVisibility(); - }); + holder.replyEditor.setEmojiKeyboard(emojiKeyboard); + holder.replyEditor.requestEditTextFocus(); + emojiKeyboard.registerEmojiInputField(holder.replyEditor); holder.replyEditor.setText(viewModel.getBuildedQuotes()); holder.replyEditor.setOnSubmitListener(view -> { @@ -611,7 +604,7 @@ class TopicAdapter extends RecyclerView.Adapter { imm.hideSoftInputFromWindow(view.getWindowToken(), 0); holder.itemView.setAlpha(0.5f); holder.itemView.setEnabled(false); - emojiKeyboardOwner.setEmojiKeyboardVisible(false); + emojiKeyboard.hide(); viewModel.postReply(context, holder.quickReplySubject.getText().toString(), holder.replyEditor.getText().toString()); @@ -641,18 +634,10 @@ class TopicAdapter extends RecyclerView.Adapter { holder.editSubject.setRawInputType(InputType.TYPE_CLASS_TEXT); holder.editSubject.setImeOptions(EditorInfo.IME_ACTION_DONE); - holder.editEditor.setEmojiKeyboardOwner(emojiKeyboardOwner); - InputConnection ic = holder.editEditor.getInputConnection(); - emojiKeyboardOwner.setEmojiKeyboardInputConnection(ic); - holder.editEditor.updateEmojiKeyboardVisibility(); + holder.editEditor.setEmojiKeyboard(emojiKeyboard); + holder.editEditor.requestEditTextFocus(); + emojiKeyboard.registerEmojiInputField(holder.editEditor); holder.editEditor.setText(viewModel.getPostBeingEditedText()); - holder.editEditor.getEditText().setOnFocusChangeListener((v, hasFocus) -> { - if (hasFocus) { - InputConnection ic1 = holder.editEditor.getInputConnection(); - emojiKeyboardOwner.setEmojiKeyboardInputConnection(ic1); - holder.editEditor.updateEmojiKeyboardVisibility(); - } - }); holder.editEditor.setOnSubmitListener(view -> { if (holder.editSubject.getText().toString().isEmpty()) return; if (holder.editEditor.getText().toString().isEmpty()) { @@ -663,7 +648,7 @@ class TopicAdapter extends RecyclerView.Adapter { imm.hideSoftInputFromWindow(view.getWindowToken(), 0); holder.itemView.setAlpha(0.5f); holder.itemView.setEnabled(false); - emojiKeyboardOwner.setEmojiKeyboardVisible(false); + emojiKeyboard.hide(); viewModel.editPost(position, holder.editSubject.getText().toString(), holder.editEditor.getText().toString()); }); diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java b/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java index 527b3fcb..fb82337a 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java +++ b/app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java @@ -31,7 +31,7 @@ import java.util.Objects; import gr.thmmy.mthmmy.R; -public class EditorView extends LinearLayout { +public class EditorView extends LinearLayout implements EmojiInputField { private SparseArray colors = new SparseArray<>(); @@ -39,7 +39,7 @@ public class EditorView extends LinearLayout { private TextInputEditText editText; private AppCompatImageButton emojiButton; private AppCompatImageButton submitButton; - private EmojiKeyboard.EmojiKeyboardOwner emojiKeyboardOwner; + private IEmojiKeyboard emojiKeyboard; public EditorView(Context context) { super(context); @@ -63,6 +63,22 @@ public class EditorView extends LinearLayout { edittextWrapper = findViewById(R.id.editor_edittext_wrapper); editText = findViewById(R.id.editor_edittext); + editText.setOnFocusChangeListener((view, focused) -> { + if (focused) emojiKeyboard.onEmojiInputFieldFocused(EditorView.this); + }); + edittextWrapper.setOnFocusChangeListener((view, focused) -> { + if (focused) emojiKeyboard.onEmojiInputFieldFocused(EditorView.this); + }); + editText.setOnClickListener(view -> { + if (!emojiKeyboard.isVisible()) { + InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE); + imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT); + } else { + InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(getWindowToken(), 0); + requestEditTextFocus(); + } + }); TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.EditorView, 0, 0); try { @@ -79,11 +95,6 @@ public class EditorView extends LinearLayout { emojiButton = findViewById(R.id.emoji_keyboard_button); - editText.setOnTouchListener((v, event) -> { - if (emojiKeyboardOwner.isEmojiKeyboardVisible()) return true; - return false; - }); - colors.append(R.id.black, "black"); colors.append(R.id.red, "red"); colors.append(R.id.yellow, "yellow"); @@ -267,22 +278,28 @@ public class EditorView extends LinearLayout { emojiButton.setOnClickListener(view -> { InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE); - assert imm != null; - if (emojiKeyboardOwner.isEmojiKeyboardVisible()) { + //cache selection. For some reason it gets reset sometimes + int selectionStart = editText.getSelectionStart(); + int selectionEnd = editText.getSelectionStart(); + if (emojiKeyboard.onEmojiButtonToggle()) { + //prevent system keyboard from appearing when clicking the edittext + editText.setTextIsSelectable(true); + imm.hideSoftInputFromWindow(getWindowToken(), 0); + } + else { editText.requestFocus(); imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT); - emojiButton.setImageResource(R.drawable.ic_tag_faces_24dp); - } else { - imm.hideSoftInputFromWindow(getWindowToken(), 0); - view.clearFocus(); - emojiButton.setImageResource(R.drawable.ic_keyboard_24dp); } - emojiKeyboardOwner.setEmojiKeyboardVisible(!emojiKeyboardOwner.isEmojiKeyboardVisible()); + editText.setSelection(selectionStart, selectionEnd); }); submitButton = findViewById(R.id.submit_button); } + public void setEmojiKeyboard(IEmojiKeyboard emojiKeyboard) { + this.emojiKeyboard = emojiKeyboard; + } + public TextInputEditText getEditText() { return editText; } @@ -307,18 +324,22 @@ public class EditorView extends LinearLayout { submitButton.setOnClickListener(onSubmitListener); } - public void setEmojiKeyboardOwner(EmojiKeyboard.EmojiKeyboardOwner emojiKeyboardOwner) { - this.emojiKeyboardOwner = emojiKeyboardOwner; - } - - public InputConnection getInputConnection() { - return editText.onCreateInputConnection(new EditorInfo()); + public boolean requestEditTextFocus() { + emojiKeyboard.onEmojiInputFieldFocused(EditorView.this); + return editText.requestFocus(); } - public void updateEmojiKeyboardVisibility() { - if (emojiKeyboardOwner.isEmojiKeyboardVisible()) + @Override + public void onKeyboardVisibilityChange(boolean visible) { + if (visible) { emojiButton.setImageResource(R.drawable.ic_keyboard_24dp); - else + } else { emojiButton.setImageResource(R.drawable.ic_tag_faces_24dp); + } + } + + @Override + public InputConnection getInputConnection() { + return editText.onCreateInputConnection(new EditorInfo()); } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiInputField.java b/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiInputField.java new file mode 100644 index 00000000..0cdccd60 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiInputField.java @@ -0,0 +1,8 @@ +package gr.thmmy.mthmmy.editorview; + +import android.view.inputmethod.InputConnection; + +public interface EmojiInputField { + void onKeyboardVisibilityChange(boolean visible); + InputConnection getInputConnection(); +} diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiKeyboard.java b/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiKeyboard.java index 14a63438..856498ec 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiKeyboard.java +++ b/app/src/main/java/gr/thmmy/mthmmy/editorview/EmojiKeyboard.java @@ -12,9 +12,11 @@ import android.view.MotionEvent; import android.view.inputmethod.InputConnection; import android.widget.LinearLayout; +import java.util.HashSet; + import gr.thmmy.mthmmy.R; -public class EmojiKeyboard extends LinearLayout { +public class EmojiKeyboard extends LinearLayout implements IEmojiKeyboard { // TODO: Sort emojis in a way that makes sense private final Emoji[] emojis = {new Emoji(R.drawable.emoji_smiley, ":)"), @@ -134,7 +136,9 @@ public class EmojiKeyboard extends LinearLayout { new Emoji(R.drawable.emoji_smurf, "^smurf^") }; - InputConnection inputConnection; + private InputConnection inputConnection; + private HashSet emojiInputFields = new HashSet<>(); + private Context context; public EmojiKeyboard(Context context) { this(context, null, 0); @@ -150,6 +154,7 @@ public class EmojiKeyboard extends LinearLayout { } public void init(Context context, AttributeSet attrs) { + this.context = context; LayoutInflater.from(context).inflate(R.layout.emoji_keyboard, this, true); setOrientation(VERTICAL); setBackgroundColor(getResources().getColor(R.color.primary)); @@ -195,14 +200,43 @@ public class EmojiKeyboard extends LinearLayout { }); } + @Override + public void hide() { + setVisibility(GONE); + } + + @Override + public void registerEmojiInputField(EmojiInputField emojiInputField) { + emojiInputFields.add(emojiInputField); + } + public void setInputConnection(InputConnection inputConnection) { this.inputConnection = inputConnection; } - public interface EmojiKeyboardOwner { - void setEmojiKeyboardVisible(boolean visible); - boolean isEmojiKeyboardVisible(); - void setEmojiKeyboardInputConnection(InputConnection ic); + @Override + public boolean onEmojiButtonToggle() { + if (getVisibility() == VISIBLE) setVisibility(GONE); + else setVisibility(VISIBLE); + return getVisibility() == VISIBLE; + } + + @Override + public void onEmojiInputFieldFocused(EmojiInputField emojiInputField) { + setInputConnection(emojiInputField.getInputConnection()); + } + + @Override + public void setVisibility(int visibility) { + //notify input fields + for (EmojiInputField emojiInputField : emojiInputFields) + emojiInputField.onKeyboardVisibilityChange(visibility == VISIBLE); + super.setVisibility(visibility); + } + + @Override + public boolean isVisible() { + return getVisibility() == VISIBLE; } class Emoji { diff --git a/app/src/main/java/gr/thmmy/mthmmy/editorview/IEmojiKeyboard.java b/app/src/main/java/gr/thmmy/mthmmy/editorview/IEmojiKeyboard.java new file mode 100644 index 00000000..3ec906f2 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/editorview/IEmojiKeyboard.java @@ -0,0 +1,32 @@ +package gr.thmmy.mthmmy.editorview; + +public interface IEmojiKeyboard { + /** + * Hide keyboard + */ + void hide(); + + /** + * Check if keyboard is visible + * @return true, if {@link EmojiKeyboard#getVisibility()} returns View.VISIBLE, otherwise false + */ + boolean isVisible(); + + /** + * Callback to the keyboard when {@link EditorView#emojiButton} is clicked + * @return whether the keyboard became visible or not + */ + boolean onEmojiButtonToggle(); + + /** + * Callback to create input connection with {@link EmojiInputField} + * @param emojiInputField the connected input field + */ + void onEmojiInputFieldFocused(EmojiInputField emojiInputField); + + /** + * Persist a set of all input fields to update all of them when visibility changes + * @param emojiInputField the input field to be added + */ + void registerEmojiInputField(EmojiInputField emojiInputField); +}