package org.telegram.ui.Components; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.content.Context; import android.content.res.Configuration; import android.graphics.Canvas; import android.graphics.Paint; import android.util.LongSparseArray; import android.util.SparseArray; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import androidx.annotation.NonNull; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaDataController; import org.telegram.messenger.MessageObject; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.AdjustPanLayoutHelper; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Adapters.StickersSearchAdapter; import org.telegram.ui.Cells.EmptyCell; import org.telegram.ui.Cells.FeaturedStickerSetCell2; import org.telegram.ui.Cells.FeaturedStickerSetInfoCell; import org.telegram.ui.Cells.GraySectionCell; import org.telegram.ui.Cells.StickerEmojiCell; import java.util.ArrayList; import java.util.HashMap; import java.util.List; public class TrendingStickersLayout extends FrameLayout implements NotificationCenter.NotificationCenterDelegate { public abstract static class Delegate { private String[] lastSearchKeyboardLanguage = new String[0]; public void onStickerSetAdd(TLRPC.StickerSetCovered stickerSet, boolean primary) { } public void onStickerSetRemove(TLRPC.StickerSetCovered stickerSet) { } public boolean onListViewInterceptTouchEvent(RecyclerListView listView, MotionEvent event) { return false; } public boolean onListViewTouchEvent(RecyclerListView listView, RecyclerListView.OnItemClickListener onItemClickListener, MotionEvent event) { return false; } public String[] getLastSearchKeyboardLanguage() { return lastSearchKeyboardLanguage; } public void setLastSearchKeyboardLanguage(String[] language) { lastSearchKeyboardLanguage = language; } public boolean canSendSticker() { return false; } public void onStickerSelected(TLRPC.Document sticker, Object parent, boolean clearsInputField, boolean notify, int scheduleDate) { } public boolean canSchedule() { return false; } public boolean isInScheduleMode() { return false; } } private final int currentAccount = UserConfig.selectedAccount; private final Delegate delegate; private final TLRPC.StickerSetCovered[] primaryInstallingStickerSets; private final LongSparseArray installingStickerSets; private final LongSparseArray removingStickerSets; private final View shadowView; private final SearchField searchView; private final RecyclerListView listView; private final GridLayoutManager layoutManager; private final TrendingStickersAdapter adapter; private final StickersSearchAdapter searchAdapter; private final FrameLayout searchLayout; private BaseFragment parentFragment; private RecyclerListView.OnScrollListener onScrollListener; private int topOffset; private boolean motionEventCatchedByListView; private boolean shadowVisible; private boolean ignoreLayout; private boolean wasLayout; private boolean loaded; private long hash; ValueAnimator glueToTopAnimator; private boolean gluedToTop; private boolean scrollFromAnimator; private TLRPC.StickerSetCovered scrollToSet; private final Theme.ResourcesProvider resourcesProvider; public TrendingStickersLayout(@NonNull Context context, Delegate delegate) { this(context, delegate, new TLRPC.StickerSetCovered[10], new LongSparseArray<>(), new LongSparseArray<>(), null, null); } public TrendingStickersLayout(@NonNull Context context, Delegate delegate, TLRPC.StickerSetCovered[] primaryInstallingStickerSets, LongSparseArray installingStickerSets, LongSparseArray removingStickerSets, TLRPC.StickerSetCovered scrollToSet, Theme.ResourcesProvider resourcesProvider) { super(context); this.delegate = delegate; this.primaryInstallingStickerSets = primaryInstallingStickerSets; this.installingStickerSets = installingStickerSets; this.removingStickerSets = removingStickerSets; this.scrollToSet = scrollToSet; this.resourcesProvider = resourcesProvider; this.adapter = new TrendingStickersAdapter(context); final StickersSearchAdapter.Delegate searchAdapterDelegate = new StickersSearchAdapter.Delegate() { @Override public void onSearchStart() { searchView.getProgressDrawable().startAnimation(); } @Override public void onSearchStop() { searchView.getProgressDrawable().stopAnimation(); } @Override public void setAdapterVisible(boolean visible) { boolean changed = false; if (visible && listView.getAdapter() != searchAdapter) { listView.setAdapter(searchAdapter); changed = true; } else if (!visible && listView.getAdapter() != adapter) { listView.setAdapter(adapter); changed = true; } if (changed && listView.getAdapter().getItemCount() > 0) { layoutManager.scrollToPositionWithOffset(0, -listView.getPaddingTop() + AndroidUtilities.dp(58) + topOffset, false); } } @Override public void onStickerSetAdd(TLRPC.StickerSetCovered stickerSet, boolean primary) { delegate.onStickerSetAdd(stickerSet, primary); } @Override public void onStickerSetRemove(TLRPC.StickerSetCovered stickerSet) { delegate.onStickerSetRemove(stickerSet); } @Override public int getStickersPerRow() { return adapter.stickersPerRow; } @Override public String[] getLastSearchKeyboardLanguage() { return delegate.getLastSearchKeyboardLanguage(); } @Override public void setLastSearchKeyboardLanguage(String[] language) { delegate.setLastSearchKeyboardLanguage(language); } }; searchAdapter = new StickersSearchAdapter(context, searchAdapterDelegate, primaryInstallingStickerSets, installingStickerSets, removingStickerSets, resourcesProvider); searchLayout = new FrameLayout(context); searchLayout.setBackgroundColor(getThemedColor(Theme.key_dialogBackground)); searchView = new SearchField(context, true, resourcesProvider) { @Override public void onTextChange(String text) { searchAdapter.search(text); } }; searchView.setHint(LocaleController.getString("SearchTrendingStickersHint", R.string.SearchTrendingStickersHint)); searchLayout.addView(searchView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP)); listView = new RecyclerListView(context) { @Override public boolean onInterceptTouchEvent(MotionEvent event) { boolean result = delegate.onListViewInterceptTouchEvent(this, event); return super.onInterceptTouchEvent(event) || result; } @Override public boolean dispatchTouchEvent(MotionEvent ev) { motionEventCatchedByListView = true; return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent e) { if (glueToTopAnimator != null) { return false; } return super.onTouchEvent(e); } @Override public void requestLayout() { if (!ignoreLayout) { super.requestLayout(); } } @Override protected boolean allowSelectChildAtPosition(float x, float y) { return y >= topOffset + AndroidUtilities.dp(58); } }; final RecyclerListView.OnItemClickListener trendingOnItemClickListener = (view, position) -> { final TLRPC.StickerSetCovered pack; if (listView.getAdapter() == searchAdapter) { pack = searchAdapter.getSetForPosition(position); } else { if (position < adapter.totalItems) { pack = adapter.positionsToSets.get(position); } else { pack = null; } } if (pack != null) { showStickerSet(pack.set); } }; listView.setOnTouchListener((v, event) -> delegate.onListViewTouchEvent(listView, trendingOnItemClickListener, event)); listView.setOverScrollMode(View.OVER_SCROLL_NEVER); listView.setClipToPadding(false); listView.setItemAnimator(null); listView.setLayoutAnimation(null); listView.setLayoutManager(layoutManager = new FillLastGridLayoutManager(context, 5, AndroidUtilities.dp(58), listView) { @Override public boolean supportsPredictiveItemAnimations() { return false; } @Override protected boolean isLayoutRTL() { return LocaleController.isRTL; } @Override protected boolean shouldCalcLastItemHeight() { return listView.getAdapter() == searchAdapter; } @Override public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) { if (scrollFromAnimator) { return super.scrollVerticallyBy(dy, recycler, state); } if (glueToTopAnimator != null) { return 0; } if (gluedToTop) { int minPosition = 1; for (int i = 0; i < getChildCount(); i++) { int p = listView.getChildAdapterPosition(getChildAt(i)); if (p < minPosition) { minPosition = p; break; } } if (minPosition == 0) { View minView = layoutManager.findViewByPosition(minPosition); if (minView != null && minView.getTop() - dy > AndroidUtilities.dp(58)) { dy = minView.getTop() - AndroidUtilities.dp(58); } } } return super.scrollVerticallyBy(dy, recycler, state); } }); layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { if (listView.getAdapter() == adapter) { if (adapter.cache.get(position) instanceof Integer || position >= adapter.totalItems) { return adapter.stickersPerRow; } return 1; } else { return searchAdapter.getSpanSize(position); } } }); listView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { if (onScrollListener != null) { onScrollListener.onScrolled(listView, dx, dy); } if (dy > 0 && listView.getAdapter() == adapter && loaded && !adapter.loadingMore && !adapter.endReached) { final int threshold = (adapter.stickersPerRow + 1) * 10; if (layoutManager.findLastVisibleItemPosition() >= adapter.getItemCount() - threshold - 1) { adapter.loadMoreStickerSets(); } } } @Override public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { if (onScrollListener != null) { onScrollListener.onScrollStateChanged(recyclerView, newState); } } }); listView.setAdapter(adapter); listView.setOnItemClickListener(trendingOnItemClickListener); addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 0)); shadowView = new View(context); shadowView.setBackgroundColor(getThemedColor(Theme.key_dialogShadowLine)); shadowView.setAlpha(0.0f); final FrameLayout.LayoutParams shadowViewParams = new FrameLayout.LayoutParams(LayoutHelper.MATCH_PARENT, AndroidUtilities.getShadowHeight()); shadowViewParams.topMargin = AndroidUtilities.dp(58); addView(shadowView, shadowViewParams); addView(searchLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 58, Gravity.LEFT | Gravity.TOP)); updateColors(); final NotificationCenter notificationCenter = NotificationCenter.getInstance(currentAccount); notificationCenter.addObserver(this, NotificationCenter.stickersDidLoad); notificationCenter.addObserver(this, NotificationCenter.featuredStickersDidLoad); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); if (!wasLayout) { wasLayout = true; adapter.refreshStickerSets(); if (scrollToSet != null) { Integer pos = adapter.setsToPosition.get(scrollToSet); if (pos != null) { layoutManager.scrollToPositionWithOffset(pos, -listView.getPaddingTop() + AndroidUtilities.dp(58)); } } } } private float highlightProgress = 1f; Paint paint = new Paint(); @Override protected void dispatchDraw(Canvas canvas) { if (highlightProgress != 0 && scrollToSet != null) { highlightProgress -= 16f / 3000f; if (highlightProgress < 0) { highlightProgress = 0; } else { invalidate(); } Integer pos = adapter.setsToPosition.get(scrollToSet); if (pos != null) { View view1 = layoutManager.findViewByPosition(pos); int t = -1, b = -1; if (view1 != null) { t = (int) view1.getY(); b = (int) view1.getY() + view1.getMeasuredHeight(); } View view2 = layoutManager.findViewByPosition(pos + 1); if (view2 != null) { if (view1 == null) { t = (int) view2.getY(); } b = (int) view2.getY() + view2.getMeasuredHeight(); } if (view1 != null || view2 != null) { paint.setColor(Theme.getColor(Theme.key_featuredStickers_addButton)); float p = highlightProgress < 0.06f ? highlightProgress / 0.06f : 1f; paint.setAlpha((int) (255 * 0.1f * p)); canvas.drawRect(0, t, getMeasuredWidth(), b, paint); } } } super.dispatchDraw(canvas); } @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); updateLastItemInAdapter(); wasLayout = false; } @Override public boolean dispatchTouchEvent(MotionEvent ev) { motionEventCatchedByListView = false; boolean result = super.dispatchTouchEvent(ev); if (!motionEventCatchedByListView) { MotionEvent e = MotionEvent.obtain(ev); listView.dispatchTouchEvent(e); e.recycle(); } return result; } private void showStickerSet(TLRPC.StickerSet pack) { showStickerSet(pack, null); } public void showStickerSet(TLRPC.StickerSet pack, TLRPC.InputStickerSet inputStickerSet) { if (pack != null) { inputStickerSet = new TLRPC.TL_inputStickerSetID(); inputStickerSet.access_hash = pack.access_hash; inputStickerSet.id = pack.id; } if (inputStickerSet != null) { showStickerSet(inputStickerSet); } } private void showStickerSet(TLRPC.InputStickerSet inputStickerSet) { final StickersAlert.StickersAlertDelegate stickersAlertDelegate; if (delegate.canSendSticker()) { stickersAlertDelegate = new StickersAlert.StickersAlertDelegate() { @Override public void onStickerSelected(TLRPC.Document sticker, String query, Object parent, MessageObject.SendAnimationData sendAnimationData, boolean clearsInputField, boolean notify, int scheduleDate) { delegate.onStickerSelected(sticker, parent, clearsInputField, notify, scheduleDate); } @Override public boolean canSchedule() { return delegate.canSchedule(); } @Override public boolean isInScheduleMode() { return delegate.isInScheduleMode(); } }; } else { stickersAlertDelegate = null; } final StickersAlert stickersAlert = new StickersAlert(getContext(), parentFragment, inputStickerSet, null, stickersAlertDelegate, resourcesProvider); stickersAlert.setShowTooltipWhenToggle(false); stickersAlert.setInstallDelegate(new StickersAlert.StickersAlertInstallDelegate() { @Override public void onStickerSetInstalled() { if (listView.getAdapter() == adapter) { for (int i = 0; i < adapter.sets.size(); i++) { final TLRPC.StickerSetCovered setCovered = adapter.sets.get(i); if (setCovered.set.id == inputStickerSet.id) { adapter.installStickerSet(setCovered, null); break; } } } else { searchAdapter.installStickerSet(inputStickerSet); } } @Override public void onStickerSetUninstalled() { } }); parentFragment.showDialog(stickersAlert); } public void recycle() { final NotificationCenter notificationCenter = NotificationCenter.getInstance(currentAccount); notificationCenter.removeObserver(this, NotificationCenter.stickersDidLoad); notificationCenter.removeObserver(this, NotificationCenter.featuredStickersDidLoad); } @Override public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.stickersDidLoad) { if ((Integer) args[0] == MediaDataController.TYPE_IMAGE) { if (loaded) { updateVisibleTrendingSets(); } else { adapter.refreshStickerSets(); } } } else if (id == NotificationCenter.featuredStickersDidLoad) { if (hash != MediaDataController.getInstance(currentAccount).getFeaturedStickersHashWithoutUnread(false)) { loaded = false; } if (loaded) { updateVisibleTrendingSets(); } else { adapter.refreshStickerSets(); } } } public void setOnScrollListener(RecyclerListView.OnScrollListener onScrollListener) { this.onScrollListener = onScrollListener; } public void setParentFragment(BaseFragment parentFragment) { this.parentFragment = parentFragment; } public void setContentViewPaddingTop(int paddingTop) { paddingTop += AndroidUtilities.dp(58); if (listView.getPaddingTop() != paddingTop) { ignoreLayout = true; listView.setPadding(0, paddingTop, 0, 0); ignoreLayout = false; } } private void updateLastItemInAdapter() { final RecyclerView.Adapter adapter = listView.getAdapter(); adapter.notifyItemChanged(adapter.getItemCount() - 1); } public int getContentTopOffset() { return topOffset; } public boolean update() { if (listView.getChildCount() <= 0) { topOffset = listView.getPaddingTop(); listView.setTopGlowOffset(topOffset); searchLayout.setTranslationY(topOffset); shadowView.setTranslationY(topOffset); setShadowVisible(false); return true; } View child = listView.getChildAt(0); for (int i = 1; i < listView.getChildCount(); i++) { View view = listView.getChildAt(i); if (view.getTop() < child.getTop()) { child = view; } } RecyclerListView.Holder holder = (RecyclerListView.Holder) listView.findContainingViewHolder(child); int top = child.getTop() - AndroidUtilities.dp(58); int newOffset = top > 0 && holder != null && holder.getAdapterPosition() == 0 ? top : 0; setShadowVisible(top < 0); if (topOffset != newOffset) { topOffset = newOffset; listView.setTopGlowOffset(topOffset + AndroidUtilities.dp(58)); searchLayout.setTranslationY(topOffset); shadowView.setTranslationY(topOffset); return true; } return false; } private void updateVisibleTrendingSets() { final RecyclerListView.Adapter listAdapter = listView.getAdapter(); if (listAdapter != null) { listAdapter.notifyItemRangeChanged(0, listAdapter.getItemCount(), listAdapter == adapter ? TrendingStickersAdapter.PAYLOAD_ANIMATED : StickersSearchAdapter.PAYLOAD_ANIMATED); } } private void setShadowVisible(boolean visible) { if (shadowVisible != visible) { shadowVisible = visible; shadowView.animate().alpha(visible ? 1f : 0f).setDuration(200).start(); } } public void updateColors() { if (listView.getAdapter() == adapter) { adapter.updateColors(listView); } else { searchAdapter.updateColors(listView); } } public void getThemeDescriptions(List descriptions, ThemeDescription.ThemeDescriptionDelegate delegate) { searchView.getThemeDescriptions(descriptions); adapter.getThemeDescriptions(descriptions, listView, delegate); searchAdapter.getThemeDescriptions(descriptions, listView, delegate); descriptions.add(new ThemeDescription(shadowView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_dialogShadowLine)); descriptions.add(new ThemeDescription(searchLayout, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_dialogBackground)); } public void glueToTop(boolean glue) { gluedToTop = glue; if (glue) { if (getContentTopOffset() > 0 && glueToTopAnimator == null) { int startFrom = getContentTopOffset(); glueToTopAnimator = ValueAnimator.ofFloat(0, 1f); glueToTopAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { int dy = 0; @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { int currentDy = (int) (startFrom * (float) valueAnimator.getAnimatedValue()); scrollFromAnimator = true; listView.scrollBy(0, currentDy - dy); scrollFromAnimator = false; dy = currentDy; } }); glueToTopAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { glueToTopAnimator = null; } }); glueToTopAnimator.setDuration(AdjustPanLayoutHelper.keyboardDuration); glueToTopAnimator.setInterpolator(AdjustPanLayoutHelper.keyboardInterpolator); glueToTopAnimator.start(); } } else { if (glueToTopAnimator != null) { glueToTopAnimator.removeAllListeners(); glueToTopAnimator.cancel(); glueToTopAnimator = null; } } } private class TrendingStickersAdapter extends RecyclerListView.SelectionAdapter { public static final int PAYLOAD_ANIMATED = 0; private static final int ITEM_SECTION = -1; private final Context context; private final SparseArray cache = new SparseArray<>(); private final ArrayList sets = new ArrayList<>(); private final SparseArray positionsToSets = new SparseArray<>(); private final HashMap setsToPosition = new HashMap<>(); private final ArrayList otherPacks = new ArrayList<>(); private boolean loadingMore; private boolean endReached; private int stickersPerRow = 5; private int totalItems; public TrendingStickersAdapter(Context context) { this.context = context; } @Override public int getItemCount() { return totalItems + 1; } @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { return holder.getItemViewType() == 5; } @Override public int getItemViewType(int position) { if (position == getItemCount() - 1) { return 3; // fill view } Object object = cache.get(position); if (object != null) { if (object instanceof TLRPC.Document) { return 0; // sticker cell } else if (object.equals(ITEM_SECTION)) { return 4; // section cell } else { return 2; // set info cell } } return 1; // empty cell } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = null; switch (viewType) { case 0: StickerEmojiCell stickerCell = new StickerEmojiCell(context, false) { public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(82), MeasureSpec.EXACTLY)); } }; stickerCell.getImageView().setLayerNum(3); view = stickerCell; break; case 1: view = new EmptyCell(context); break; case 2: view = new FeaturedStickerSetInfoCell(context, 17, true, true, resourcesProvider); ((FeaturedStickerSetInfoCell) view).setAddOnClickListener(v -> { final FeaturedStickerSetInfoCell cell = (FeaturedStickerSetInfoCell) v.getParent(); TLRPC.StickerSetCovered pack = cell.getStickerSet(); if (installingStickerSets.indexOfKey(pack.set.id) >= 0 || removingStickerSets.indexOfKey(pack.set.id) >= 0) { return; } if (cell.isInstalled()) { removingStickerSets.put(pack.set.id, pack); delegate.onStickerSetRemove(pack); } else { installStickerSet(pack, cell); } }); break; case 3: view = new View(context); break; case 4: view = new GraySectionCell(context, resourcesProvider); break; case 5: final FeaturedStickerSetCell2 stickerSetCell = new FeaturedStickerSetCell2(context, resourcesProvider); stickerSetCell.setAddOnClickListener(v -> { final FeaturedStickerSetCell2 cell = (FeaturedStickerSetCell2) v.getParent(); TLRPC.StickerSetCovered pack = cell.getStickerSet(); if (installingStickerSets.indexOfKey(pack.set.id) >= 0 || removingStickerSets.indexOfKey(pack.set.id) >= 0) { return; } if (cell.isInstalled()) { removingStickerSets.put(pack.set.id, pack); delegate.onStickerSetRemove(pack); } else { installStickerSet(pack, cell); } }); stickerSetCell.getImageView().setLayerNum(3); view = stickerSetCell; break; } return new RecyclerListView.Holder(view); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (holder.getItemViewType()) { case 0: TLRPC.Document sticker = (TLRPC.Document) cache.get(position); ((StickerEmojiCell) holder.itemView).setSticker(sticker, positionsToSets.get(position), false); break; case 1: ((EmptyCell) holder.itemView).setHeight(AndroidUtilities.dp(82)); break; case 2: case 5: bindStickerSetCell(holder.itemView, position, false); break; case 4: ((GraySectionCell) holder.itemView).setText(LocaleController.getString("OtherStickers", R.string.OtherStickers)); break; } } @SuppressWarnings("unchecked") @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position, @NonNull List payloads) { if (payloads.contains(PAYLOAD_ANIMATED)) { final int type = holder.getItemViewType(); if (type == 2 || type == 5) { bindStickerSetCell(holder.itemView, position, true); } } else { super.onBindViewHolder(holder, position, payloads); } } private void bindStickerSetCell(View view, int position, boolean animated) { final MediaDataController mediaDataController = MediaDataController.getInstance(currentAccount); boolean unread = false; final TLRPC.StickerSetCovered stickerSetCovered; if (position < totalItems) { stickerSetCovered = sets.get((Integer) cache.get(position)); final ArrayList unreadStickers = mediaDataController.getUnreadStickerSets(); unread = unreadStickers != null && unreadStickers.contains(stickerSetCovered.set.id); if (unread) { mediaDataController.markFeaturedStickersByIdAsRead(false, stickerSetCovered.set.id); } } else { stickerSetCovered = sets.get((Integer) cache.get(position)); } mediaDataController.preloadStickerSetThumb(stickerSetCovered); boolean forceInstalled = false; for (int i = 0; i < primaryInstallingStickerSets.length; i++) { if (primaryInstallingStickerSets[i] != null) { final TLRPC.TL_messages_stickerSet s = MediaDataController.getInstance(currentAccount).getStickerSetById(primaryInstallingStickerSets[i].set.id); if (s != null && !s.set.archived) { primaryInstallingStickerSets[i] = null; continue; } if (primaryInstallingStickerSets[i].set.id == stickerSetCovered.set.id) { forceInstalled = true; break; } } } final boolean isSetInstalled = mediaDataController.isStickerPackInstalled(stickerSetCovered.set.id); boolean installing = installingStickerSets.indexOfKey(stickerSetCovered.set.id) >= 0; boolean removing = removingStickerSets.indexOfKey(stickerSetCovered.set.id) >= 0; if (installing && isSetInstalled) { installingStickerSets.remove(stickerSetCovered.set.id); installing = false; } else if (removing && !isSetInstalled) { removingStickerSets.remove(stickerSetCovered.set.id); } final FeaturedStickerSetInfoCell cell = (FeaturedStickerSetInfoCell) view; cell.setStickerSet(stickerSetCovered, unread, animated, 0, 0, forceInstalled); cell.setAddDrawProgress(!forceInstalled && installing, animated); cell.setNeedDivider(position > 0 && (cache.get(position - 1) == null || !cache.get(position - 1).equals(ITEM_SECTION))); } private void installStickerSet(TLRPC.StickerSetCovered pack, View view) { for (int i = 0; i < primaryInstallingStickerSets.length; i++) { if (primaryInstallingStickerSets[i] != null) { final TLRPC.TL_messages_stickerSet s = MediaDataController.getInstance(currentAccount).getStickerSetById(primaryInstallingStickerSets[i].set.id); if (s != null && !s.set.archived) { primaryInstallingStickerSets[i] = null; break; } if (primaryInstallingStickerSets[i].set.id == pack.set.id) { return; } } } boolean primary = false; for (int i = 0; i < primaryInstallingStickerSets.length; i++) { if (primaryInstallingStickerSets[i] == null) { primaryInstallingStickerSets[i] = pack; primary = true; break; } } if (!primary && view != null) { if (view instanceof FeaturedStickerSetCell2) { ((FeaturedStickerSetCell2) view).setDrawProgress(true, true); } else if (view instanceof FeaturedStickerSetInfoCell) { ((FeaturedStickerSetInfoCell) view).setAddDrawProgress(true, true); } } installingStickerSets.put(pack.set.id, pack); if (view != null) { delegate.onStickerSetAdd(pack, primary); } else { for (int i = 0, size = positionsToSets.size(); i < size; i++) { final TLRPC.StickerSetCovered item = positionsToSets.get(i); if (item != null && item.set.id == pack.set.id) { notifyItemChanged(i, PAYLOAD_ANIMATED); break; } } } } public void refreshStickerSets() { int width = getMeasuredWidth(); if (width != 0) { stickersPerRow = Math.max(5, width / AndroidUtilities.dp(72)); if (layoutManager.getSpanCount() != stickersPerRow) { layoutManager.setSpanCount(stickersPerRow); loaded = false; } } if (loaded) { return; } cache.clear(); positionsToSets.clear(); setsToPosition.clear(); sets.clear(); totalItems = 0; int num = 0; final MediaDataController mediaDataController = MediaDataController.getInstance(currentAccount); ArrayList packs = new ArrayList<>(mediaDataController.getFeaturedStickerSets()); final int otherStickersSectionPosition = packs.size(); packs.addAll(otherPacks); for (int a = 0; a < packs.size(); a++) { TLRPC.StickerSetCovered pack = packs.get(a); if (pack.covers.isEmpty() && pack.cover == null) { continue; } if (a == otherStickersSectionPosition) { cache.put(totalItems++, ITEM_SECTION); } sets.add(pack); positionsToSets.put(totalItems, pack); setsToPosition.put(pack, totalItems); cache.put(totalItems++, num++); int count; if (!pack.covers.isEmpty()) { count = (int) Math.ceil(pack.covers.size() / (float) stickersPerRow); for (int b = 0; b < pack.covers.size(); b++) { cache.put(b + totalItems, pack.covers.get(b)); } } else { count = 1; cache.put(totalItems, pack.cover); } for (int b = 0; b < count * stickersPerRow; b++) { positionsToSets.put(totalItems + b, pack); } totalItems += count * stickersPerRow; } if (totalItems != 0) { loaded = true; hash = mediaDataController.getFeaturedStickersHashWithoutUnread(false); } notifyDataSetChanged(); } public void loadMoreStickerSets() { if (!loaded || loadingMore || endReached) { return; } loadingMore = true; final TLRPC.TL_messages_getOldFeaturedStickers req = new TLRPC.TL_messages_getOldFeaturedStickers(); req.offset = otherPacks.size(); req.limit = 40; ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { loadingMore = false; if (error == null && response instanceof TLRPC.TL_messages_featuredStickers) { final TLRPC.TL_messages_featuredStickers stickersResponse = (TLRPC.TL_messages_featuredStickers) response; final List packs = stickersResponse.sets; if (packs.size() < 40) { endReached = true; } if (!packs.isEmpty()) { if (otherPacks.isEmpty()) { cache.put(totalItems++, ITEM_SECTION); } otherPacks.addAll(packs); int num = sets.size(); for (int a = 0; a < packs.size(); a++) { TLRPC.StickerSetCovered pack = packs.get(a); if (pack.covers.isEmpty() && pack.cover == null) { continue; } sets.add(pack); positionsToSets.put(totalItems, pack); cache.put(totalItems++, num++); int count; if (!pack.covers.isEmpty()) { count = (int) Math.ceil(pack.covers.size() / (float) stickersPerRow); for (int b = 0; b < pack.covers.size(); b++) { cache.put(b + totalItems, pack.covers.get(b)); } } else { count = 1; cache.put(totalItems, pack.cover); } for (int b = 0; b < count * stickersPerRow; b++) { positionsToSets.put(totalItems + b, pack); } totalItems += count * stickersPerRow; } notifyDataSetChanged(); } } else { endReached = true; } })); } public void updateColors(RecyclerListView listView) { for (int i = 0, size = listView.getChildCount(); i < size; i++) { final View child = listView.getChildAt(i); if (child instanceof FeaturedStickerSetInfoCell) { ((FeaturedStickerSetInfoCell) child).updateColors(); } else if (child instanceof FeaturedStickerSetCell2) { ((FeaturedStickerSetCell2) child).updateColors(); } } } public void getThemeDescriptions(List descriptions, RecyclerListView listView, ThemeDescription.ThemeDescriptionDelegate delegate) { FeaturedStickerSetInfoCell.createThemeDescriptions(descriptions, listView, delegate); FeaturedStickerSetCell2.createThemeDescriptions(descriptions, listView, delegate); GraySectionCell.createThemeDescriptions(descriptions, listView); } } private int getThemedColor(String key) { Integer color = resourcesProvider != null ? resourcesProvider.getColor(key) : null; return color != null ? color : Theme.getColor(key); } }