NekoX/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatThemeBottomSheet.java

1065 lines
49 KiB
Java
Raw Normal View History

2021-09-20 07:54:41 +02:00
package org.telegram.ui.Components;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.OvershootInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.LinearSmoothScroller;
import androidx.recyclerview.widget.RecyclerView;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.ChatThemeController;
import org.telegram.messenger.Emoji;
import org.telegram.messenger.ImageLocation;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.MediaDataController;
import org.telegram.messenger.MessagesController;
import org.telegram.messenger.NotificationCenter;
import org.telegram.messenger.R;
import org.telegram.messenger.SharedConfig;
import org.telegram.tgnet.ResultCallback;
import org.telegram.tgnet.TLRPC;
import org.telegram.ui.ActionBar.AlertDialog;
import org.telegram.ui.ActionBar.BottomSheet;
import org.telegram.ui.ActionBar.ChatTheme;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.ActionBar.ThemeDescription;
import org.telegram.ui.ChatActivity;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
public class ChatThemeBottomSheet extends BottomSheet implements NotificationCenter.NotificationCenterDelegate {
private final Adapter adapter;
private final ChatActivity.ThemeDelegate themeDelegate;
private final ChatTheme originalTheme;
private final boolean originalIsDark;
private final ChatActivity chatActivity;
private final RecyclerListView recyclerView;
private final LinearLayoutManager layoutManager;
private final FlickerLoadingView progressView;
private final TextView titleView;
private final RLottieDrawable darkThemeDrawable;
private final RLottieImageView darkThemeView;
private final LinearSmoothScroller scroller;
private final View applyButton;
private TextView applyTextView;
private TextView resetTextView;
private ChatThemeItem selectedItem;
private boolean forceDark;
private boolean isApplyClicked;
private boolean isLightDarkChangeAnimation;
private int prevSelectedPosition = -1;
private View changeDayNightView;
private float changeDayNightViewProgress;
private ValueAnimator changeDayNightViewAnimator;
HintView hintView;
public ChatThemeBottomSheet(final ChatActivity chatActivity, ChatActivity.ThemeDelegate themeDelegate) {
super(chatActivity.getParentActivity(), true, themeDelegate);
this.chatActivity = chatActivity;
this.themeDelegate = themeDelegate;
this.originalTheme = themeDelegate.getCurrentTheme();
this.originalIsDark = Theme.getActiveTheme().isDark();
adapter = new Adapter(themeDelegate);
setDimBehind(false);
setCanDismissWithSwipe(false);
setApplyBottomPadding(false);
FrameLayout rootLayout = new FrameLayout(getContext());
setCustomView(rootLayout);
titleView = new TextView(getContext());
titleView.setEllipsize(TextUtils.TruncateAt.MIDDLE);
titleView.setLines(1);
titleView.setSingleLine(true);
titleView.setText(LocaleController.getString("SelectTheme", R.string.SelectTheme));
titleView.setTextColor(getThemedColor(Theme.key_dialogTextBlack));
titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20);
titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
titleView.setPadding(AndroidUtilities.dp(21), AndroidUtilities.dp(6), AndroidUtilities.dp(21), AndroidUtilities.dp(8));
rootLayout.addView(titleView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.START, 0, 0, 62, 0));
int drawableColor = getThemedColor(Theme.key_featuredStickers_addButton);
int drawableSize = AndroidUtilities.dp(28);
darkThemeDrawable = new RLottieDrawable(R.raw.sun_outline, "" + R.raw.sun_outline, drawableSize, drawableSize, true, null);
darkThemeDrawable.setPlayInDirectionOfCustomEndFrame(true);
darkThemeDrawable.beginApplyLayerColors();
setDarkButtonColor(drawableColor);
darkThemeDrawable.commitApplyLayerColors();
darkThemeView = new RLottieImageView(getContext());
darkThemeView.setAnimation(darkThemeDrawable);
darkThemeView.setScaleType(ImageView.ScaleType.CENTER);
darkThemeView.setOnClickListener(view -> {
if (changeDayNightViewAnimator != null) {
return;
}
setupLightDarkTheme(!forceDark);
});
rootLayout.addView(darkThemeView, LayoutHelper.createFrame(44, 44, Gravity.TOP | Gravity.END, 0, 0, 7, 0));
forceDark = !Theme.getActiveTheme().isDark();
setForceDark(Theme.getActiveTheme().isDark(), false);
scroller = new LinearSmoothScroller(getContext()) {
@Override
protected int calculateTimeForScrolling(int dx) {
return super.calculateTimeForScrolling(dx) * 6;
}
};
recyclerView = new RecyclerListView(getContext());
recyclerView.setAdapter(adapter);
recyclerView.setClipChildren(false);
recyclerView.setClipToPadding(false);
recyclerView.setHasFixedSize(true);
recyclerView.setItemAnimator(null);
recyclerView.setNestedScrollingEnabled(false);
recyclerView.setLayoutManager(layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false));
recyclerView.setPadding(AndroidUtilities.dp(12), 0, AndroidUtilities.dp(12), 0);
recyclerView.setOnItemClickListener((view, position) -> {
2021-09-21 11:51:08 +02:00
if (adapter.items.get(position) == selectedItem || changeDayNightView != null) {
2021-09-20 07:54:41 +02:00
return;
}
selectedItem = adapter.items.get(position);
isLightDarkChangeAnimation = false;
if (selectedItem.chatTheme == null || selectedItem.chatTheme.isDefault) {
applyTextView.animate().alpha(0f).setDuration(300).start();
resetTextView.animate().alpha(1f).setDuration(300).start();
} else {
resetTextView.animate().alpha(0f).setDuration(300).start();
applyTextView.animate().alpha(1f).setDuration(300).start();
}
if (selectedItem.chatTheme.isDefault) {
themeDelegate.setCurrentTheme(null, true, forceDark);
} else {
themeDelegate.setCurrentTheme(selectedItem.chatTheme, true, forceDark);
}
adapter.setSelectedItem(position);
containerView.postDelayed(new Runnable() {
@Override
public void run() {
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
if (layoutManager != null) {
final int targetPosition = position > prevSelectedPosition
? Math.min(position + 1, adapter.items.size() - 1)
: Math.max(position - 1, 0);
scroller.setTargetPosition(targetPosition);
layoutManager.startSmoothScroll(scroller);
}
prevSelectedPosition = position;
}
}, 100);
for (int i = 0; i < recyclerView.getChildCount(); i++) {
Adapter.ChatThemeView child = (Adapter.ChatThemeView) recyclerView.getChildAt(i);
if (child != view) {
child.cancelAnimation();
}
}
if (!adapter.items.get(position).chatTheme.isDefault) {
((Adapter.ChatThemeView) view).playEmojiAnimation();
}
});
progressView = new FlickerLoadingView(getContext(), resourcesProvider);
progressView.setViewType(FlickerLoadingView.CHAT_THEMES_TYPE);
progressView.setVisibility(View.VISIBLE);
rootLayout.addView(progressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 104, Gravity.START, 0, 44, 0, 0));
rootLayout.addView(recyclerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 104, Gravity.START, 0, 44, 0, 0));
applyButton = new View(getContext());
applyButton.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(6), getThemedColor(Theme.key_featuredStickers_addButton), getThemedColor(Theme.key_featuredStickers_addButtonPressed)));
applyButton.setEnabled(false);
applyButton.setOnClickListener((view) -> applySelectedTheme());
rootLayout.addView(applyButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.START, 16, 162, 16, 16));
resetTextView = new TextView(getContext());
resetTextView.setAlpha(0f);
resetTextView.setEllipsize(TextUtils.TruncateAt.END);
resetTextView.setGravity(Gravity.CENTER);
resetTextView.setLines(1);
resetTextView.setSingleLine(true);
resetTextView.setText(themeDelegate.getCurrentTheme() == null ? LocaleController.getString("DoNoSetTheme", R.string.DoNoSetTheme) : LocaleController.getString("ChatResetTheme", R.string.ChatResetTheme));
resetTextView.setTextColor(getThemedColor(Theme.key_featuredStickers_buttonText));
resetTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
resetTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
resetTextView.setVisibility(View.INVISIBLE);
rootLayout.addView(resetTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.START, 16, 162, 16, 16));
applyTextView = new TextView(getContext());
applyTextView.setEllipsize(TextUtils.TruncateAt.END);
applyTextView.setGravity(Gravity.CENTER);
applyTextView.setLines(1);
applyTextView.setSingleLine(true);
applyTextView.setText(LocaleController.getString("ChatApplyTheme", R.string.ChatApplyTheme));
applyTextView.setTextColor(getThemedColor(Theme.key_featuredStickers_buttonText));
applyTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
applyTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
applyTextView.setVisibility(View.INVISIBLE);
rootLayout.addView(applyTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.START, 16, 162, 16, 16));
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ChatThemeController.preloadAllWallpaperThumbs(true);
ChatThemeController.preloadAllWallpaperThumbs(false);
ChatThemeController.preloadAllWallpaperImages(true);
ChatThemeController.preloadAllWallpaperImages(false);
NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.emojiLoaded);
isApplyClicked = false;
List<ChatTheme> cachedThemes = themeDelegate.getCachedThemes();
if (cachedThemes == null || cachedThemes.isEmpty()) {
ChatThemeController.requestAllChatThemes(new ResultCallback<List<ChatTheme>>() {
@Override
public void onComplete(List<ChatTheme> result) {
if (result != null && !result.isEmpty()) {
themeDelegate.setCachedThemes(result);
}
onDataLoaded(result);
}
@Override
public void onError(TLRPC.TL_error error) {
Toast.makeText(getContext(), error.text, Toast.LENGTH_SHORT).show();
}
}, true);
} else {
onDataLoaded(cachedThemes);
}
if (chatActivity.getCurrentUser() != null && SharedConfig.dayNightThemeSwitchHintCount > 0) {
SharedConfig.updateDayNightThemeSwitchHintCount(SharedConfig.dayNightThemeSwitchHintCount - 1);
hintView = new HintView(getContext(), 9, chatActivity.getResourceProvider());
hintView.setVisibility(View.INVISIBLE);
hintView.setShowingDuration(5000);
hintView.setBottomOffset(-AndroidUtilities.dp(8));
hintView.setText(AndroidUtilities.replaceTags(LocaleController.formatString("ChatThemeDayNightSwitchTooltip", R.string.ChatThemeDayNightSwitchTooltip, chatActivity.getCurrentUser().first_name)));
AndroidUtilities.runOnUIThread(() -> {
hintView.showForView(darkThemeView, true);
}, 1500);
container.addView(hintView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 10, 0, 10, 0));
}
}
@Override
public void onContainerTranslationYChanged(float y) {
if (hintView != null) {
hintView.hide();
}
}
@Override
public void onBackPressed() {
close();
}
@Override
public void dismiss() {
NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.emojiLoaded);
super.dismiss();
if (!isApplyClicked) {
themeDelegate.setCurrentTheme(originalTheme, true, originalIsDark);
}
}
public void close() {
if (hasChanges()) {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext(), resourcesProvider);
builder.setTitle(LocaleController.getString("ChatThemeSaveDialogTitle", R.string.ChatThemeSaveDialogTitle));
builder.setSubtitle(LocaleController.getString("ChatThemeSaveDialogText", R.string.ChatThemeSaveDialogText));
builder.setPositiveButton(LocaleController.getString("ChatThemeSaveDialogApply", R.string.ChatThemeSaveDialogApply), (dialogInterface, i) -> applySelectedTheme());
builder.setNegativeButton(LocaleController.getString("ChatThemeSaveDialogDiscard", R.string.ChatThemeSaveDialogDiscard), (dialogInterface, i) -> dismiss());
builder.show();
} else {
dismiss();
}
}
@SuppressLint("NotifyDataSetChanged")
@Override
public void didReceivedNotification(int id, int account, Object... args) {
if (id == NotificationCenter.emojiLoaded) {
adapter.notifyDataSetChanged();
}
}
@Override
public ArrayList<ThemeDescription> getThemeDescriptions() {
ThemeDescription.ThemeDescriptionDelegate descriptionDelegate = new ThemeDescription.ThemeDescriptionDelegate() {
private boolean isAnimationStarted = false;
@Override
public void onAnimationProgress(float progress) {
if (progress == 0f && !isAnimationStarted) {
onAnimationStart();
isAnimationStarted = true;
}
setDarkButtonColor(getThemedColor(Theme.key_featuredStickers_addButton));
setOverlayNavBarColor(getThemedColor(Theme.key_dialogBackground));
if (isLightDarkChangeAnimation) {
setItemsAnimationProgress(progress);
}
if (progress == 1f && isAnimationStarted) {
isLightDarkChangeAnimation = false;
onAnimationEnd();
isAnimationStarted = false;
}
}
@Override
public void didSetColor() {
}
};
ArrayList<ThemeDescription> themeDescriptions = new ArrayList<>();
themeDescriptions.add(new ThemeDescription(null, ThemeDescription.FLAG_BACKGROUNDFILTER, null, null, new Drawable[]{shadowDrawable}, descriptionDelegate, Theme.key_dialogBackground));
themeDescriptions.add(new ThemeDescription(titleView, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_dialogTextBlack));
themeDescriptions.add(new ThemeDescription(recyclerView, ThemeDescription.FLAG_CELLBACKGROUNDCOLOR, new Class[]{Adapter.ChatThemeView.class}, null, null, null, Theme.key_dialogBackgroundGray));
themeDescriptions.add(new ThemeDescription(applyButton, ThemeDescription.FLAG_BACKGROUNDFILTER, null, null, null, null, Theme.key_featuredStickers_addButton));
themeDescriptions.add(new ThemeDescription(applyButton, ThemeDescription.FLAG_BACKGROUNDFILTER | ThemeDescription.FLAG_DRAWABLESELECTEDSTATE, null, null, null, null, Theme.key_featuredStickers_addButtonPressed));
for (ThemeDescription description : themeDescriptions) {
description.resourcesProvider = themeDelegate;
}
return themeDescriptions;
}
@SuppressLint("NotifyDataSetChanged")
public void setupLightDarkTheme(boolean isDark) {
if (changeDayNightViewAnimator != null) {
changeDayNightViewAnimator.cancel();
}
FrameLayout decorView1 = (FrameLayout) chatActivity.getParentActivity().getWindow().getDecorView();
FrameLayout decorView2 = (FrameLayout) getWindow().getDecorView();
Bitmap bitmap = Bitmap.createBitmap(decorView2.getWidth(), decorView2.getHeight(), Bitmap.Config.ARGB_8888);
Canvas bitmapCanvas = new Canvas(bitmap);
darkThemeView.setAlpha(0f);
decorView1.draw(bitmapCanvas);
decorView2.draw(bitmapCanvas);
darkThemeView.setAlpha(1f);
Paint xRefPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
xRefPaint.setColor(0xff000000);
xRefPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
Paint bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
bitmapPaint.setFilterBitmap(true);
int[] position = new int[2];
darkThemeView.getLocationInWindow(position);
float x = position[0];
float y = position[1];
float cx = x + darkThemeView.getMeasuredWidth() / 2f;
float cy = y + darkThemeView.getMeasuredHeight() / 2f;
float r = Math.max(bitmap.getHeight(), bitmap.getWidth()) * 0.9f;
Shader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
bitmapPaint.setShader(bitmapShader);
changeDayNightView = new View(getContext()) {
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isDark) {
if (changeDayNightViewProgress > 0f) {
bitmapCanvas.drawCircle(cx, cy, r * changeDayNightViewProgress, xRefPaint);
}
canvas.drawBitmap(bitmap, 0, 0, bitmapPaint);
} else {
canvas.drawCircle(cx, cy, r * (1f - changeDayNightViewProgress), bitmapPaint);
}
canvas.save();
canvas.translate(x, y);
darkThemeView.draw(canvas);
canvas.restore();
}
};
changeDayNightViewProgress = 0f;
changeDayNightViewAnimator = ValueAnimator.ofFloat(0, 1f);
changeDayNightViewAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
changeDayNightViewProgress = (float) valueAnimator.getAnimatedValue();
changeDayNightView.invalidate();
}
});
changeDayNightViewAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (changeDayNightView != null) {
if (changeDayNightView.getParent() != null) {
((ViewGroup) changeDayNightView.getParent()).removeView(changeDayNightView);
}
changeDayNightView = null;
}
changeDayNightViewAnimator = null;
super.onAnimationEnd(animation);
}
});
changeDayNightViewAnimator.setDuration(400);
changeDayNightViewAnimator.setInterpolator(Easings.easeInOutQuad);
changeDayNightViewAnimator.start();
decorView2.addView(changeDayNightView, new ViewGroup.LayoutParams(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
AndroidUtilities.runOnUIThread(() -> {
if (adapter == null || adapter.items == null) {
return;
}
setForceDark(isDark, true);
if (selectedItem != null) {
isLightDarkChangeAnimation = true;
if (selectedItem.chatTheme.isDefault) {
themeDelegate.setCurrentTheme(null, false, isDark);
} else {
themeDelegate.setCurrentTheme(selectedItem.chatTheme, false, isDark);
}
}
if (adapter != null && adapter.items != null) {
for (int i = 0; i < adapter.items.size(); i++) {
adapter.items.get(i).isDark = isDark;
}
adapter.notifyDataSetChanged();
}
});
}
@Override
protected boolean onContainerTouchEvent(MotionEvent event) {
if (event == null || !hasChanges()) {
return false;
}
int x = (int) event.getX();
int y = (int) event.getY();
boolean touchInsideContainer = y >= containerView.getTop()
&& x >= containerView.getLeft()
&& x <= containerView.getRight();
if (touchInsideContainer) {
return false;
} else {
chatActivity.getFragmentView().dispatchTouchEvent(event);
return true;
}
}
private void onDataLoaded(List<ChatTheme> result) {
if (result == null || result.isEmpty()) {
return;
}
ChatThemeItem noThemeItem = new ChatThemeItem(result.get(0));
List<ChatThemeItem> items = new ArrayList<>(result.size());
ChatTheme currentTheme = themeDelegate.getCurrentTheme();
items.add(0, noThemeItem);
selectedItem = noThemeItem;
for (int i = 1; i < result.size(); ++i) {
ChatTheme chatTheme = result.get(i);
ChatThemeItem item = new ChatThemeItem(chatTheme);
HashMap<String, Integer> colorsMap = chatTheme.getCurrentColors(chatActivity.getCurrentAccount(), true);
Integer color = colorsMap.get(Theme.key_chat_inBubble);
if (color == null) {
color = getThemedColor(Theme.key_chat_inBubble);
}
item.inBubbleColorDark = color;
color = colorsMap.get(Theme.key_chat_outBubble);
if (color == null) {
color = getThemedColor(Theme.key_chat_outBubble);
}
item.outBubbleColorDark = color;
color = colorsMap.get(Theme.key_featuredStickers_addButton);
item.strokeColorLight = color != null ? color : 0;
colorsMap = chatTheme.getCurrentColors(chatActivity.getCurrentAccount(), false);
color = colorsMap.get(Theme.key_chat_inBubble);
if (color == null) {
color = getThemedColor(Theme.key_chat_inBubble);
}
item.inBubbleColorLight = color;
color = colorsMap.get(Theme.key_chat_outBubble);
if (color == null) {
color = getThemedColor(Theme.key_chat_outBubble);
}
item.outBubbleColorLight = color;
color = colorsMap.get(Theme.key_featuredStickers_addButton);
item.strokeColorDark = color != null ? color : 0;
item.isDark = forceDark;
items.add(item);
}
adapter.setItems(items);
applyButton.setEnabled(true);
applyTextView.setAlpha(0f);
resetTextView.setAlpha(0f);
recyclerView.setAlpha(0f);
applyTextView.setVisibility(View.VISIBLE);
resetTextView.setVisibility(View.VISIBLE);
darkThemeView.setVisibility(View.VISIBLE);
boolean showRestText = false;
if (currentTheme != null) {
int selectedPosition = -1;
for (int i = 0; i != items.size(); ++i) {
if (items.get(i).chatTheme.getEmoticon().equals(currentTheme.getEmoticon())) {
selectedItem = items.get(i);
selectedPosition = i;
break;
}
}
if (selectedPosition != -1) {
prevSelectedPosition = selectedPosition;
adapter.setSelectedItem(selectedPosition);
int finalSelectedPosition = Math.min(selectedPosition, adapter.items.size() - 1);
layoutManager.scrollToPositionWithOffset(finalSelectedPosition, 0);
}
} else {
showRestText = true;
adapter.setSelectedItem(0);
layoutManager.scrollToPositionWithOffset(0, 0);
}
recyclerView.animate().alpha(1f).setDuration(150).start();
resetTextView.animate().alpha(showRestText ? 1f : 0).setDuration(150).start();
applyTextView.animate().alpha(showRestText ? 0f : 1).setDuration(150).start();
progressView.animate().alpha(0f).setListener(new HideViewAfterAnimation(progressView)).setDuration(150).start();
}
private void onAnimationStart() {
if (adapter != null) {
for (ChatThemeItem item : adapter.items) {
item.isDark = forceDark;
}
}
if (!isLightDarkChangeAnimation) {
setItemsAnimationProgress(1.0f);
}
}
private void onAnimationEnd() {
isLightDarkChangeAnimation = false;
}
private void setDarkButtonColor(int color) {
darkThemeDrawable.setLayerColor("Sunny.**", color);
darkThemeDrawable.setLayerColor("Path.**", color);
darkThemeDrawable.setLayerColor("Path 10.**", color);
darkThemeDrawable.setLayerColor("Path 11.**", color);
}
private void setForceDark(boolean isDark, boolean playAnimation) {
useLightNavBar = isDark;
useLightStatusBar = isDark;
if (forceDark == isDark) {
return;
}
forceDark = isDark;
if (playAnimation) {
darkThemeDrawable.setCustomEndFrame(isDark ? darkThemeDrawable.getFramesCount() : 0);
darkThemeView.playAnimation();
} else {
darkThemeDrawable.setCurrentFrame(isDark ? darkThemeDrawable.getFramesCount() - 1 : 0, false, true);
darkThemeView.invalidate();
}
}
private void setItemsAnimationProgress(float progress) {
for (int i = 0; i < adapter.getItemCount(); ++i) {
adapter.items.get(i).animationProgress = progress;
}
}
private void applySelectedTheme() {
Bulletin bulletin = null;
ChatTheme newTheme = selectedItem.chatTheme;
if (newTheme.isDefault) {
newTheme = null;
}
if (selectedItem != null && newTheme != originalTheme) {
ChatTheme chatTheme = selectedItem.chatTheme;
String emoticon = (chatTheme != null && !chatTheme.isDefault) ? chatTheme.getEmoticon() : null;
ChatThemeController.getInstance(currentAccount).setDialogTheme(chatActivity.getDialogId(), emoticon, true);
if (chatTheme != null && !chatTheme.isDefault) {
themeDelegate.setCurrentTheme(chatTheme, true, originalIsDark);
} else {
themeDelegate.setCurrentTheme(null, true, originalIsDark);
}
isApplyClicked = true;
TLRPC.User user = chatActivity.getCurrentUser();
if (user != null && !user.self) {
boolean themeDisabled = false;
if (TextUtils.isEmpty(emoticon)) {
themeDisabled = true;
emoticon = "";
}
TLRPC.Document document = emoticon != null ? MediaDataController.getInstance(currentAccount).getEmojiAnimatedSticker(emoticon) : null;
StickerSetBulletinLayout layout = new StickerSetBulletinLayout(getContext(), null, StickerSetBulletinLayout.TYPE_EMPTY, document, chatActivity.getResourceProvider());
layout.subtitleTextView.setVisibility(View.GONE);
if (themeDisabled) {
layout.titleTextView.setText(AndroidUtilities.replaceTags(LocaleController.formatString("ThemeAlsoDisabledForHint", R.string.ThemeAlsoDisabledForHint, user.first_name)));
} else {
layout.titleTextView.setText(AndroidUtilities.replaceTags(LocaleController.formatString("ThemeAlsoAppliedForHint", R.string.ThemeAlsoAppliedForHint, user.first_name)));
}
layout.titleTextView.setTypeface(null);
bulletin = Bulletin.make(chatActivity, layout, Bulletin.DURATION_LONG);
}
}
dismiss();
if (bulletin != null) {
bulletin.show();
}
}
private boolean hasChanges() {
if (selectedItem == null) {
return false;
} else {
String oldEmoticon = originalTheme != null ? originalTheme.getEmoticon() : null;
if (TextUtils.isEmpty(oldEmoticon)) {
oldEmoticon = "";
}
String newEmoticon = selectedItem.chatTheme != null ? selectedItem.chatTheme.getEmoticon() : null;
if (TextUtils.isEmpty(newEmoticon)) {
newEmoticon = "";
}
return !Objects.equals(oldEmoticon, newEmoticon);
}
}
@SuppressLint("NotifyDataSetChanged")
private class Adapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final Theme.ResourcesProvider resourcesProvider;
private List<ChatThemeItem> items;
private WeakReference<ChatThemeView> selectedViewRef;
private int selectedItemPosition = -1;
public Adapter(Theme.ResourcesProvider resourcesProvider) {
this.resourcesProvider = resourcesProvider;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new RecyclerListView.Holder(new ChatThemeView(parent.getContext(), resourcesProvider));
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
ChatThemeView view = (ChatThemeView) holder.itemView;
view.setItem(items.get(position));
view.setSelected(position == selectedItemPosition);
if (position == selectedItemPosition) {
selectedViewRef = new WeakReference<>(view);
}
}
@Override
public int getItemCount() {
return items == null ? 0 : items.size();
}
public void setItems(List<ChatThemeItem> newItems) {
items = newItems;
notifyDataSetChanged();
}
public void setSelectedItem(int position) {
if (selectedItemPosition == position) {
return;
}
if (selectedItemPosition >= 0) {
notifyItemChanged(selectedItemPosition);
ChatThemeView view = selectedViewRef.get();
if (view != null) {
view.setSelected(false);
}
}
selectedItemPosition = position;
notifyItemChanged(selectedItemPosition);
}
private class ChatThemeView extends FrameLayout implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener {
private final float STROKE_RADIUS = AndroidUtilities.dp(8);
private final float INNER_RADIUS = AndroidUtilities.dp(6);
private final float INNER_RECT_SPACE = AndroidUtilities.dp(4);
private final float BUBBLE_HEIGHT = AndroidUtilities.dp(21);
private final float BUBBLE_WIDTH = AndroidUtilities.dp(41);
private final Paint backgroundFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Paint strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Paint outBubblePaintFirst = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Paint outBubblePaintSecond = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Paint inBubblePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final RectF rectF = new RectF();
private final Path clipPath = new Path();
private final Theme.ResourcesProvider resourcesProvider;
private ValueAnimator strokeAlphaAnimator;
private TextPaint noThemeTextPaint;
private StaticLayout textLayout;
private ChatThemeItem chatThemeItem;
private BackupImageView backupImageView;
private boolean isDark;
private boolean hasAnimatedEmoji;
Runnable animationCancelRunnable;
public ChatThemeView(Context context, Theme.ResourcesProvider resourcesProvider) {
super(context);
this.resourcesProvider = resourcesProvider;
strokePaint.setStyle(Paint.Style.STROKE);
strokePaint.setStrokeWidth(AndroidUtilities.dp(2));
setBackgroundColor(getThemedColor(Theme.key_dialogBackgroundGray));
backupImageView = new BackupImageView(context);
backupImageView.getImageReceiver().setCrossfadeWithOldImage(true);
backupImageView.getImageReceiver().setAllowStartLottieAnimation(false);
backupImageView.getImageReceiver().setAutoRepeat(0);
addView(backupImageView, LayoutHelper.createFrame(28, 28, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 12));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = MeasureSpec.getSize(heightMeasureSpec);
int width = AndroidUtilities.dp(77);
super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (w == oldw && h == oldh) {
return;
}
rectF.set(INNER_RECT_SPACE, INNER_RECT_SPACE, w - INNER_RECT_SPACE, h - INNER_RECT_SPACE);
clipPath.reset();
clipPath.addRoundRect(rectF, INNER_RADIUS, INNER_RADIUS, Path.Direction.CW);
}
@Override
protected void dispatchDraw(Canvas canvas) {
if (chatThemeItem == null) {
super.dispatchDraw(canvas);
return;
}
if (chatThemeItem.isSelected || strokeAlphaAnimator != null) {
float rectSpace = strokePaint.getStrokeWidth() * 0.5f;
rectF.set(rectSpace, rectSpace, getWidth() - rectSpace, getHeight() - rectSpace);
canvas.drawRoundRect(rectF, STROKE_RADIUS, STROKE_RADIUS, strokePaint);
}
rectF.set(INNER_RECT_SPACE, INNER_RECT_SPACE, getWidth() - INNER_RECT_SPACE, getHeight() - INNER_RECT_SPACE);
if (chatThemeItem.chatTheme == null || chatThemeItem.chatTheme.isDefault) {
canvas.drawRoundRect(rectF, INNER_RADIUS, INNER_RADIUS, backgroundFillPaint);
canvas.save();
StaticLayout textLayout = getNoThemeStaticLayout();
canvas.translate((getWidth() - textLayout.getWidth()) * 0.5f, AndroidUtilities.dp(18));
textLayout.draw(canvas);
canvas.restore();
} else {
if (chatThemeItem.previewDrawable != null) {
canvas.save();
canvas.clipPath(clipPath);
chatThemeItem.previewDrawable.setBounds(0, 0, getWidth(), getHeight());
chatThemeItem.previewDrawable.draw(canvas);
canvas.restore();
} else {
canvas.drawRoundRect(rectF, INNER_RADIUS, INNER_RADIUS, backgroundFillPaint);
}
float bubbleTop = INNER_RECT_SPACE + AndroidUtilities.dp(8);
float bubbleLeft = INNER_RECT_SPACE + AndroidUtilities.dp(22);
rectF.set(bubbleLeft, bubbleTop, bubbleLeft + BUBBLE_WIDTH, bubbleTop + BUBBLE_HEIGHT);
canvas.drawRoundRect(rectF, rectF.height() * 0.5f, rectF.height() * 0.5f, outBubblePaintFirst);
canvas.drawRoundRect(rectF, rectF.height() * 0.5f, rectF.height() * 0.5f, outBubblePaintSecond);
bubbleLeft = INNER_RECT_SPACE + AndroidUtilities.dp(5);
bubbleTop += BUBBLE_HEIGHT + AndroidUtilities.dp(4);
rectF.set(bubbleLeft, bubbleTop, bubbleLeft + BUBBLE_WIDTH, bubbleTop + BUBBLE_HEIGHT);
canvas.drawRoundRect(rectF, rectF.height() * 0.5f, rectF.height() * 0.5f, inBubblePaint);
}
super.dispatchDraw(canvas);
}
public void setItem(ChatThemeItem item) {
boolean itemChanged = chatThemeItem != item;
boolean darkModeChanged = isDark != item.isDark;
isDark = item.isDark;
this.chatThemeItem = item;
hasAnimatedEmoji = false;
TLRPC.Document document = null;
if (item.chatTheme.getEmoticon() != null) {
document = MediaDataController.getInstance(currentAccount).getEmojiAnimatedSticker(item.chatTheme.getEmoticon());
}
if (itemChanged) {
if (animationCancelRunnable != null) {
AndroidUtilities.cancelRunOnUIThread(animationCancelRunnable);
animationCancelRunnable = null;
}
backupImageView.animate().cancel();
backupImageView.setScaleX(1f);
backupImageView.setScaleY(1f);
}
backupImageView.setImage(ImageLocation.getForDocument(document), "50_50", Emoji.getEmojiDrawable(item.chatTheme == null ? "" : item.chatTheme.getEmoticon()), null);
if (item.chatTheme != null && !item.chatTheme.isDefault) {
updatePreviewBackground();
if (itemChanged || darkModeChanged) {
final long themeId = item.chatTheme.getTlTheme(isDark).id;
final int intensity = item.chatTheme.getWallpaper(isDark).settings.intensity;
item.chatTheme.loadWallpaperThumb(isDark, result -> {
if (result != null && result.first == themeId) {
MotionBackgroundDrawable drawable = getPreviewDrawable();
if (drawable != null) {
drawable.setPatternBitmap(intensity >= 0 ? 100 : -100, result.second);
drawable.setPatternColorFilter(drawable.getPatternColor());
}
2021-09-21 11:51:08 +02:00
invalidate();
2021-09-20 07:54:41 +02:00
}
});
}
}
setBackgroundColor(0);
}
@Override
public void setSelected(boolean selected) {
super.setSelected(selected);
if (chatThemeItem.isSelected != selected) {
if (strokeAlphaAnimator != null) {
strokeAlphaAnimator.cancel();
}
if (selected) {
strokePaint.setAlpha(0);
}
strokeAlphaAnimator = ValueAnimator.ofInt(selected ? 0 : 255, selected ? 255 : 0);
strokeAlphaAnimator.addUpdateListener(this);
strokeAlphaAnimator.addListener(this);
strokeAlphaAnimator.setDuration(350);
strokeAlphaAnimator.start();
}
chatThemeItem.isSelected = selected;
}
@Override
public void setBackgroundColor(int color) {
backgroundFillPaint.setColor(getThemedColor(Theme.key_dialogBackgroundGray));
if (noThemeTextPaint != null) {
noThemeTextPaint.setColor(getThemedColor(Theme.key_chat_emojiPanelTrendingDescription));
}
invalidate();
}
private void fillOutBubblePaint(Paint paint, List<Integer> messageColors) {
if (messageColors.size() > 1) {
int[] colors = new int[messageColors.size()];
for (int i = 0; i != messageColors.size(); ++i) {
colors[i] = messageColors.get(i);
}
float top = INNER_RECT_SPACE + AndroidUtilities.dp(8);
paint.setShader(new LinearGradient(0f, top, 0f, top + BUBBLE_HEIGHT, colors, null, Shader.TileMode.CLAMP));
} else {
paint.setShader(null);
}
}
public void updatePreviewBackground() {
if (chatThemeItem == null || chatThemeItem.chatTheme == null || chatThemeItem.chatTheme.isDefault) {
return;
}
int color = chatThemeItem.isDark ? chatThemeItem.inBubbleColorDark : chatThemeItem.inBubbleColorLight;
inBubblePaint.setColor(color);
color = chatThemeItem.isDark ? chatThemeItem.outBubbleColorDark : chatThemeItem.outBubbleColorLight;
outBubblePaintSecond.setColor(color);
TLRPC.TL_theme firstTlTheme = chatThemeItem.chatTheme.getTlTheme(!chatThemeItem.isDark);
fillOutBubblePaint(outBubblePaintFirst, firstTlTheme.settings.message_colors);
TLRPC.TL_theme secondTlTheme = chatThemeItem.chatTheme.getTlTheme(chatThemeItem.isDark);
fillOutBubblePaint(outBubblePaintSecond, secondTlTheme.settings.message_colors);
outBubblePaintSecond.setAlpha(255);
MotionBackgroundDrawable drawable = getPreviewDrawable();
if (drawable != null) {
TLRPC.WallPaperSettings secondSettings = secondTlTheme.settings.wallpaper.settings;
int color1 = 0xff000000 | secondSettings.background_color;
if (color1 == 0xff000000) {
color1 = Color.TRANSPARENT;
}
int color2 = 0xff000000 | secondSettings.second_background_color;
if (color2 == 0xff000000) {
color2 = Color.TRANSPARENT;
}
int color3 = 0xff000000 | secondSettings.third_background_color;
if (color3 == 0xff000000) {
color3 = Color.TRANSPARENT;
}
int color4 = 0xff000000 | secondSettings.fourth_background_color;
if (color4 == 0xff000000) {
color4 = Color.TRANSPARENT;
}
drawable.setPatternBitmap(secondSettings.intensity >= 0 ? 100 : -100);
drawable.setColors(color1, color2, color3, color4, false);
drawable.setPatternColorFilter(drawable.getPatternColor());
}
invalidate();
}
private MotionBackgroundDrawable getPreviewDrawable() {
if (chatThemeItem == null) {
return null;
}
MotionBackgroundDrawable drawable = chatThemeItem.previewDrawable;
if (drawable == null) {
drawable = new MotionBackgroundDrawable();
chatThemeItem.previewDrawable = drawable;
}
return drawable;
}
private StaticLayout getNoThemeStaticLayout() {
if (textLayout != null) {
return textLayout;
}
noThemeTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG + TextPaint.SUBPIXEL_TEXT_FLAG);
noThemeTextPaint.setColor(getThemedColor(Theme.key_chat_emojiPanelTrendingDescription));
noThemeTextPaint.setTextSize(AndroidUtilities.dp(14));
noThemeTextPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
textLayout = StaticLayoutEx.createStaticLayout2(
2021-09-21 11:51:08 +02:00
LocaleController.getString("ChatNoTheme", R.string.ChatNoTheme),
2021-09-20 07:54:41 +02:00
noThemeTextPaint,
AndroidUtilities.dp(52),
Layout.Alignment.ALIGN_CENTER,
1f, 0f, true,
TextUtils.TruncateAt.END, AndroidUtilities.dp(52), 3
);
return textLayout;
}
private int getThemedColor(String key) {
Integer color = resourcesProvider != null ? resourcesProvider.getColor(key) : null;
return color != null ? color : Theme.getColor(key);
}
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int strokeColor = chatThemeItem.chatTheme.isDefault
? getThemedColor(Theme.key_featuredStickers_addButton)
: chatThemeItem.isDark ? chatThemeItem.strokeColorDark : chatThemeItem.strokeColorLight;
strokePaint.setColor(strokeColor);
strokePaint.setAlpha((int) valueAnimator.getAnimatedValue());
invalidate();
}
@Override
public void onAnimationEnd(Animator animator) {
strokeAlphaAnimator = null;
invalidate();
}
@Override
public void onAnimationCancel(Animator animator) {
strokeAlphaAnimator = null;
invalidate();
}
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
public void playEmojiAnimation() {
if (backupImageView.getImageReceiver().getLottieAnimation() != null) {
AndroidUtilities.cancelRunOnUIThread(animationCancelRunnable);
backupImageView.setVisibility(View.VISIBLE);
backupImageView.getImageReceiver().getLottieAnimation().setCurrentFrame(0, false);
backupImageView.getImageReceiver().getLottieAnimation().start();
backupImageView.setPivotY(AndroidUtilities.dp(24));
backupImageView.setPivotX(AndroidUtilities.dp(12));
backupImageView.animate().scaleX(2f).scaleY(2f).setDuration(300).setInterpolator(AndroidUtilities.overshootInterpolator).start();
AndroidUtilities.runOnUIThread(animationCancelRunnable = () -> {
animationCancelRunnable = null;
backupImageView.animate().scaleX(1f).scaleY(1f).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start();
}, 2500);
}
}
public void cancelAnimation() {
if (animationCancelRunnable != null) {
AndroidUtilities.cancelRunOnUIThread(animationCancelRunnable);
animationCancelRunnable.run();
}
}
}
}
private static class ChatThemeItem {
public final ChatTheme chatTheme;
public MotionBackgroundDrawable previewDrawable;
public boolean isDark;
public boolean isSelected;
public float animationProgress = 1f;
public int inBubbleColorLight;
public int inBubbleColorDark;
public int outBubbleColorLight;
public int outBubbleColorDark;
public int strokeColorDark;
public int strokeColorLight;
public ChatThemeItem(ChatTheme chatTheme) {
this.chatTheme = chatTheme;
}
}
@Override
public void show() {
super.show();
resetTextView.setText(themeDelegate.getCurrentTheme() == null ? LocaleController.getString("DoNoSetTheme", R.string.DoNoSetTheme) : LocaleController.getString("ChatResetTheme", R.string.ChatResetTheme));
}
}