NekoX/TMessagesProj/src/main/java/org/telegram/ui/Cells/AppIconsSelectorCell.java

351 lines
14 KiB
Java

package org.telegram.ui.Cells;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.Spannable;
import android.text.SpannableString;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.ColorUtils;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.LinearSmoothScroller;
import androidx.recyclerview.widget.RecyclerView;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.MessagesController;
import org.telegram.messenger.NotificationCenter;
import org.telegram.messenger.R;
import org.telegram.messenger.UserConfig;
import org.telegram.ui.ActionBar.BaseFragment;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.Components.Bulletin;
import org.telegram.ui.Components.ColoredImageSpan;
import org.telegram.ui.Components.Easings;
import org.telegram.ui.Components.LayoutHelper;
import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet;
import org.telegram.ui.Components.RecyclerListView;
import org.telegram.ui.LauncherIconController;
import org.telegram.ui.PremiumPreviewFragment;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class AppIconsSelectorCell extends RecyclerListView implements NotificationCenter.NotificationCenterDelegate {
public final static float ICONS_ROUND_RADIUS = 18;
private List<LauncherIconController.LauncherIcon> availableIcons = new ArrayList<>();
private LinearLayoutManager linearLayoutManager;
private int currentAccount;
public AppIconsSelectorCell(Context context, BaseFragment fragment, int currentAccount) {
super(context);
this.currentAccount = currentAccount;
setPadding(0, AndroidUtilities.dp(12), 0, AndroidUtilities.dp(12));
setFocusable(false);
setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite));
setItemAnimator(null);
setLayoutAnimation(null);
setLayoutManager(linearLayoutManager = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false));
setAdapter(new Adapter() {
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new RecyclerListView.Holder(new IconHolderView(parent.getContext()));
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
IconHolderView holderView = (IconHolderView) holder.itemView;
LauncherIconController.LauncherIcon icon = availableIcons.get(position);
holderView.bind(icon);
holderView.iconView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(ICONS_ROUND_RADIUS), Color.TRANSPARENT, Theme.getColor(Theme.key_listSelector), Color.BLACK));
holderView.iconView.setForeground(icon.foreground);
holderView.iconView.setIsNekoXIcon(icon.isNekoX());
}
@Override
public int getItemCount() {
return availableIcons.size();
}
});
addItemDecoration(new ItemDecoration() {
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull State state) {
int pos = parent.getChildViewHolder(view).getAdapterPosition();
if (pos == 0) {
outRect.left = AndroidUtilities.dp(18);
}
if (pos == getAdapter().getItemCount() - 1) {
outRect.right = AndroidUtilities.dp(18);
} else {
int itemCount = getAdapter().getItemCount();
if (itemCount == 4) {
outRect.right = (getWidth() - AndroidUtilities.dp(36) - AndroidUtilities.dp(58) * itemCount) / (itemCount - 1);
} else {
outRect.right = AndroidUtilities.dp(24);
}
}
}
});
setOnItemClickListener((view, position) -> {
IconHolderView holderView = (IconHolderView) view;
LauncherIconController.LauncherIcon icon = availableIcons.get(position);
if (icon.premium && !UserConfig.hasPremiumOnAccounts()) {
fragment.showDialog(new PremiumFeatureBottomSheet(fragment, PremiumPreviewFragment.PREMIUM_FEATURE_APPLICATION_ICONS, true));
return;
}
if (LauncherIconController.isEnabled(icon)) {
return;
}
LinearSmoothScroller smoothScroller = new LinearSmoothScroller(context) {
@Override
public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) {
return boxStart - viewStart + AndroidUtilities.dp(16);
}
@Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return super.calculateSpeedPerPixel(displayMetrics) * 3f;
}
};
smoothScroller.setTargetPosition(position);
linearLayoutManager.startSmoothScroll(smoothScroller);
LauncherIconController.setIcon(icon);
holderView.setSelected(true, true);
for (int i = 0; i < getChildCount(); i++) {
IconHolderView otherView = (IconHolderView) getChildAt(i);
if (otherView != holderView) {
otherView.setSelected(false, true);
}
}
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.showBulletin, Bulletin.TYPE_APP_ICON, icon);
});
updateIconsVisibility();
}
@SuppressLint("NotifyDataSetChanged")
private void updateIconsVisibility() {
availableIcons.clear();
availableIcons.addAll(Arrays.asList(LauncherIconController.LauncherIcon.values()));
if (MessagesController.getInstance(currentAccount).premiumLocked) {
for (int i = 0; i < availableIcons.size(); i++) {
if (availableIcons.get(i).premium) {
availableIcons.remove(i);
i--;
}
}
}
getAdapter().notifyDataSetChanged();
invalidateItemDecorations();
for (int i = 0; i < availableIcons.size(); i++) {
LauncherIconController.LauncherIcon icon = availableIcons.get(i);
if (LauncherIconController.isEnabled(icon)) {
linearLayoutManager.scrollToPositionWithOffset(i, AndroidUtilities.dp(16));
break;
}
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
invalidateItemDecorations();
}
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthSpec), MeasureSpec.EXACTLY), heightSpec);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.premiumStatusChangedGlobal);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.premiumStatusChangedGlobal);
}
@Override
public void didReceivedNotification(int id, int account, Object... args) {
if (id == NotificationCenter.premiumStatusChangedGlobal) {
updateIconsVisibility();
}
}
private final static class IconHolderView extends LinearLayout {
private Paint outlinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private AdaptiveIconImageView iconView;
private TextView titleView;
private float progress;
private IconHolderView(@NonNull Context context) {
super(context);
setOrientation(VERTICAL);
setWillNotDraw(false);
iconView = new AdaptiveIconImageView(context);
iconView.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8));
addView(iconView, LayoutHelper.createLinear(58, 58, Gravity.CENTER_HORIZONTAL));
titleView = new TextView(context);
titleView.setSingleLine();
titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13);
titleView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
addView(titleView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 4, 0, 0));
outlinePaint.setStyle(Paint.Style.STROKE);
outlinePaint.setStrokeWidth(Math.max(2, AndroidUtilities.dp(0.5f)));
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
float stroke = outlinePaint.getStrokeWidth();
AndroidUtilities.rectTmp.set(iconView.getLeft() + stroke, iconView.getTop() + stroke, iconView.getRight() - stroke, iconView.getBottom() - stroke);
canvas.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(ICONS_ROUND_RADIUS), AndroidUtilities.dp(ICONS_ROUND_RADIUS), outlinePaint);
}
private void setProgress(float progress) {
this.progress = progress;
titleView.setTextColor(ColorUtils.blendARGB(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText), Theme.getColor(Theme.key_windowBackgroundWhiteValueText), progress));
outlinePaint.setColor(ColorUtils.blendARGB(ColorUtils.setAlphaComponent(Theme.getColor(Theme.key_switchTrack), 0x3F), Theme.getColor(Theme.key_windowBackgroundWhiteValueText), progress));
outlinePaint.setStrokeWidth(Math.max(2, AndroidUtilities.dp(AndroidUtilities.lerp(0.5f, 2f, progress))));
invalidate();
}
private void setSelected(boolean selected, boolean animate) {
float to = selected ? 1 : 0;
if (to == progress && animate) {
return;
}
if (animate) {
ValueAnimator animator = ValueAnimator.ofFloat(progress, to).setDuration(250);
animator.setInterpolator(Easings.easeInOutQuad);
animator.addUpdateListener(animation -> setProgress((Float) animation.getAnimatedValue()));
animator.start();
} else {
setProgress(to);
}
}
private void bind(LauncherIconController.LauncherIcon icon) {
iconView.setImageResource(icon.background);
MarginLayoutParams params = (MarginLayoutParams) titleView.getLayoutParams();
if (icon.premium && !UserConfig.hasPremiumOnAccounts()) {
SpannableString str = new SpannableString("d " + LocaleController.getString(icon.title));
ColoredImageSpan span = new ColoredImageSpan(R.drawable.msg_mini_premiumlock);
span.setTopOffset(1);
span.setSize(AndroidUtilities.dp(13));
str.setSpan(span, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
params.rightMargin = AndroidUtilities.dp(4);
titleView.setText(str);
} else {
params.rightMargin = 0;
titleView.setText(LocaleController.getString(icon.title));
}
setSelected(LauncherIconController.isEnabled(icon), false);
}
}
public static class AdaptiveIconImageView extends ImageView {
private boolean isNekoXIcon = false;
private Drawable foreground;
private Path path = new Path();
private int outerPadding = AndroidUtilities.dp(5);
private int backgroundOuterPadding = AndroidUtilities.dp(42);
public AdaptiveIconImageView(Context context) {
super(context);
}
public void setForeground(int res) {
foreground = ContextCompat.getDrawable(getContext(), res);
invalidate();
}
public void setIsNekoXIcon(boolean value) {
this.isNekoXIcon = value;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
updatePath();
}
public void setPadding(int padding) {
setPadding(padding, padding, padding, padding);
}
public void setOuterPadding(int outerPadding) {
this.outerPadding = outerPadding;
}
public void setBackgroundOuterPadding(int backgroundOuterPadding) {
this.backgroundOuterPadding = backgroundOuterPadding;
}
@Override
public void draw(Canvas canvas) {
canvas.save();
canvas.clipPath(path);
if (!this.isNekoXIcon)
canvas.scale(1f + backgroundOuterPadding / (float) getWidth(), 1f + backgroundOuterPadding / (float) getHeight(), getWidth() / 2f, getHeight() / 2f);
super.draw(canvas);
canvas.restore();
if (foreground != null && !this.isNekoXIcon) {
foreground.setBounds(-outerPadding, -outerPadding, getWidth() + outerPadding, getHeight() + outerPadding);
foreground.draw(canvas);
}
}
private void updatePath() {
path.rewind();
path.addCircle(getWidth() / 2f, getHeight() / 2f, Math.min(getWidth() - getPaddingLeft() - getPaddingRight(), getHeight() - getPaddingTop() - getPaddingBottom()) / 2f, Path.Direction.CW);
}
}
}