mirror of
https://github.com/Helium314/HeliBoard.git
synced 2025-06-08 23:57:41 +00:00
Allow for switching between emoji categories using swipe left/right (#1488)
This commit is contained in:
parent
199f177c2d
commit
731c6cdd5e
9 changed files with 217 additions and 252 deletions
|
@ -107,6 +107,7 @@ dependencies {
|
||||||
implementation("androidx.core:core-ktx:1.16.0")
|
implementation("androidx.core:core-ktx:1.16.0")
|
||||||
implementation("androidx.recyclerview:recyclerview:1.4.0")
|
implementation("androidx.recyclerview:recyclerview:1.4.0")
|
||||||
implementation("androidx.autofill:autofill:1.1.0")
|
implementation("androidx.autofill:autofill:1.1.0")
|
||||||
|
implementation("androidx.viewpager2:viewpager2:1.1.0")
|
||||||
|
|
||||||
// kotlin
|
// kotlin
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.1")
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.1")
|
||||||
|
|
|
@ -479,7 +479,6 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
|
||||||
if (mKeyboardViewWrapper.getOneHandedModeEnabled() == enabled) {
|
if (mKeyboardViewWrapper.getOneHandedModeEnabled() == enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mEmojiPalettesView.clearKeyboardCache();
|
|
||||||
final Settings settings = Settings.getInstance();
|
final Settings settings = Settings.getInstance();
|
||||||
mKeyboardViewWrapper.setOneHandedModeEnabled(enabled);
|
mKeyboardViewWrapper.setOneHandedModeEnabled(enabled);
|
||||||
mKeyboardViewWrapper.setOneHandedGravity(settings.getCurrent().mOneHandedModeGravity);
|
mKeyboardViewWrapper.setOneHandedGravity(settings.getCurrent().mOneHandedModeGravity);
|
||||||
|
@ -645,6 +644,12 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void trimMemory() {
|
||||||
|
if (mEmojiPalettesView != null) {
|
||||||
|
mEmojiPalettesView.clearKeyboardCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressLint("InflateParams")
|
@SuppressLint("InflateParams")
|
||||||
public View onCreateInputView(@NonNull Context displayContext, final boolean isHardwareAcceleratedDrawingEnabled) {
|
public View onCreateInputView(@NonNull Context displayContext, final boolean isHardwareAcceleratedDrawingEnabled) {
|
||||||
if (mKeyboardView != null) {
|
if (mKeyboardView != null) {
|
||||||
|
|
|
@ -261,20 +261,6 @@ final class EmojiCategory {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the view pager's page position for the categoryId
|
|
||||||
public int getPagerPageIdFromCategoryAndPageId(final int categoryId, final int categoryPageId) {
|
|
||||||
int sum = 0;
|
|
||||||
for (int i = 0; i < mShownCategories.size(); ++i) {
|
|
||||||
final CategoryProperties props = mShownCategories.get(i);
|
|
||||||
if (props.mCategoryId == categoryId) {
|
|
||||||
return sum + categoryPageId;
|
|
||||||
}
|
|
||||||
sum += props.getPageCount();
|
|
||||||
}
|
|
||||||
Log.w(TAG, "categoryId not found: " + categoryId);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRecentTabId() {
|
public int getRecentTabId() {
|
||||||
return getTabIdFromCategoryId(EmojiCategory.ID_RECENTS);
|
return getTabIdFromCategoryId(EmojiCategory.ID_RECENTS);
|
||||||
}
|
}
|
||||||
|
@ -285,11 +271,11 @@ final class EmojiCategory {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a keyboard from the recycler view's adapter position.
|
// Returns a keyboard from the recycler view's adapter position.
|
||||||
public DynamicGridKeyboard getKeyboardFromAdapterPosition(final int position) {
|
public DynamicGridKeyboard getKeyboardFromAdapterPosition(int categoryId, final int position) {
|
||||||
if (position >= 0 && position < getCurrentCategoryPageCount()) {
|
if (position >= 0 && position < getCategoryPageCount(categoryId)) {
|
||||||
return getKeyboard(mCurrentCategoryId, position);
|
return getKeyboard(categoryId, position);
|
||||||
}
|
}
|
||||||
Log.w(TAG, "invalid position for categoryId : " + mCurrentCategoryId);
|
Log.w(TAG, "invalid position for categoryId : " + categoryId);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ package helium314.keyboard.keyboard.emoji
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.viewpager2.widget.ViewPager2
|
||||||
import helium314.keyboard.keyboard.internal.KeyboardParams
|
import helium314.keyboard.keyboard.internal.KeyboardParams
|
||||||
import helium314.keyboard.latin.R
|
import helium314.keyboard.latin.R
|
||||||
import helium314.keyboard.latin.settings.Settings
|
import helium314.keyboard.latin.settings.Settings
|
||||||
|
@ -47,7 +47,7 @@ internal class EmojiLayoutParams(res: Resources) {
|
||||||
emojiKeyboardHeight = emojiListHeight - emojiCategoryPageIdViewHeight - emojiListBottomMargin
|
emojiKeyboardHeight = emojiListHeight - emojiCategoryPageIdViewHeight - emojiListBottomMargin
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setEmojiListProperties(vp: RecyclerView) {
|
fun setEmojiListProperties(vp: ViewPager2) {
|
||||||
val lp = vp.layoutParams as LinearLayout.LayoutParams
|
val lp = vp.layoutParams as LinearLayout.LayoutParams
|
||||||
lp.height = emojiKeyboardHeight
|
lp.height = emojiKeyboardHeight
|
||||||
lp.bottomMargin = emojiListBottomMargin
|
lp.bottomMargin = emojiListBottomMargin
|
||||||
|
|
|
@ -12,156 +12,32 @@ import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import helium314.keyboard.keyboard.Key;
|
|
||||||
import helium314.keyboard.keyboard.Keyboard;
|
import helium314.keyboard.keyboard.Keyboard;
|
||||||
import helium314.keyboard.keyboard.KeyboardView;
|
|
||||||
import helium314.keyboard.latin.R;
|
import helium314.keyboard.latin.R;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import helium314.keyboard.latin.settings.Settings;
|
|
||||||
|
|
||||||
final class EmojiPalettesAdapter extends RecyclerView.Adapter<EmojiPalettesAdapter.ViewHolder>{
|
final class EmojiPalettesAdapter extends RecyclerView.Adapter<EmojiPalettesAdapter.ViewHolder>{
|
||||||
private static final String TAG = EmojiPalettesAdapter.class.getSimpleName();
|
private static final String TAG = EmojiPalettesAdapter.class.getSimpleName();
|
||||||
private static final boolean DEBUG_PAGER = false;
|
private static final boolean DEBUG_PAGER = false;
|
||||||
|
|
||||||
|
private final int mCategoryId;
|
||||||
private final OnKeyEventListener mListener;
|
private final OnKeyEventListener mListener;
|
||||||
private final DynamicGridKeyboard mRecentsKeyboard;
|
|
||||||
private final SparseArray<EmojiPageKeyboardView> mActiveKeyboardViews = new SparseArray<>();
|
|
||||||
private final EmojiCategory mEmojiCategory;
|
private final EmojiCategory mEmojiCategory;
|
||||||
private int mActivePosition = 0;
|
|
||||||
|
|
||||||
public EmojiPalettesAdapter(final EmojiCategory emojiCategory,
|
public EmojiPalettesAdapter(final EmojiCategory emojiCategory, int categoryId, final OnKeyEventListener listener) {
|
||||||
final OnKeyEventListener listener) {
|
|
||||||
mEmojiCategory = emojiCategory;
|
mEmojiCategory = emojiCategory;
|
||||||
|
mCategoryId = categoryId;
|
||||||
mListener = listener;
|
mListener = listener;
|
||||||
mRecentsKeyboard = mEmojiCategory.getKeyboard(EmojiCategory.ID_RECENTS, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void flushPendingRecentKeys() {
|
|
||||||
mRecentsKeyboard.flushPendingRecentKeys();
|
|
||||||
final KeyboardView recentKeyboardView =
|
|
||||||
mActiveKeyboardViews.get(mEmojiCategory.getRecentTabId());
|
|
||||||
if (recentKeyboardView != null) {
|
|
||||||
recentKeyboardView.invalidateAllKeys();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addRecentKey(final Key key) {
|
|
||||||
if (Settings.getValues().mIncognitoModeEnabled) {
|
|
||||||
// We do not want to log recent keys while being in incognito
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mEmojiCategory.isInRecentTab()) {
|
|
||||||
mRecentsKeyboard.addPendingKey(key);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mRecentsKeyboard.addKeyFirst(key);
|
|
||||||
final KeyboardView recentKeyboardView =
|
|
||||||
mActiveKeyboardViews.get(mEmojiCategory.getRecentTabId());
|
|
||||||
if (recentKeyboardView != null) {
|
|
||||||
recentKeyboardView.invalidateAllKeys();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onPageScrolled() {
|
|
||||||
releaseCurrentKey(false /* withKeyRegistering */);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void releaseCurrentKey(final boolean withKeyRegistering) {
|
|
||||||
// Make sure the delayed key-down event (highlight effect and haptic feedback) will be
|
|
||||||
// canceled.
|
|
||||||
final EmojiPageKeyboardView currentKeyboardView =
|
|
||||||
mActiveKeyboardViews.get(mActivePosition);
|
|
||||||
if (currentKeyboardView == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
currentKeyboardView.releaseCurrentKey(withKeyRegistering);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
@Override
|
|
||||||
public Object instantiateItem(final ViewGroup container, final int position) {
|
|
||||||
if (DEBUG_PAGER) {
|
|
||||||
Log.d(TAG, "instantiate item: " + position);
|
|
||||||
}
|
|
||||||
final EmojiPageKeyboardView oldKeyboardView = mActiveKeyboardViews.get(position);
|
|
||||||
if (oldKeyboardView != null) {
|
|
||||||
oldKeyboardView.deallocateMemory();
|
|
||||||
// This may be redundant but wanted to be safer..
|
|
||||||
mActiveKeyboardViews.remove(position);
|
|
||||||
}
|
|
||||||
final Keyboard keyboard =
|
|
||||||
mEmojiCategory.getKeyboardFromPagePosition(position);
|
|
||||||
final LayoutInflater inflater = LayoutInflater.from(container.getContext());
|
|
||||||
final EmojiPageKeyboardView keyboardView = (EmojiPageKeyboardView) inflater.inflate(
|
|
||||||
R.layout.emoji_keyboard_page, container, false);
|
|
||||||
keyboardView.setKeyboard(keyboard);
|
|
||||||
keyboardView.setOnKeyEventListener(mListener);
|
|
||||||
container.addView(keyboardView);
|
|
||||||
mActiveKeyboardViews.put(position, keyboardView);
|
|
||||||
return keyboardView;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPrimaryItem(final ViewGroup container, final int position,
|
|
||||||
final Object object) {
|
|
||||||
if (mActivePosition == position) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final EmojiPageKeyboardView oldKeyboardView = mActiveKeyboardViews.get(mActivePosition);
|
|
||||||
if (oldKeyboardView != null) {
|
|
||||||
oldKeyboardView.releaseCurrentKey(false);
|
|
||||||
oldKeyboardView.deallocateMemory();
|
|
||||||
}
|
|
||||||
mActivePosition = position;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isViewFromObject(final View view, final Object object) {
|
|
||||||
return view == object;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void destroyItem(final ViewGroup container, final int position,
|
|
||||||
final Object object) {
|
|
||||||
if (DEBUG_PAGER) {
|
|
||||||
Log.d(TAG, "destroy item: " + position + ", " + object.getClass().getSimpleName());
|
|
||||||
}
|
|
||||||
final EmojiPageKeyboardView keyboardView = mActiveKeyboardViews.get(position);
|
|
||||||
if (keyboardView != null) {
|
|
||||||
keyboardView.deallocateMemory();
|
|
||||||
mActiveKeyboardViews.remove(position);
|
|
||||||
}
|
|
||||||
if (object instanceof View) {
|
|
||||||
container.removeView((View)object);
|
|
||||||
} else {
|
|
||||||
Log.w(TAG, "Warning!!! Emoji palette may be leaking. " + object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
/*if (DEBUG_PAGER) {
|
|
||||||
Log.d(TAG, "instantiate item: " + viewType);
|
|
||||||
}
|
|
||||||
final EmojiPageKeyboardView oldKeyboardView = mActiveKeyboardViews.get(viewType);
|
|
||||||
if (oldKeyboardView != null) {
|
|
||||||
oldKeyboardView.deallocateMemory();
|
|
||||||
// This may be redundant but wanted to be safer..
|
|
||||||
mActiveKeyboardViews.remove(viewType);
|
|
||||||
}
|
|
||||||
final Keyboard keyboard =
|
|
||||||
mEmojiCategory.getKeyboardFromPagePosition(parent.getVerticalScrollbarPosition());*/
|
|
||||||
final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
||||||
final EmojiPageKeyboardView keyboardView = (EmojiPageKeyboardView)inflater.inflate(
|
final EmojiPageKeyboardView keyboardView = (EmojiPageKeyboardView)inflater.inflate(
|
||||||
R.layout.emoji_keyboard_page, parent, false);
|
R.layout.emoji_keyboard_page, parent, false);
|
||||||
/*keyboardView.setKeyboard(keyboard);
|
|
||||||
keyboardView.setOnKeyEventListener(mListener);
|
|
||||||
parent.addView(keyboardView);
|
|
||||||
mActiveKeyboardViews.put(parent.getVerticalScrollbarPosition(), keyboardView);*/
|
|
||||||
return new ViewHolder(keyboardView);
|
return new ViewHolder(keyboardView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,33 +46,22 @@ final class EmojiPalettesAdapter extends RecyclerView.Adapter<EmojiPalettesAdapt
|
||||||
if (DEBUG_PAGER) {
|
if (DEBUG_PAGER) {
|
||||||
Log.d(TAG, "instantiate item: " + position);
|
Log.d(TAG, "instantiate item: " + position);
|
||||||
}
|
}
|
||||||
final EmojiPageKeyboardView oldKeyboardView = mActiveKeyboardViews.get(position);
|
|
||||||
if (oldKeyboardView != null) {
|
|
||||||
oldKeyboardView.deallocateMemory();
|
|
||||||
// This may be redundant but wanted to be safer..
|
|
||||||
mActiveKeyboardViews.remove(position);
|
|
||||||
}
|
|
||||||
final Keyboard keyboard =
|
final Keyboard keyboard =
|
||||||
mEmojiCategory.getKeyboardFromAdapterPosition(position);
|
mEmojiCategory.getKeyboardFromAdapterPosition(mCategoryId, position);
|
||||||
holder.getKeyboardView().setKeyboard(keyboard);
|
holder.getKeyboardView().setKeyboard(keyboard);
|
||||||
holder.getKeyboardView().setOnKeyEventListener(mListener);
|
holder.getKeyboardView().setOnKeyEventListener(mListener);
|
||||||
//parent.addView(keyboardView);
|
}
|
||||||
mActiveKeyboardViews.put(position, holder.getKeyboardView());
|
|
||||||
|
|
||||||
/*if (mActivePosition == position) {
|
@Override
|
||||||
return;
|
public void onViewDetachedFromWindow(@NonNull ViewHolder holder) {
|
||||||
}
|
holder.getKeyboardView().releaseCurrentKey(false);
|
||||||
final EmojiPageKeyboardView oldKeyboardView = mActiveKeyboardViews.get(mActivePosition);
|
holder.getKeyboardView().deallocateMemory();
|
||||||
if (oldKeyboardView != null) {
|
|
||||||
oldKeyboardView.releaseCurrentKey(false);
|
|
||||||
oldKeyboardView.deallocateMemory();
|
|
||||||
}
|
|
||||||
mActivePosition = position;*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
return mEmojiCategory.getCurrentCategoryPageCount();
|
return mEmojiCategory.getCategoryPageCount(mCategoryId);
|
||||||
}
|
}
|
||||||
|
|
||||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
@ -210,7 +75,6 @@ final class EmojiPalettesAdapter extends RecyclerView.Adapter<EmojiPalettesAdapt
|
||||||
public EmojiPageKeyboardView getKeyboardView() {
|
public EmojiPageKeyboardView getKeyboardView() {
|
||||||
return customView;
|
return customView;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
|
@ -20,6 +21,7 @@ import android.widget.LinearLayout;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import androidx.viewpager2.widget.ViewPager2;
|
||||||
import helium314.keyboard.keyboard.Key;
|
import helium314.keyboard.keyboard.Key;
|
||||||
import helium314.keyboard.keyboard.Keyboard;
|
import helium314.keyboard.keyboard.Keyboard;
|
||||||
import helium314.keyboard.keyboard.KeyboardActionListener;
|
import helium314.keyboard.keyboard.KeyboardActionListener;
|
||||||
|
@ -41,8 +43,6 @@ import helium314.keyboard.latin.settings.Settings;
|
||||||
import helium314.keyboard.latin.settings.SettingsValues;
|
import helium314.keyboard.latin.settings.SettingsValues;
|
||||||
import helium314.keyboard.latin.utils.ResourceUtils;
|
import helium314.keyboard.latin.utils.ResourceUtils;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import static helium314.keyboard.latin.common.Constants.NOT_A_COORDINATE;
|
import static helium314.keyboard.latin.common.Constants.NOT_A_COORDINATE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -58,20 +58,132 @@ import static helium314.keyboard.latin.common.Constants.NOT_A_COORDINATE;
|
||||||
*/
|
*/
|
||||||
public final class EmojiPalettesView extends LinearLayout
|
public final class EmojiPalettesView extends LinearLayout
|
||||||
implements View.OnClickListener, OnKeyEventListener {
|
implements View.OnClickListener, OnKeyEventListener {
|
||||||
|
private static final class PagerViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
private long mCategoryId;
|
||||||
|
|
||||||
|
private PagerViewHolder(View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class PagerAdapter extends RecyclerView.Adapter<PagerViewHolder> {
|
||||||
|
private boolean mInitialized;
|
||||||
|
|
||||||
|
private PagerAdapter() {
|
||||||
|
setHasStableIds(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
|
||||||
|
recyclerView.setItemViewCacheSize(mEmojiCategory.getShownCategories().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public PagerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
var view = LayoutInflater.from(parent.getContext()).inflate(R.layout.emoji_category_view, parent, false);
|
||||||
|
var viewHolder = new PagerViewHolder(view);
|
||||||
|
var emojiRecyclerView = getRecyclerView(view);
|
||||||
|
|
||||||
|
emojiRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
||||||
|
@Override
|
||||||
|
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
|
||||||
|
super.onScrollStateChanged(recyclerView, newState);
|
||||||
|
// Ignore this message. Only want the actual page selected.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
|
||||||
|
updateState(recyclerView, viewHolder);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
emojiRecyclerView.setPersistentDrawingCache(PERSISTENT_NO_CACHE);
|
||||||
|
return viewHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(PagerViewHolder holder, int position) {
|
||||||
|
holder.mCategoryId = getItemId(position);
|
||||||
|
var recyclerView = getRecyclerView(holder.itemView);
|
||||||
|
recyclerView.setAdapter(new EmojiPalettesAdapter(mEmojiCategory, (int) holder.mCategoryId,
|
||||||
|
EmojiPalettesView.this));
|
||||||
|
|
||||||
|
if (! mInitialized) {
|
||||||
|
recyclerView.scrollToPosition(mEmojiCategory.getCurrentCategoryPageId());
|
||||||
|
mInitialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return mEmojiCategory.getShownCategories().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewAttachedToWindow(PagerViewHolder holder) {
|
||||||
|
if (mPager.getScrollState() == ViewPager2.SCROLL_STATE_DRAGGING // swipe
|
||||||
|
|| holder.getBindingAdapterPosition() == mPager.getCurrentItem() // tab
|
||||||
|
) {
|
||||||
|
setCurrentCategoryId((int) getItemId(holder.getBindingAdapterPosition()), false);
|
||||||
|
updateState(getRecyclerView(holder.itemView), holder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewDetachedFromWindow(PagerViewHolder holder) {
|
||||||
|
if (holder.mCategoryId == EmojiCategory.ID_RECENTS) {
|
||||||
|
// Needs to save pending updates for recent keys when we get out of the recents
|
||||||
|
// category because we don't want to move the recent emojis around while the user
|
||||||
|
// is in the recents category.
|
||||||
|
getRecentsKeyboard().flushPendingRecentKeys();
|
||||||
|
getRecyclerView(holder.itemView).getAdapter().notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int position) {
|
||||||
|
return mEmojiCategory.getShownCategories().get(position).mCategoryId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RecyclerView getRecyclerView(View view) {
|
||||||
|
return view.findViewById(R.id.emoji_keyboard_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateState(@NonNull RecyclerView recyclerView, PagerViewHolder viewHolder) {
|
||||||
|
if (viewHolder.mCategoryId != mEmojiCategory.getCurrentCategoryId()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int offset = recyclerView.computeVerticalScrollOffset();
|
||||||
|
final int extent = recyclerView.computeVerticalScrollExtent();
|
||||||
|
final int range = recyclerView.computeVerticalScrollRange();
|
||||||
|
final float percentage = offset / (float) (range - extent);
|
||||||
|
|
||||||
|
final int currentCategorySize = mEmojiCategory.getCurrentCategoryPageCount();
|
||||||
|
final int a = (int) (percentage * currentCategorySize);
|
||||||
|
final float b = percentage * currentCategorySize - a;
|
||||||
|
mEmojiCategoryPageIndicatorView.setCategoryPageId(currentCategorySize, a, b);
|
||||||
|
|
||||||
|
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
|
||||||
|
final int firstCompleteVisibleBoard = layoutManager.findFirstCompletelyVisibleItemPosition();
|
||||||
|
final int firstVisibleBoard = layoutManager.findFirstVisibleItemPosition();
|
||||||
|
mEmojiCategory.setCurrentCategoryPageId(
|
||||||
|
firstCompleteVisibleBoard > 0 ? firstCompleteVisibleBoard : firstVisibleBoard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean initialized = false;
|
private boolean initialized = false;
|
||||||
private final Colors mColors;
|
private final Colors mColors;
|
||||||
private EmojiPalettesAdapter mEmojiPalettesAdapter;
|
|
||||||
private final EmojiLayoutParams mEmojiLayoutParams;
|
private final EmojiLayoutParams mEmojiLayoutParams;
|
||||||
private final LinearLayoutManager mEmojiLayoutManager;
|
|
||||||
|
|
||||||
private LinearLayout mTabStrip;
|
private LinearLayout mTabStrip;
|
||||||
private RecyclerView mEmojiRecyclerView;
|
|
||||||
private EmojiCategoryPageIndicatorView mEmojiCategoryPageIndicatorView;
|
private EmojiCategoryPageIndicatorView mEmojiCategoryPageIndicatorView;
|
||||||
|
|
||||||
private KeyboardActionListener mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER;
|
private KeyboardActionListener mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER;
|
||||||
|
|
||||||
private final EmojiCategory mEmojiCategory;
|
private final EmojiCategory mEmojiCategory;
|
||||||
|
private ViewPager2 mPager;
|
||||||
|
|
||||||
public EmojiPalettesView(final Context context, final AttributeSet attrs) {
|
public EmojiPalettesView(final Context context, final AttributeSet attrs) {
|
||||||
this(context, attrs, R.attr.emojiPalettesViewStyle);
|
this(context, attrs, R.attr.emojiPalettesViewStyle);
|
||||||
|
@ -91,7 +203,6 @@ public final class EmojiPalettesView extends LinearLayout
|
||||||
R.styleable.EmojiPalettesView, defStyle, R.style.EmojiPalettesView);
|
R.styleable.EmojiPalettesView, defStyle, R.style.EmojiPalettesView);
|
||||||
mEmojiCategory = new EmojiCategory(context, layoutSet, emojiPalettesViewAttr);
|
mEmojiCategory = new EmojiCategory(context, layoutSet, emojiPalettesViewAttr);
|
||||||
emojiPalettesViewAttr.recycle();
|
emojiPalettesViewAttr.recycle();
|
||||||
mEmojiLayoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false);
|
|
||||||
setFitsSystemWindows(true);
|
setFitsSystemWindows(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,47 +240,14 @@ public final class EmojiPalettesView extends LinearLayout
|
||||||
for (final EmojiCategory.CategoryProperties properties : mEmojiCategory.getShownCategories()) {
|
for (final EmojiCategory.CategoryProperties properties : mEmojiCategory.getShownCategories()) {
|
||||||
addTab(mTabStrip, properties.mCategoryId);
|
addTab(mTabStrip, properties.mCategoryId);
|
||||||
}
|
}
|
||||||
mEmojiPalettesAdapter = new EmojiPalettesAdapter(mEmojiCategory, this);
|
|
||||||
|
|
||||||
mEmojiRecyclerView = findViewById(R.id.emoji_keyboard_list);
|
|
||||||
mEmojiRecyclerView.setLayoutManager(mEmojiLayoutManager);
|
|
||||||
mEmojiRecyclerView.setAdapter(mEmojiPalettesAdapter);
|
|
||||||
mEmojiRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
|
||||||
@Override
|
|
||||||
public void onScrollStateChanged(@NonNull @NotNull RecyclerView recyclerView, int newState) {
|
|
||||||
super.onScrollStateChanged(recyclerView, newState);
|
|
||||||
// Ignore this message. Only want the actual page selected.
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onScrolled(@NonNull @NotNull RecyclerView recyclerView, int dx, int dy) {
|
|
||||||
super.onScrolled(recyclerView, dx, dy);
|
|
||||||
mEmojiPalettesAdapter.onPageScrolled();
|
|
||||||
|
|
||||||
final int offset = recyclerView.computeVerticalScrollOffset();
|
|
||||||
final int extent = recyclerView.computeVerticalScrollExtent();
|
|
||||||
final int range = recyclerView.computeVerticalScrollRange();
|
|
||||||
final float percentage = offset / (float) (range - extent);
|
|
||||||
|
|
||||||
final int currentCategorySize = mEmojiCategory.getCurrentCategoryPageCount();
|
|
||||||
final int a = (int) (percentage * currentCategorySize);
|
|
||||||
final float b = percentage * currentCategorySize - a;
|
|
||||||
mEmojiCategoryPageIndicatorView.setCategoryPageId(currentCategorySize, a, b);
|
|
||||||
|
|
||||||
final int firstCompleteVisibleBoard = mEmojiLayoutManager.findFirstCompletelyVisibleItemPosition();
|
|
||||||
final int firstVisibleBoard = mEmojiLayoutManager.findFirstVisibleItemPosition();
|
|
||||||
mEmojiCategory.setCurrentCategoryPageId(
|
|
||||||
firstCompleteVisibleBoard > 0 ? firstCompleteVisibleBoard : firstVisibleBoard);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mEmojiRecyclerView.setPersistentDrawingCache(PERSISTENT_NO_CACHE);
|
|
||||||
mEmojiLayoutParams.setEmojiListProperties(mEmojiRecyclerView);
|
|
||||||
|
|
||||||
|
mPager = findViewById(R.id.emoji_pager);
|
||||||
|
mPager.setAdapter(new PagerAdapter());
|
||||||
|
mEmojiLayoutParams.setEmojiListProperties(mPager);
|
||||||
mEmojiCategoryPageIndicatorView = findViewById(R.id.emoji_category_page_id_view);
|
mEmojiCategoryPageIndicatorView = findViewById(R.id.emoji_category_page_id_view);
|
||||||
mEmojiLayoutParams.setCategoryPageIdViewProperties(mEmojiCategoryPageIndicatorView);
|
mEmojiLayoutParams.setCategoryPageIdViewProperties(mEmojiCategoryPageIndicatorView);
|
||||||
|
|
||||||
setCurrentCategoryAndPageId(mEmojiCategory.getCurrentCategoryId(), mEmojiCategory.getCurrentCategoryPageId(), true);
|
setCurrentCategoryId(mEmojiCategory.getCurrentCategoryId(), true);
|
||||||
|
|
||||||
mEmojiCategoryPageIndicatorView.setColors(mColors.get(ColorType.EMOJI_CATEGORY_SELECTED), mColors.get(ColorType.STRIP_BACKGROUND));
|
mEmojiCategoryPageIndicatorView.setColors(mColors.get(ColorType.EMOJI_CATEGORY_SELECTED), mColors.get(ColorType.STRIP_BACKGROUND));
|
||||||
initialized = true;
|
initialized = true;
|
||||||
|
@ -187,7 +265,7 @@ public final class EmojiPalettesView extends LinearLayout
|
||||||
AudioAndHapticFeedbackManager.getInstance().performHapticAndAudioFeedback(KeyCode.NOT_SPECIFIED, this);
|
AudioAndHapticFeedbackManager.getInstance().performHapticAndAudioFeedback(KeyCode.NOT_SPECIFIED, this);
|
||||||
final int categoryId = ((Long) tag).intValue();
|
final int categoryId = ((Long) tag).intValue();
|
||||||
if (categoryId != mEmojiCategory.getCurrentCategoryId()) {
|
if (categoryId != mEmojiCategory.getCurrentCategoryId()) {
|
||||||
setCurrentCategoryAndPageId(categoryId, 0, false);
|
setCurrentCategoryId(categoryId, false);
|
||||||
updateEmojiCategoryPageIdView();
|
updateEmojiCategoryPageIdView();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -212,7 +290,7 @@ public final class EmojiPalettesView extends LinearLayout
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onReleaseKey(final Key key) {
|
public void onReleaseKey(final Key key) {
|
||||||
mEmojiPalettesAdapter.addRecentKey(key);
|
addRecentKey(key);
|
||||||
final int code = key.getCode();
|
final int code = key.getCode();
|
||||||
if (code == KeyCode.MULTIPLE_CODE_POINTS) {
|
if (code == KeyCode.MULTIPLE_CODE_POINTS) {
|
||||||
mKeyboardActionListener.onTextInput(key.getOutputText());
|
mKeyboardActionListener.onTextInput(key.getOutputText());
|
||||||
|
@ -237,13 +315,22 @@ public final class EmojiPalettesView extends LinearLayout
|
||||||
setupBottomRowKeyboard(editorInfo, keyboardActionListener);
|
setupBottomRowKeyboard(editorInfo, keyboardActionListener);
|
||||||
final KeyDrawParams params = new KeyDrawParams();
|
final KeyDrawParams params = new KeyDrawParams();
|
||||||
params.updateParams(mEmojiLayoutParams.getBottomRowKeyboardHeight(), keyVisualAttr);
|
params.updateParams(mEmojiLayoutParams.getBottomRowKeyboardHeight(), keyVisualAttr);
|
||||||
if (mEmojiRecyclerView.getAdapter() == null) {
|
|
||||||
mEmojiRecyclerView.setAdapter(mEmojiPalettesAdapter);
|
|
||||||
setCurrentCategoryAndPageId(mEmojiCategory.getCurrentCategoryId(), mEmojiCategory.getCurrentCategoryPageId(), true);
|
|
||||||
}
|
|
||||||
setupSidePadding();
|
setupSidePadding();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addRecentKey(final Key key) {
|
||||||
|
if (Settings.getValues().mIncognitoModeEnabled) {
|
||||||
|
// We do not want to log recent keys while being in incognito
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mEmojiCategory.isInRecentTab()) {
|
||||||
|
getRecentsKeyboard().addPendingKey(key);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getRecentsKeyboard().addKeyFirst(key);
|
||||||
|
mPager.getAdapter().notifyItemChanged(mEmojiCategory.getRecentTabId());
|
||||||
|
}
|
||||||
|
|
||||||
private void setupBottomRowKeyboard(final EditorInfo editorInfo, final KeyboardActionListener keyboardActionListener) {
|
private void setupBottomRowKeyboard(final EditorInfo editorInfo, final KeyboardActionListener keyboardActionListener) {
|
||||||
MainKeyboardView keyboardView = findViewById(R.id.bottom_row_keyboard);
|
MainKeyboardView keyboardView = findViewById(R.id.bottom_row_keyboard);
|
||||||
keyboardView.setKeyboardActionListener(keyboardActionListener);
|
keyboardView.setKeyboardActionListener(keyboardActionListener);
|
||||||
|
@ -263,11 +350,11 @@ public final class EmojiPalettesView extends LinearLayout
|
||||||
final float rightPadding = keyboardAttr.getFraction(R.styleable.Keyboard_keyboardRightPadding,
|
final float rightPadding = keyboardAttr.getFraction(R.styleable.Keyboard_keyboardRightPadding,
|
||||||
keyboardWidth, keyboardWidth, 0f) * sv.mSidePaddingScale;
|
keyboardWidth, keyboardWidth, 0f) * sv.mSidePaddingScale;
|
||||||
keyboardAttr.recycle();
|
keyboardAttr.recycle();
|
||||||
mEmojiRecyclerView.setPadding(
|
mPager.setPadding(
|
||||||
(int) leftPadding,
|
(int) leftPadding,
|
||||||
mEmojiRecyclerView.getPaddingTop(),
|
mPager.getPaddingTop(),
|
||||||
(int) rightPadding,
|
(int) rightPadding,
|
||||||
mEmojiRecyclerView.getPaddingBottom()
|
mPager.getPaddingBottom()
|
||||||
);
|
);
|
||||||
mEmojiCategoryPageIndicatorView.setPadding(
|
mEmojiCategoryPageIndicatorView.setPadding(
|
||||||
(int) leftPadding,
|
(int) leftPadding,
|
||||||
|
@ -280,9 +367,11 @@ public final class EmojiPalettesView extends LinearLayout
|
||||||
|
|
||||||
public void stopEmojiPalettes() {
|
public void stopEmojiPalettes() {
|
||||||
if (!initialized) return;
|
if (!initialized) return;
|
||||||
mEmojiPalettesAdapter.releaseCurrentKey(true);
|
getRecentsKeyboard().flushPendingRecentKeys();
|
||||||
mEmojiPalettesAdapter.flushPendingRecentKeys();
|
}
|
||||||
mEmojiRecyclerView.setAdapter(null);
|
|
||||||
|
private DynamicGridKeyboard getRecentsKeyboard() {
|
||||||
|
return mEmojiCategory.getKeyboard(EmojiCategory.ID_RECENTS, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setKeyboardActionListener(final KeyboardActionListener listener) {
|
public void setKeyboardActionListener(final KeyboardActionListener listener) {
|
||||||
|
@ -298,22 +387,15 @@ public final class EmojiPalettesView extends LinearLayout
|
||||||
mEmojiCategory.getCurrentCategoryPageId(), 0.0f);
|
mEmojiCategory.getCurrentCategoryPageId(), 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setCurrentCategoryAndPageId(final int categoryId, final int categoryPageId, final boolean force) {
|
private void setCurrentCategoryId(final int categoryId, final boolean initial) {
|
||||||
final int oldCategoryId = mEmojiCategory.getCurrentCategoryId();
|
final int oldCategoryId = mEmojiCategory.getCurrentCategoryId();
|
||||||
final int oldCategoryPageId = mEmojiCategory.getCurrentCategoryPageId();
|
if (initial || oldCategoryId != categoryId) {
|
||||||
|
|
||||||
if (oldCategoryId == EmojiCategory.ID_RECENTS && categoryId != EmojiCategory.ID_RECENTS) {
|
|
||||||
// Needs to save pending updates for recent keys when we get out of the recents
|
|
||||||
// category because we don't want to move the recent emojis around while the user
|
|
||||||
// is in the recents category.
|
|
||||||
mEmojiPalettesAdapter.flushPendingRecentKeys();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (force || oldCategoryId != categoryId || oldCategoryPageId != categoryPageId) {
|
|
||||||
mEmojiCategory.setCurrentCategoryId(categoryId);
|
mEmojiCategory.setCurrentCategoryId(categoryId);
|
||||||
mEmojiCategory.setCurrentCategoryPageId(categoryPageId);
|
|
||||||
mEmojiPalettesAdapter.notifyDataSetChanged();
|
if (mPager.getScrollState() != ViewPager2.SCROLL_STATE_DRAGGING) {
|
||||||
mEmojiRecyclerView.scrollToPosition(categoryPageId);
|
// Not swiping
|
||||||
|
mPager.setCurrentItem(mEmojiCategory.getTabIdFromCategoryId(
|
||||||
|
mEmojiCategory.getCurrentCategoryId()), ! initial);
|
||||||
}
|
}
|
||||||
|
|
||||||
final View old = mTabStrip.findViewWithTag((long) oldCategoryId);
|
final View old = mTabStrip.findViewWithTag((long) oldCategoryId);
|
||||||
|
@ -324,8 +406,14 @@ public final class EmojiPalettesView extends LinearLayout
|
||||||
if (current instanceof ImageView)
|
if (current instanceof ImageView)
|
||||||
Settings.getValues().mColors.setColor((ImageView) current, ColorType.EMOJI_CATEGORY_SELECTED);
|
Settings.getValues().mColors.setColor((ImageView) current, ColorType.EMOJI_CATEGORY_SELECTED);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void clearKeyboardCache() {
|
public void clearKeyboardCache() {
|
||||||
|
if (!initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mEmojiCategory.clearKeyboardCache();
|
mEmojiCategory.clearKeyboardCache();
|
||||||
|
mPager.getAdapter().notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2022,8 +2022,10 @@ public class LatinIME extends InputMethodService implements
|
||||||
public void onTrimMemory(int level) {
|
public void onTrimMemory(int level) {
|
||||||
super.onTrimMemory(level);
|
super.onTrimMemory(level);
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case TRIM_MEMORY_RUNNING_LOW, TRIM_MEMORY_RUNNING_CRITICAL, TRIM_MEMORY_COMPLETE ->
|
case TRIM_MEMORY_RUNNING_LOW, TRIM_MEMORY_RUNNING_CRITICAL, TRIM_MEMORY_COMPLETE -> {
|
||||||
KeyboardLayoutSet.onSystemLocaleChanged(); // clears caches, nothing else
|
KeyboardLayoutSet.onSystemLocaleChanged(); // clears caches, nothing else
|
||||||
|
mKeyboardSwitcher.trimMemory();
|
||||||
|
}
|
||||||
// deallocateMemory always called on hiding, and should not be called when showing
|
// deallocateMemory always called on hiding, and should not be called when showing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
20
app/src/main/res/layout/emoji_category_view.xml
Normal file
20
app/src/main/res/layout/emoji_category_view.xml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright (C) 2013 The Android Open Source Project
|
||||||
|
modified
|
||||||
|
SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only
|
||||||
|
-->
|
||||||
|
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
style="?attr/emojiPalettesViewStyle">
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/emoji_keyboard_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
android:orientation="vertical" />
|
||||||
|
</FrameLayout>
|
|
@ -15,11 +15,10 @@
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
style="?attr/emojiPalettesViewStyle"
|
style="?attr/emojiPalettesViewStyle"
|
||||||
>
|
>
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.viewpager2.widget.ViewPager2
|
||||||
android:id="@+id/emoji_keyboard_list"
|
android:id="@+id/emoji_pager"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content" />
|
||||||
android:orientation="vertical" />
|
|
||||||
<helium314.keyboard.keyboard.emoji.EmojiCategoryPageIndicatorView
|
<helium314.keyboard.keyboard.emoji.EmojiCategoryPageIndicatorView
|
||||||
android:id="@+id/emoji_category_page_id_view"
|
android:id="@+id/emoji_category_page_id_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue