Allow for switching between emoji categories using swipe left/right (#1488)

This commit is contained in:
Eran Leshem 2025-05-18 20:18:23 +03:00 committed by GitHub
parent 199f177c2d
commit 731c6cdd5e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 217 additions and 252 deletions

View file

@ -107,6 +107,7 @@ dependencies {
implementation("androidx.core:core-ktx:1.16.0")
implementation("androidx.recyclerview:recyclerview:1.4.0")
implementation("androidx.autofill:autofill:1.1.0")
implementation("androidx.viewpager2:viewpager2:1.1.0")
// kotlin
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.1")

View file

@ -479,7 +479,6 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
if (mKeyboardViewWrapper.getOneHandedModeEnabled() == enabled) {
return;
}
mEmojiPalettesView.clearKeyboardCache();
final Settings settings = Settings.getInstance();
mKeyboardViewWrapper.setOneHandedModeEnabled(enabled);
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")
public View onCreateInputView(@NonNull Context displayContext, final boolean isHardwareAcceleratedDrawingEnabled) {
if (mKeyboardView != null) {

View file

@ -261,20 +261,6 @@ final class EmojiCategory {
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() {
return getTabIdFromCategoryId(EmojiCategory.ID_RECENTS);
}
@ -285,11 +271,11 @@ final class EmojiCategory {
}
// Returns a keyboard from the recycler view's adapter position.
public DynamicGridKeyboard getKeyboardFromAdapterPosition(final int position) {
if (position >= 0 && position < getCurrentCategoryPageCount()) {
return getKeyboard(mCurrentCategoryId, position);
public DynamicGridKeyboard getKeyboardFromAdapterPosition(int categoryId, final int position) {
if (position >= 0 && position < getCategoryPageCount(categoryId)) {
return getKeyboard(categoryId, position);
}
Log.w(TAG, "invalid position for categoryId : " + mCurrentCategoryId);
Log.w(TAG, "invalid position for categoryId : " + categoryId);
return null;
}

View file

@ -8,7 +8,7 @@ package helium314.keyboard.keyboard.emoji
import android.content.res.Resources
import android.view.View
import android.widget.LinearLayout
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import helium314.keyboard.keyboard.internal.KeyboardParams
import helium314.keyboard.latin.R
import helium314.keyboard.latin.settings.Settings
@ -47,7 +47,7 @@ internal class EmojiLayoutParams(res: Resources) {
emojiKeyboardHeight = emojiListHeight - emojiCategoryPageIdViewHeight - emojiListBottomMargin
}
fun setEmojiListProperties(vp: RecyclerView) {
fun setEmojiListProperties(vp: ViewPager2) {
val lp = vp.layoutParams as LinearLayout.LayoutParams
lp.height = emojiKeyboardHeight
lp.bottomMargin = emojiListBottomMargin

View file

@ -12,156 +12,32 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import helium314.keyboard.keyboard.Key;
import helium314.keyboard.keyboard.Keyboard;
import helium314.keyboard.keyboard.KeyboardView;
import helium314.keyboard.latin.R;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import helium314.keyboard.latin.settings.Settings;
final class EmojiPalettesAdapter extends RecyclerView.Adapter<EmojiPalettesAdapter.ViewHolder>{
private static final String TAG = EmojiPalettesAdapter.class.getSimpleName();
private static final boolean DEBUG_PAGER = false;
private final int mCategoryId;
private final OnKeyEventListener mListener;
private final DynamicGridKeyboard mRecentsKeyboard;
private final SparseArray<EmojiPageKeyboardView> mActiveKeyboardViews = new SparseArray<>();
private final EmojiCategory mEmojiCategory;
private int mActivePosition = 0;
public EmojiPalettesAdapter(final EmojiCategory emojiCategory,
final OnKeyEventListener listener) {
public EmojiPalettesAdapter(final EmojiCategory emojiCategory, int categoryId, final OnKeyEventListener listener) {
mEmojiCategory = emojiCategory;
mCategoryId = categoryId;
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
@Override
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 EmojiPageKeyboardView keyboardView = (EmojiPageKeyboardView)inflater.inflate(
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);
}
@ -170,33 +46,22 @@ final class EmojiPalettesAdapter extends RecyclerView.Adapter<EmojiPalettesAdapt
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.getKeyboardFromAdapterPosition(position);
mEmojiCategory.getKeyboardFromAdapterPosition(mCategoryId, position);
holder.getKeyboardView().setKeyboard(keyboard);
holder.getKeyboardView().setOnKeyEventListener(mListener);
//parent.addView(keyboardView);
mActiveKeyboardViews.put(position, holder.getKeyboardView());
}
/*if (mActivePosition == position) {
return;
}
final EmojiPageKeyboardView oldKeyboardView = mActiveKeyboardViews.get(mActivePosition);
if (oldKeyboardView != null) {
oldKeyboardView.releaseCurrentKey(false);
oldKeyboardView.deallocateMemory();
}
mActivePosition = position;*/
@Override
public void onViewDetachedFromWindow(@NonNull ViewHolder holder) {
holder.getKeyboardView().releaseCurrentKey(false);
holder.getKeyboardView().deallocateMemory();
}
@Override
public int getItemCount() {
return mEmojiCategory.getCurrentCategoryPageCount();
return mEmojiCategory.getCategoryPageCount(mCategoryId);
}
static class ViewHolder extends RecyclerView.ViewHolder {
@ -210,7 +75,6 @@ final class EmojiPalettesAdapter extends RecyclerView.Adapter<EmojiPalettesAdapt
public EmojiPageKeyboardView getKeyboardView() {
return customView;
}
}
}

View file

@ -11,6 +11,7 @@ import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
@ -20,6 +21,7 @@ import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.ViewPager2;
import helium314.keyboard.keyboard.Key;
import helium314.keyboard.keyboard.Keyboard;
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.utils.ResourceUtils;
import org.jetbrains.annotations.NotNull;
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
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 final Colors mColors;
private EmojiPalettesAdapter mEmojiPalettesAdapter;
private final EmojiLayoutParams mEmojiLayoutParams;
private final LinearLayoutManager mEmojiLayoutManager;
private LinearLayout mTabStrip;
private RecyclerView mEmojiRecyclerView;
private EmojiCategoryPageIndicatorView mEmojiCategoryPageIndicatorView;
private KeyboardActionListener mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER;
private final EmojiCategory mEmojiCategory;
private ViewPager2 mPager;
public EmojiPalettesView(final Context context, final AttributeSet attrs) {
this(context, attrs, R.attr.emojiPalettesViewStyle);
@ -91,7 +203,6 @@ public final class EmojiPalettesView extends LinearLayout
R.styleable.EmojiPalettesView, defStyle, R.style.EmojiPalettesView);
mEmojiCategory = new EmojiCategory(context, layoutSet, emojiPalettesViewAttr);
emojiPalettesViewAttr.recycle();
mEmojiLayoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false);
setFitsSystemWindows(true);
}
@ -129,47 +240,14 @@ public final class EmojiPalettesView extends LinearLayout
for (final EmojiCategory.CategoryProperties properties : mEmojiCategory.getShownCategories()) {
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);
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));
initialized = true;
@ -187,7 +265,7 @@ public final class EmojiPalettesView extends LinearLayout
AudioAndHapticFeedbackManager.getInstance().performHapticAndAudioFeedback(KeyCode.NOT_SPECIFIED, this);
final int categoryId = ((Long) tag).intValue();
if (categoryId != mEmojiCategory.getCurrentCategoryId()) {
setCurrentCategoryAndPageId(categoryId, 0, false);
setCurrentCategoryId(categoryId, false);
updateEmojiCategoryPageIdView();
}
}
@ -212,7 +290,7 @@ public final class EmojiPalettesView extends LinearLayout
*/
@Override
public void onReleaseKey(final Key key) {
mEmojiPalettesAdapter.addRecentKey(key);
addRecentKey(key);
final int code = key.getCode();
if (code == KeyCode.MULTIPLE_CODE_POINTS) {
mKeyboardActionListener.onTextInput(key.getOutputText());
@ -237,13 +315,22 @@ public final class EmojiPalettesView extends LinearLayout
setupBottomRowKeyboard(editorInfo, keyboardActionListener);
final KeyDrawParams params = new KeyDrawParams();
params.updateParams(mEmojiLayoutParams.getBottomRowKeyboardHeight(), keyVisualAttr);
if (mEmojiRecyclerView.getAdapter() == null) {
mEmojiRecyclerView.setAdapter(mEmojiPalettesAdapter);
setCurrentCategoryAndPageId(mEmojiCategory.getCurrentCategoryId(), mEmojiCategory.getCurrentCategoryPageId(), true);
}
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) {
MainKeyboardView keyboardView = findViewById(R.id.bottom_row_keyboard);
keyboardView.setKeyboardActionListener(keyboardActionListener);
@ -263,11 +350,11 @@ public final class EmojiPalettesView extends LinearLayout
final float rightPadding = keyboardAttr.getFraction(R.styleable.Keyboard_keyboardRightPadding,
keyboardWidth, keyboardWidth, 0f) * sv.mSidePaddingScale;
keyboardAttr.recycle();
mEmojiRecyclerView.setPadding(
mPager.setPadding(
(int) leftPadding,
mEmojiRecyclerView.getPaddingTop(),
mPager.getPaddingTop(),
(int) rightPadding,
mEmojiRecyclerView.getPaddingBottom()
mPager.getPaddingBottom()
);
mEmojiCategoryPageIndicatorView.setPadding(
(int) leftPadding,
@ -280,9 +367,11 @@ public final class EmojiPalettesView extends LinearLayout
public void stopEmojiPalettes() {
if (!initialized) return;
mEmojiPalettesAdapter.releaseCurrentKey(true);
mEmojiPalettesAdapter.flushPendingRecentKeys();
mEmojiRecyclerView.setAdapter(null);
getRecentsKeyboard().flushPendingRecentKeys();
}
private DynamicGridKeyboard getRecentsKeyboard() {
return mEmojiCategory.getKeyboard(EmojiCategory.ID_RECENTS, 0);
}
public void setKeyboardActionListener(final KeyboardActionListener listener) {
@ -298,22 +387,15 @@ public final class EmojiPalettesView extends LinearLayout
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 oldCategoryPageId = mEmojiCategory.getCurrentCategoryPageId();
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) {
if (initial || oldCategoryId != categoryId) {
mEmojiCategory.setCurrentCategoryId(categoryId);
mEmojiCategory.setCurrentCategoryPageId(categoryPageId);
mEmojiPalettesAdapter.notifyDataSetChanged();
mEmojiRecyclerView.scrollToPosition(categoryPageId);
if (mPager.getScrollState() != ViewPager2.SCROLL_STATE_DRAGGING) {
// Not swiping
mPager.setCurrentItem(mEmojiCategory.getTabIdFromCategoryId(
mEmojiCategory.getCurrentCategoryId()), ! initial);
}
final View old = mTabStrip.findViewWithTag((long) oldCategoryId);
@ -324,8 +406,14 @@ public final class EmojiPalettesView extends LinearLayout
if (current instanceof ImageView)
Settings.getValues().mColors.setColor((ImageView) current, ColorType.EMOJI_CATEGORY_SELECTED);
}
}
public void clearKeyboardCache() {
if (!initialized) {
return;
}
mEmojiCategory.clearKeyboardCache();
mPager.getAdapter().notifyDataSetChanged();
}
}

View file

@ -2022,8 +2022,10 @@ public class LatinIME extends InputMethodService implements
public void onTrimMemory(int level) {
super.onTrimMemory(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
mKeyboardSwitcher.trimMemory();
}
// deallocateMemory always called on hiding, and should not be called when showing
}
}

View 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>

View file

@ -15,11 +15,10 @@
android:background="@android:color/transparent"
style="?attr/emojiPalettesViewStyle"
>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/emoji_keyboard_list"
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/emoji_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
android:layout_height="wrap_content" />
<helium314.keyboard.keyboard.emoji.EmojiCategoryPageIndicatorView
android:id="@+id/emoji_category_page_id_view"
android:layout_width="match_parent"