From 95685d4de868c543775c09f0226a0653dea0ec45 Mon Sep 17 00:00:00 2001 From: Tyler Baker <91493312+btylerh7@users.noreply.github.com> Date: Sat, 30 Sep 2023 13:21:36 -0400 Subject: [PATCH] Feature: Support filtering custom emoji in reaction view (#836) * Support filtering custom emojis in reaction keyboard. * Move creation of EditText to conditional block. * Clear unused comment * Update requests variable when publishing filter results so the images displayed will be correct. * Combine text fields in emoji reaction keyboard, create new initializer for EmojiCategory so it can be copied properly. * Performance optimization and fixed a typo in filter. * improve layout --------- Co-authored-by: sk --- .../android/model/EmojiCategory.java | 5 + .../android/ui/CustomEmojiPopupKeyboard.java | 109 +++++++++++++----- mastodon/src/main/res/values/strings_sk.xml | 4 +- 3 files changed, 88 insertions(+), 30 deletions(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/model/EmojiCategory.java b/mastodon/src/main/java/org/joinmastodon/android/model/EmojiCategory.java index 902a60eb2..95eaadf28 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/model/EmojiCategory.java +++ b/mastodon/src/main/java/org/joinmastodon/android/model/EmojiCategory.java @@ -1,5 +1,6 @@ package org.joinmastodon.android.model; +import java.util.ArrayList; import java.util.List; public class EmojiCategory{ @@ -10,4 +11,8 @@ public class EmojiCategory{ this.title=title; this.emojis=emojis; } + public EmojiCategory(EmojiCategory category){ + this.title = category.title; + this.emojis = new ArrayList<>(category.emojis); + } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/CustomEmojiPopupKeyboard.java b/mastodon/src/main/java/org/joinmastodon/android/ui/CustomEmojiPopupKeyboard.java index 2c61a1d31..c1a2fd75a 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/CustomEmojiPopupKeyboard.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/CustomEmojiPopupKeyboard.java @@ -17,6 +17,8 @@ import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; +import android.widget.Filter; +import android.widget.Filterable; import android.widget.FrameLayout; import android.widget.ImageButton; import android.widget.ImageView; @@ -34,6 +36,7 @@ import org.joinmastodon.android.model.Emoji; import org.joinmastodon.android.model.EmojiCategory; import org.joinmastodon.android.ui.utils.UiUtils; +import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -125,13 +128,13 @@ public class CustomEmojiPopupKeyboard extends PopupKeyboard{ new StickyHeadersOverlay(activity, 0).install(list); LinearLayout ll=new LinearLayout(activity) { - @Override - public boolean onInterceptTouchEvent(MotionEvent e){ - if (e.getAction() == MotionEvent.ACTION_MOVE) { - getParent().requestDisallowInterceptTouchEvent(true); - } - return false; + @Override + public boolean onInterceptTouchEvent(MotionEvent e){ + if (e.getAction() == MotionEvent.ACTION_MOVE) { + getParent().requestDisallowInterceptTouchEvent(true); } + return false; + } }; ll.setOrientation(LinearLayout.VERTICAL); ll.setElevation(V.dp(3)); @@ -139,43 +142,52 @@ public class CustomEmojiPopupKeyboard extends PopupKeyboard{ ll.addView(list, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0, 1f)); - FrameLayout bottomPanel=new FrameLayout(activity); - bottomPanel.setPadding(V.dp(16), V.dp(8), V.dp(16), V.dp(8)); - bottomPanel.setBackgroundResource(R.drawable.bg_m3_surface2); - ll.addView(bottomPanel, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - if(forReaction){ + FrameLayout topPanel=new FrameLayout(activity); + topPanel.setPadding(V.dp(16), V.dp(12), V.dp(16), V.dp(12)); + topPanel.setBackgroundResource(R.drawable.bg_m3_surface2); + ll.addView(topPanel, 0, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + InputMethodManager imm=(InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); - - // TODO: support filtering custom emoji EditText input=new EditText(activity); input.setHint(R.string.sk_enter_emoji_hint); input.addTextChangedListener(new TextWatcher() { @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - if (!s.toString().isEmpty()) { - if (emojiRegex.matcher(s.toString()).find()) { + public void onTextChanged(CharSequence s, int start, int before, int count){ + // Only check the emoji regex if the text field was empty before + if(start == 0){ + if(emojiRegex.matcher(s.toString()).find()){ imm.hideSoftInputFromWindow(input.getWindowToken(), 0); listener.onEmojiSelected(s.toString().substring(before)); input.getText().clear(); - } else { - Toast.makeText(activity, R.string.sk_enter_emoji_toast, Toast.LENGTH_SHORT).show(); - input.getText().clear(); } } + for(int i=0; i implements ImageLoaderRecyclerAdapter{ - private final EmojiCategory category; - private final List requests; + private class SingleCategoryAdapter extends UsableRecyclerView.Adapter implements ImageLoaderRecyclerAdapter, Filterable{ + private EmojiCategory category; + + private final EmojiCategory originalCategory; + private List requests; public SingleCategoryAdapter(EmojiCategory category){ super(imgLoader); this.category=category; + this.originalCategory=new EmojiCategory(category); requests=category.emojis.stream().map(e->new UrlImageLoaderRequest(e.getUrl(playGifs), V.dp(24), V.dp(24))).collect(Collectors.toList()); } @@ -225,17 +240,22 @@ public class CustomEmojiPopupKeyboard extends PopupKeyboard{ @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position){ + if(category.emojis.size() == 0) { + holder.itemView.setVisibility(View.GONE); + } if(holder instanceof EmojiViewHolder evh){ evh.bind(category.emojis.get(position-1)); evh.positionWithinCategory=position-1; }else if(holder instanceof SectionHeaderViewHolder shvh){ shvh.bind(TextUtils.isEmpty(category.title) ? domain : category.title); } + super.onBindViewHolder(holder, position); } @Override public int getItemCount(){ + if(category.emojis.size() == 0) return 0; return category.emojis.size()+1; } @@ -253,6 +273,39 @@ public class CustomEmojiPopupKeyboard extends PopupKeyboard{ public ImageLoaderRequest getImageRequest(int position, int image){ return requests.get(position-1); } + + @Override + public Filter getFilter(){ + return emojiFilter; + } + private final Filter emojiFilter = new Filter(){ + @Override + protected FilterResults performFiltering(CharSequence charSequence){ + List filteredEmoji=new ArrayList<>(); + String search=charSequence.toString().toLowerCase().trim(); + + if(charSequence==null || charSequence.length()==0){ + filteredEmoji.addAll(originalCategory.emojis); + }else{ + for(Emoji emoji : originalCategory.emojis){ + if(emoji.shortcode.toLowerCase().contains(search)){ + filteredEmoji.add(emoji); + } + } + + } + FilterResults results=new FilterResults(); + results.values=filteredEmoji; + return results; + } + @Override + protected void publishResults(CharSequence charSequence, FilterResults filterResults){ + category.emojis.clear(); + category.emojis.addAll((List) filterResults.values); + requests=category.emojis.stream().map(e->new UrlImageLoaderRequest(e.getUrl(playGifs), V.dp(24), V.dp(24))).collect(Collectors.toList()); + notifyDataSetChanged(); + } + }; } private class SectionHeaderViewHolder extends BindableViewHolder implements StickyHeadersOverlay.HeaderViewHolder{ diff --git a/mastodon/src/main/res/values/strings_sk.xml b/mastodon/src/main/res/values/strings_sk.xml index 01d926db1..6c0ecf7aa 100644 --- a/mastodon/src/main/res/values/strings_sk.xml +++ b/mastodon/src/main/res/values/strings_sk.xml @@ -363,8 +363,8 @@ %1$,d users reacted with %2$s React with emoji - Please type an emoji - Type to react with an emoji + Please type an emoji + Type an emoji or search custom emoji Duration Indefinite 5 minutes