NekoX/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsLayoutInBubble.java

945 lines
43 KiB
Java

package org.telegram.ui.Components.Reactions;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.TextPaint;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import androidx.core.graphics.ColorUtils;
import androidx.recyclerview.widget.ChatListItemAnimator;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.ApplicationLoader;
import org.telegram.messenger.DocumentObject;
import org.telegram.messenger.ImageLocation;
import org.telegram.messenger.ImageReceiver;
import org.telegram.messenger.MediaDataController;
import org.telegram.messenger.MessageObject;
import org.telegram.messenger.MessagesController;
import org.telegram.messenger.SvgHelper;
import org.telegram.messenger.UserConfig;
import org.telegram.tgnet.TLRPC;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.Cells.ChatMessageCell;
import org.telegram.ui.Components.AnimatedEmojiDrawable;
import org.telegram.ui.Components.AvatarsDarawable;
import org.telegram.ui.Components.CounterView;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Objects;
public class ReactionsLayoutInBubble {
private final static int ANIMATION_TYPE_IN = 1;
private final static int ANIMATION_TYPE_OUT = 2;
private final static int ANIMATION_TYPE_MOVE = 3;
public boolean drawServiceShaderBackground;
private static Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private static TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
public boolean isSmall;
public int x;
public int y;
private float fromX;
private float fromY;
private float lastDrawnX;
private float lastDrawnY;
private boolean wasDrawn;
private boolean animateMove;
private boolean animateWidth;
private boolean animateHeight;
public int positionOffsetY;
int currentAccount;
public int height;
public int totalHeight;
public int width;
public int fromWidth;
public boolean isEmpty;
private float touchSlop;
public int lastLineX;
ArrayList<ReactionButton> reactionButtons = new ArrayList<>();
ArrayList<ReactionButton> outButtons = new ArrayList<>();
HashMap<String, ReactionButton> lastDrawingReactionButtons = new HashMap<>();
HashMap<String, ReactionButton> lastDrawingReactionButtonsTmp = new HashMap<>();
ChatMessageCell parentView;
MessageObject messageObject;
Theme.ResourcesProvider resourcesProvider;
private String scrimViewReaction;
int availableWidth;
private int lastDrawnWidth;
boolean attached;
private static int animationUniq;
private final static ButtonsComparator comparator = new ButtonsComparator();
HashMap<VisibleReaction, ImageReceiver> animatedReactions = new HashMap<>();
private int lastDrawTotalHeight;
private int animateFromTotalHeight;
public boolean hasUnreadReactions;
private static int pointer = 1;
private final static Comparator<TLRPC.User> usersComparator = (user1, user2) -> (int) (user1.id - user2.id);
public ReactionsLayoutInBubble(ChatMessageCell parentView) {
this.parentView = parentView;
currentAccount = UserConfig.selectedAccount;
paint.setColor(Theme.getColor(Theme.key_chat_inLoader, resourcesProvider));
textPaint.setColor(Theme.getColor(Theme.key_featuredStickers_buttonText, resourcesProvider));
textPaint.setTextSize(AndroidUtilities.dp(12));
textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
touchSlop = ViewConfiguration.get(ApplicationLoader.applicationContext).getScaledTouchSlop();
}
public static boolean equalsTLReaction(TLRPC.Reaction reaction, TLRPC.Reaction reaction1) {
if (reaction instanceof TLRPC.TL_reactionEmoji && reaction1 instanceof TLRPC.TL_reactionEmoji) {
return TextUtils.equals(((TLRPC.TL_reactionEmoji) reaction).emoticon, ((TLRPC.TL_reactionEmoji) reaction1).emoticon);
}
if (reaction instanceof TLRPC.TL_reactionCustomEmoji && reaction1 instanceof TLRPC.TL_reactionCustomEmoji) {
return ((TLRPC.TL_reactionCustomEmoji) reaction).document_id == ((TLRPC.TL_reactionCustomEmoji) reaction1).document_id;
}
return false;
}
public void setMessage(MessageObject messageObject, boolean isSmall, Theme.ResourcesProvider resourcesProvider) {
this.resourcesProvider = resourcesProvider;
this.isSmall = isSmall;
this.messageObject = messageObject;
for (int i = 0; i < reactionButtons.size(); i++) {
reactionButtons.get(i).detach();
}
hasUnreadReactions = false;
reactionButtons.clear();
if (messageObject != null) {
comparator.dialogId = messageObject.getDialogId();
if (messageObject.messageOwner.reactions != null && messageObject.messageOwner.reactions.results != null) {
int totalCount = 0;
for (int i = 0; i < messageObject.messageOwner.reactions.results.size(); i++) {
totalCount += messageObject.messageOwner.reactions.results.get(i).count;
}
for (int i = 0; i < messageObject.messageOwner.reactions.results.size(); i++) {
TLRPC.ReactionCount reactionCount = messageObject.messageOwner.reactions.results.get(i);
ReactionButton button = new ReactionButton(reactionCount, isSmall);
reactionButtons.add(button);
if (!isSmall && messageObject.messageOwner.reactions.recent_reactions != null) {
ArrayList<TLRPC.User> users = null;
if (messageObject.getDialogId() > 0) {
users = new ArrayList<>();
if (reactionCount.count == 2) {
users.add(UserConfig.getInstance(currentAccount).getCurrentUser());
users.add(MessagesController.getInstance(currentAccount).getUser(messageObject.getDialogId()));
} else {
if (reactionCount.chosen) {
users.add(UserConfig.getInstance(currentAccount).getCurrentUser());
} else {
users.add(MessagesController.getInstance(currentAccount).getUser(messageObject.getDialogId()));
}
}
button.setUsers(users);
if (users != null && !users.isEmpty()) {
button.count = 0;
button.counterDrawable.setCount(0, false);
}
} else if (reactionCount.count <= 3 && totalCount <= 3) {
for (int j = 0; j < messageObject.messageOwner.reactions.recent_reactions.size(); j++) {
TLRPC.MessagePeerReaction reccent = messageObject.messageOwner.reactions.recent_reactions.get(j);
VisibleReaction visibleReactionPeer = VisibleReaction.fromTLReaction(reccent.reaction);
VisibleReaction visibleReactionCount = VisibleReaction.fromTLReaction(reactionCount.reaction);
if (visibleReactionPeer.equals(visibleReactionCount) && MessagesController.getInstance(currentAccount).getUser(MessageObject.getPeerId(reccent.peer_id)) != null) {
if (users == null) {
users = new ArrayList<>();
}
users.add(MessagesController.getInstance(currentAccount).getUser(MessageObject.getPeerId(reccent.peer_id)));
}
}
button.setUsers(users);
if (users != null && !users.isEmpty()) {
button.count = 0;
button.counterDrawable.setCount(0, false);
}
}
}
if (isSmall && reactionCount.count > 1 && reactionCount.chosen) {
reactionButtons.add(new ReactionButton(reactionCount, isSmall));
reactionButtons.get(0).isSelected = false;
reactionButtons.get(1).isSelected = true;
reactionButtons.get(0).realCount = 1;
reactionButtons.get(1).realCount = 1;
reactionButtons.get(1).key = reactionButtons.get(1).key + "_";
break;
}
if (isSmall && i == 2) {
break;
}
if (attached) {
button.attach();
}
}
}
if (!isSmall && !reactionButtons.isEmpty()) {
comparator.currentAccount = currentAccount;
Collections.sort(reactionButtons, comparator);
for (int i = 0; i < reactionButtons.size(); i++) {
reactionButtons.get(i).reactionCount.lastDrawnPosition = pointer++;
}
}
hasUnreadReactions = MessageObject.hasUnreadReactions(messageObject.messageOwner);
}
isEmpty = reactionButtons.isEmpty();
}
public void measure(int availableWidth, int gravity) {
height = 0;
width = 0;
positionOffsetY = 0;
totalHeight = 0;
if (isEmpty) {
return;
}
this.availableWidth = availableWidth;
int maxWidth = 0;
int currentX = 0;
int currentY = 0;
for (int i = 0; i < reactionButtons.size(); i++) {
ReactionButton button = reactionButtons.get(i);
if (button.isSmall) {
button.width = AndroidUtilities.dp(14);
button.height = AndroidUtilities.dp(14);
} else {
button.width = (int) (AndroidUtilities.dp(8) + AndroidUtilities.dp(20) + AndroidUtilities.dp(4));
if (button.avatarsDarawable != null && button.users.size() > 0) {
button.users.size();
int c1 = 1;
int c2 = button.users.size() > 1 ? button.users.size() - 1 : 0;
button.width += AndroidUtilities.dp(2) + c1 * AndroidUtilities.dp(20) + c2 * AndroidUtilities.dp(20) * 0.8f + AndroidUtilities.dp(1);
button.avatarsDarawable.height = AndroidUtilities.dp(26);
} else {
button.width += button.counterDrawable.textPaint.measureText(button.countText) + AndroidUtilities.dp(8);
}
button.height = AndroidUtilities.dp(26);
}
if (currentX + button.width > availableWidth) {
currentX = 0;
currentY += button.height + AndroidUtilities.dp(4);
}
button.x = currentX;
button.y = currentY;
currentX += button.width + AndroidUtilities.dp(4);
if (currentX > maxWidth) {
maxWidth = currentX;
}
}
if (gravity == Gravity.RIGHT && !reactionButtons.isEmpty()) {
int fromP = 0;
int startY = reactionButtons.get(0).y;
for (int i = 0; i < reactionButtons.size(); i++) {
if (reactionButtons.get(i).y != startY) {
int lineOffset = availableWidth - (reactionButtons.get(i - 1).x + reactionButtons.get(i - 1).width);
for (int k = fromP; k < i; k++) {
reactionButtons.get(k).x += lineOffset;
}
fromP = i;
}
}
int last = reactionButtons.size() - 1;
int lineOffset = availableWidth - (reactionButtons.get(last).x + reactionButtons.get(last).width);
for (int k = fromP; k <= last; k++) {
reactionButtons.get(k).x += lineOffset;
}
}
lastLineX = currentX;
if (gravity == Gravity.RIGHT) {
width = availableWidth;
} else {
width = maxWidth;
}
height = currentY + (reactionButtons.size() == 0 ? 0 : AndroidUtilities.dp(26));
drawServiceShaderBackground = false;
}
public void draw(Canvas canvas, float animationProgress, String drawOnlyReaction) {
if (isEmpty && outButtons.isEmpty()) {
return;
}
float totalX = this.x;
float totalY = this.y;
if (isEmpty) {
totalX = lastDrawnX;
totalY = lastDrawnY;
} else if (animateMove) {
totalX = totalX * (animationProgress) + fromX * (1f - animationProgress);
totalY = totalY * (animationProgress) + fromY * (1f - animationProgress);
}
canvas.save();
canvas.translate(totalX, totalY);
for (int i = 0; i < reactionButtons.size(); i++) {
ReactionButton reactionButton = reactionButtons.get(i);
if (reactionButton.reaction.equals(scrimViewReaction) || (drawOnlyReaction != null && !reactionButton.reaction.equals(drawOnlyReaction))) {
continue;
}
canvas.save();
float x = reactionButton.x;
float y = reactionButton.y;
if (animationProgress != 1f && reactionButton.animationType == ANIMATION_TYPE_MOVE) {
x = reactionButton.x * animationProgress + reactionButton.animateFromX * (1f - animationProgress);
y = reactionButton.y * animationProgress + reactionButton.animateFromY * (1f - animationProgress);
}
canvas.translate(x, y);
float alpha = 1f;
if (animationProgress != 1f && reactionButton.animationType == ANIMATION_TYPE_IN) {
float s = 0.5f + 0.5f * animationProgress;
alpha = animationProgress;
canvas.scale(s, s, reactionButton.width / 2f, reactionButton.height / 2f);
}
reactionButton.draw(canvas, reactionButton.animationType == ANIMATION_TYPE_MOVE ? animationProgress : 1f, alpha, drawOnlyReaction != null);
canvas.restore();
}
for (int i = 0; i < outButtons.size(); i++) {
ReactionButton reactionButton = outButtons.get(i);
canvas.save();
canvas.translate(reactionButton.x, reactionButton.y);
float s = 0.5f + 0.5f * (1f - animationProgress);
canvas.scale(s, s, reactionButton.width / 2f, reactionButton.height / 2f);
outButtons.get(i).draw(canvas, 1f, (1f - animationProgress), false);
canvas.restore();
}
canvas.restore();
}
public void recordDrawingState() {
lastDrawingReactionButtons.clear();
for (int i = 0; i < reactionButtons.size(); i++) {
lastDrawingReactionButtons.put(reactionButtons.get(i).key, reactionButtons.get(i));
}
wasDrawn = !isEmpty;
lastDrawnX = x;
lastDrawnY = y;
lastDrawnWidth = width;
lastDrawTotalHeight = totalHeight;
}
public boolean animateChange() {
if (messageObject == null) {
return false;
}
boolean changed = false;
lastDrawingReactionButtonsTmp.clear();
for (int i = 0; i < outButtons.size(); i++) {
outButtons.get(i).detach();
}
outButtons.clear();
lastDrawingReactionButtonsTmp.putAll(lastDrawingReactionButtons);
for (int i = 0; i < reactionButtons.size(); i++) {
ReactionButton button = reactionButtons.get(i);
ReactionButton lastButton = lastDrawingReactionButtonsTmp.get(button.key);
if (lastButton != null && button.isSmall != lastButton.isSmall) {
lastButton = null;
}
if (lastButton != null) {
lastDrawingReactionButtonsTmp.remove(button.key);
if (button.x != lastButton.x || button.y != lastButton.y || button.width != lastButton.width || button.count != lastButton.count || button.choosen != lastButton.choosen || button.avatarsDarawable != null || lastButton.avatarsDarawable != null) {
button.animateFromX = lastButton.x;
button.animateFromY = lastButton.y;
button.animateFromWidth = lastButton.width;
button.fromTextColor = lastButton.lastDrawnTextColor;
button.fromBackgroundColor = lastButton.lastDrawnBackgroundColor;
button.animationType = ANIMATION_TYPE_MOVE;
if (button.count != lastButton.count) {
button.counterDrawable.setCount(lastButton.count, false);
button.counterDrawable.setCount(button.count, true);
}
if (button.avatarsDarawable != null || lastButton.avatarsDarawable != null) {
if (button.avatarsDarawable == null) {
button.setUsers(new ArrayList<>());
}
if (lastButton.avatarsDarawable == null) {
lastButton.setUsers(new ArrayList<>());
}
if (!equalsUsersList(lastButton.users, button.users)) {
button.avatarsDarawable.animateFromState(lastButton.avatarsDarawable, currentAccount, false);
}
}
changed = true;
} else {
button.animationType = 0;
}
} else {
changed = true;
button.animationType = ANIMATION_TYPE_IN;
}
}
if (!lastDrawingReactionButtonsTmp.isEmpty()) {
changed = true;
outButtons.addAll(lastDrawingReactionButtonsTmp.values());
for (int i = 0; i < outButtons.size(); i++) {
outButtons.get(i).drawImage = outButtons.get(i).lastImageDrawn;
outButtons.get(i).attach();
}
}
if (wasDrawn && (lastDrawnX != x || lastDrawnY != y)) {
animateMove = true;
fromX = lastDrawnX;
fromY = lastDrawnY;
changed = true;
}
if (lastDrawnWidth != width) {
animateWidth = true;
fromWidth = lastDrawnWidth;
changed = true;
}
if (lastDrawTotalHeight != totalHeight) {
animateHeight = true;
animateFromTotalHeight = lastDrawTotalHeight;
changed = true;
}
return changed;
}
private boolean equalsUsersList(ArrayList<TLRPC.User> users, ArrayList<TLRPC.User> users1) {
if (users.size() != users1.size()) {
return false;
}
for (int i = 0; i < users.size(); i++) {
if (users.get(i).id != users.get(i).id) {
return false;
}
}
return true;
}
public void resetAnimation() {
for (int i = 0; i < outButtons.size(); i++) {
outButtons.get(i).detach();
}
outButtons.clear();
animateMove = false;
animateWidth = false;
animateHeight = false;
for (int i = 0; i < reactionButtons.size(); i++) {
reactionButtons.get(i).animationType = 0;
}
}
public ReactionButton getReactionButton(VisibleReaction visibleReaction) {
String hash = visibleReaction.emojicon != null ? visibleReaction.emojicon : Long.toString(visibleReaction.documentId);
if (isSmall) {
ReactionButton button = lastDrawingReactionButtons.get(hash + "_");
if (button != null) {
return button;
}
}
return lastDrawingReactionButtons.get(hash);
}
public void setScrimReaction(String scrimViewReaction) {
this.scrimViewReaction = scrimViewReaction;
}
public class ReactionButton {
private final TLRPC.ReactionCount reactionCount;
private final boolean isSmall;
public int animationType;
public int animateFromX;
public int animateFromY;
public int animateFromWidth;
public int fromBackgroundColor;
public int fromTextColor;
public int realCount;
public int choosenOrder;
public boolean drawImage = true;
public boolean lastImageDrawn;
public boolean wasDrawn;
public String key;
public boolean choosen;
String countText;
TLRPC.Reaction reaction;
VisibleReaction visibleReaction;
android.graphics.Rect drawingImageRect = new Rect();
int count;
public int x;
public int y;
public int width;
public int height;
ImageReceiver imageReceiver = new ImageReceiver();
AnimatedEmojiDrawable animatedEmojiDrawable;
CounterView.CounterDrawable counterDrawable = new CounterView.CounterDrawable(parentView, false, null);
int backgroundColor;
int textColor;
int serviceBackgroundColor;
int serviceTextColor;
int lastDrawnTextColor;
int lastDrawnBackgroundColor;
boolean isSelected;
AvatarsDarawable avatarsDarawable;
ArrayList<TLRPC.User> users;
public ReactionButton(TLRPC.ReactionCount reactionCount, boolean isSmall) {
this.reactionCount = reactionCount;
this.reaction = reactionCount.reaction;
this.visibleReaction = VisibleReaction.fromTLReaction(reactionCount.reaction);
this.count = reactionCount.count;
this.choosen = reactionCount.chosen;
this.realCount = reactionCount.count;
this.choosenOrder = reactionCount.chosen_order;
this.isSmall = isSmall;
if (this.reaction instanceof TLRPC.TL_reactionEmoji) {
this.key = ((TLRPC.TL_reactionEmoji) this.reaction).emoticon;
} else if (this.reaction instanceof TLRPC.TL_reactionCustomEmoji) {
this.key = Long.toString(((TLRPC.TL_reactionCustomEmoji) this.reaction).document_id);
} else {
throw new RuntimeException("unsupported");
}
countText = Integer.toString(reactionCount.count);
imageReceiver.setParentView(parentView);
isSelected = reactionCount.chosen;
counterDrawable.updateVisibility = false;
counterDrawable.shortFormat = true;
if (reaction != null) {
if (visibleReaction.emojicon != null) {
TLRPC.TL_availableReaction r = MediaDataController.getInstance(currentAccount).getReactionsMap().get(visibleReaction.emojicon);
if (r != null) {
SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(r.static_icon, Theme.key_windowBackgroundGray, 1.0f);
//imageReceiver.setImage(ImageLocation.getForDocument(r.static_icon), "40_40", svgThumb, "webp", r, 1);
imageReceiver.setImage(ImageLocation.getForDocument(r.center_icon), "40_40_lastframe", svgThumb, "webp", r, 1);
}
} else if (visibleReaction.documentId != 0) {
animatedEmojiDrawable = new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW, currentAccount, visibleReaction.documentId);
}
}
counterDrawable.setSize(AndroidUtilities.dp(26), AndroidUtilities.dp(100));
counterDrawable.textPaint = textPaint;
counterDrawable.setCount(count, false);
counterDrawable.setType(CounterView.CounterDrawable.TYPE_CHAT_REACTIONS);
counterDrawable.gravity = Gravity.LEFT;
}
public void draw(Canvas canvas, float progress, float alpha, boolean drawOverlayScrim) {
wasDrawn = true;
ImageReceiver imageReceiver = animatedEmojiDrawable != null ? animatedEmojiDrawable.getImageReceiver() : this.imageReceiver;
if (isSmall && imageReceiver != null) {
imageReceiver.setAlpha(alpha);
drawingImageRect.set(0, 0, AndroidUtilities.dp(14), AndroidUtilities.dp(14));
imageReceiver.setImageCoords(drawingImageRect);
imageReceiver.setRoundRadius(0);
drawImage(canvas, alpha);
return;
}
if (choosen) {
backgroundColor = Theme.getColor(messageObject.isOutOwner() ? Theme.key_chat_outReactionButtonBackground : Theme.key_chat_inReactionButtonBackground, resourcesProvider);
textColor = Theme.getColor(messageObject.isOutOwner() ? Theme.key_chat_outReactionButtonTextSelected : Theme.key_chat_inReactionButtonTextSelected, resourcesProvider);
serviceTextColor = Theme.getColor(messageObject.isOutOwner() ? Theme.key_chat_outReactionButtonBackground : Theme.key_chat_inReactionButtonBackground, resourcesProvider);
serviceBackgroundColor = Theme.getColor(messageObject.isOutOwner() ? Theme.key_chat_outBubble : Theme.key_chat_inBubble);
} else {
textColor = Theme.getColor(messageObject.isOutOwner() ? Theme.key_chat_outReactionButtonText : Theme.key_chat_inReactionButtonText, resourcesProvider);
backgroundColor = Theme.getColor(messageObject.isOutOwner() ? Theme.key_chat_outReactionButtonBackground : Theme.key_chat_inReactionButtonBackground, resourcesProvider);
backgroundColor = ColorUtils.setAlphaComponent(backgroundColor, (int) (Color.alpha(backgroundColor) * 0.156f));
serviceTextColor = Theme.getColor(Theme.key_chat_serviceText, resourcesProvider);
serviceBackgroundColor = Color.TRANSPARENT;
}
updateColors(progress);
textPaint.setColor(lastDrawnTextColor);
paint.setColor(lastDrawnBackgroundColor);
if (alpha != 1f) {
textPaint.setAlpha((int) (textPaint.getAlpha() * alpha));
paint.setAlpha((int) (paint.getAlpha() * alpha));
}
if (imageReceiver != null) {
imageReceiver.setAlpha(alpha);
}
int w = width;
if (progress != 1f && animationType == ANIMATION_TYPE_MOVE) {
w = (int) (width * progress + animateFromWidth * (1f - progress));
}
AndroidUtilities.rectTmp.set(0, 0, w, height);
float rad = height / 2f;
if (drawServiceShaderBackground) {
Paint paint1 = getThemedPaint(Theme.key_paint_chatActionBackground);
Paint paint2 = Theme.chat_actionBackgroundGradientDarkenPaint;
int oldAlpha = paint1.getAlpha();
int oldAlpha2 = paint2.getAlpha();
paint1.setAlpha((int) (oldAlpha * alpha));
paint2.setAlpha((int) (oldAlpha2 * alpha));
canvas.drawRoundRect(AndroidUtilities.rectTmp, rad, rad, paint1);
if (hasGradientService()) {
canvas.drawRoundRect(AndroidUtilities.rectTmp, rad, rad, paint2);
}
paint1.setAlpha(oldAlpha);
paint2.setAlpha(oldAlpha2);
}
if (!drawServiceShaderBackground && drawOverlayScrim) {
Theme.MessageDrawable messageBackground = parentView.getCurrentBackgroundDrawable(false);
if (messageBackground != null) {
canvas.drawRoundRect(AndroidUtilities.rectTmp, rad, rad, messageBackground.getPaint());
}
}
canvas.drawRoundRect(AndroidUtilities.rectTmp, rad, rad, paint);
if (imageReceiver != null) {
int size, x;
if (animatedEmojiDrawable != null) {
size = AndroidUtilities.dp(24);
x = AndroidUtilities.dp(6);
imageReceiver.setRoundRadius(AndroidUtilities.dp(6));
} else {
size = AndroidUtilities.dp(20);
x = AndroidUtilities.dp(8);
imageReceiver.setRoundRadius(0);
}
int y = (int) ((height - size) / 2f);
drawingImageRect.set(x, y, x + size, y + size);
imageReceiver.setImageCoords(drawingImageRect);
drawImage(canvas, alpha);
}
if (count != 0 || counterDrawable.countChangeProgress != 1f) {
canvas.save();
canvas.translate(AndroidUtilities.dp(8) + AndroidUtilities.dp(20) + AndroidUtilities.dp(2), 0);
counterDrawable.draw(canvas);
canvas.restore();
}
if (avatarsDarawable != null) {
canvas.save();
canvas.translate(AndroidUtilities.dp(10) + AndroidUtilities.dp(20) + AndroidUtilities.dp(2), 0);
avatarsDarawable.setAlpha(alpha);
avatarsDarawable.setTransitionProgress(progress);
avatarsDarawable.onDraw(canvas);
canvas.restore();
}
}
private void updateColors(float progress) {
if (drawServiceShaderBackground) {
lastDrawnTextColor = ColorUtils.blendARGB(fromTextColor, serviceTextColor, progress);
lastDrawnBackgroundColor = ColorUtils.blendARGB(fromBackgroundColor, serviceBackgroundColor, progress);
} else {
lastDrawnTextColor = ColorUtils.blendARGB(fromTextColor, textColor, progress);
lastDrawnBackgroundColor = ColorUtils.blendARGB(fromBackgroundColor, backgroundColor, progress);
}
}
private void drawImage(Canvas canvas, float alpha) {
ImageReceiver imageReceiver = animatedEmojiDrawable != null ? animatedEmojiDrawable.getImageReceiver() : this.imageReceiver;
if (drawImage && ((realCount > 1 || !ReactionsEffectOverlay.isPlaying(messageObject.getId(), messageObject.getGroupId(), visibleReaction)) || !isSelected)) {
ImageReceiver imageReceiver2 = animatedReactions.get(visibleReaction);
boolean drawStaticImage = true;
if (imageReceiver2 != null) {
if (imageReceiver2.getLottieAnimation() != null && imageReceiver2.getLottieAnimation().hasBitmap()) {
drawStaticImage = false;
}
if (alpha != 1f) {
imageReceiver2.setAlpha(alpha);
if (alpha <= 0) {
imageReceiver2.onDetachedFromWindow();
animatedReactions.remove(visibleReaction);
}
} else {
if (imageReceiver2.getLottieAnimation() != null && !imageReceiver2.getLottieAnimation().isRunning()) {
drawStaticImage = true;
float alpha1 = imageReceiver2.getAlpha() - 16f / 200;
if (alpha1 <= 0) {
imageReceiver2.onDetachedFromWindow();
animatedReactions.remove(visibleReaction);
} else {
imageReceiver2.setAlpha(alpha1);
}
parentView.invalidate();
}
}
imageReceiver2.setImageCoords(imageReceiver.getImageX() - imageReceiver.getImageWidth() / 2, imageReceiver.getImageY() - imageReceiver.getImageWidth() / 2, imageReceiver.getImageWidth() * 2, imageReceiver.getImageHeight() * 2);
imageReceiver2.draw(canvas);
}
if (drawStaticImage) {
imageReceiver.draw(canvas);
}
lastImageDrawn = true;
} else {
imageReceiver.setAlpha(0);
imageReceiver.draw(canvas);
lastImageDrawn = false;
}
}
public void setUsers(ArrayList<TLRPC.User> users) {
this.users = users;
if (users != null) {
Collections.sort(users, usersComparator);
if (avatarsDarawable == null) {
avatarsDarawable = new AvatarsDarawable(parentView, false);
avatarsDarawable.transitionDuration = ChatListItemAnimator.DEFAULT_DURATION;
avatarsDarawable.transitionInterpolator = ChatListItemAnimator.DEFAULT_INTERPOLATOR;
avatarsDarawable.setSize(AndroidUtilities.dp(20));
avatarsDarawable.width = AndroidUtilities.dp(100);
avatarsDarawable.height = height;
if (attached) {
avatarsDarawable.onAttachedToWindow();
}
}
for (int i = 0; i < users.size(); i++) {
if (i == 3) {
break;
}
avatarsDarawable.setObject(i, currentAccount, users.get(i));
}
avatarsDarawable.commitTransition(false);
}
}
public void attach() {
if (imageReceiver != null) {
imageReceiver.onAttachedToWindow();
}
if (avatarsDarawable != null) {
avatarsDarawable.onAttachedToWindow();
}
if (animatedEmojiDrawable != null) {
animatedEmojiDrawable.addView(parentView);
}
}
public void detach() {
if (imageReceiver != null) {
imageReceiver.onDetachedFromWindow();
}
if (avatarsDarawable != null) {
avatarsDarawable.onDetachedFromWindow();
}
if (animatedEmojiDrawable != null) {
animatedEmojiDrawable.removeView(parentView);
}
}
}
float lastX;
float lastY;
ReactionButton lastSelectedButton;
boolean pressed;
Runnable longPressRunnable;
public boolean chekTouchEvent(MotionEvent event) {
if (isEmpty || isSmall || messageObject == null || messageObject.messageOwner == null || messageObject.messageOwner.reactions == null) {
return false;
}
float x = event.getX() - this.x;
float y = event.getY() - this.y;
if (event.getAction() == MotionEvent.ACTION_DOWN) {
for (int i = 0, n = reactionButtons.size(); i < n; i++) {
if (x > reactionButtons.get(i).x && x < reactionButtons.get(i).x + reactionButtons.get(i).width &&
y > reactionButtons.get(i).y && y < reactionButtons.get(i).y + reactionButtons.get(i).height) {
lastX = event.getX();
lastY = event.getY();
lastSelectedButton = reactionButtons.get(i);
if (longPressRunnable != null) {
AndroidUtilities.cancelRunOnUIThread(longPressRunnable);
longPressRunnable = null;
}
final ReactionButton selectedButtonFinal = lastSelectedButton;
if (messageObject.messageOwner.reactions.can_see_list || messageObject.getDialogId() >= 0) {
AndroidUtilities.runOnUIThread(longPressRunnable = () -> {
parentView.getDelegate().didPressReaction(parentView, selectedButtonFinal.reactionCount, true);
longPressRunnable = null;
}, ViewConfiguration.getLongPressTimeout());
}
pressed = true;
break;
}
}
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
if (pressed && Math.abs(event.getX() - lastX) > touchSlop || Math.abs(event.getY() - lastY) > touchSlop) {
pressed = false;
lastSelectedButton = null;
if (longPressRunnable != null) {
AndroidUtilities.cancelRunOnUIThread(longPressRunnable);
longPressRunnable = null;
}
}
} else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
if (longPressRunnable != null) {
AndroidUtilities.cancelRunOnUIThread(longPressRunnable);
longPressRunnable = null;
}
if (pressed && lastSelectedButton != null && event.getAction() == MotionEvent.ACTION_UP) {
if (parentView.getDelegate() != null) {
parentView.getDelegate().didPressReaction(parentView, lastSelectedButton.reactionCount, false);
}
}
pressed = false;
lastSelectedButton = null;
}
return pressed;
}
private boolean hasGradientService() {
return resourcesProvider != null ? resourcesProvider.hasGradientService() : Theme.hasGradientService();
}
private Paint getThemedPaint(String paintKey) {
Paint paint = resourcesProvider != null ? resourcesProvider.getPaint(paintKey) : null;
return paint != null ? paint : Theme.getThemePaint(paintKey);
}
public float getCurrentWidth(float transitionProgress) {
if (animateWidth) {
return fromWidth * (1f - transitionProgress) + width * transitionProgress;
}
return width;
}
public float getCurrentTotalHeight(float transitionProgress) {
if (animateHeight) {
return animateFromTotalHeight * (1f - transitionProgress) + totalHeight * transitionProgress;
}
return totalHeight;
}
private static class ButtonsComparator implements Comparator<ReactionButton> {
int currentAccount;
long dialogId;
@Override
public int compare(ReactionButton o1, ReactionButton o2) {
if (dialogId >= 0) {
if (o1.isSelected != o2.isSelected) {
return o1.isSelected ? -1 : 1;
} else if (o1.isSelected) {
if (o1.choosenOrder != o2.choosenOrder) {
return o1.choosenOrder - o2.choosenOrder;
}
}
return o1.reactionCount.lastDrawnPosition - o2.reactionCount.lastDrawnPosition;
} else {
if (o1.realCount != o2.realCount) {
return o2.realCount - o1.realCount;
}
}
// TLRPC.TL_availableReaction availableReaction1 = MediaDataController.getInstance(currentAccount).getReactionsMap().get(o1.reaction);
// TLRPC.TL_availableReaction availableReaction2 = MediaDataController.getInstance(currentAccount).getReactionsMap().get(o2.reaction);
// if (availableReaction1 != null && availableReaction2 != null) {
// return availableReaction1.positionInList - availableReaction2.positionInList;
// }
return o1.reactionCount.lastDrawnPosition - o2.reactionCount.lastDrawnPosition;
}
}
public void onAttachToWindow() {
attached = true;
for (int i = 0; i < reactionButtons.size(); i++) {
reactionButtons.get(i).attach();
}
}
public void onDetachFromWindow() {
attached = false;
for (int i = 0; i < reactionButtons.size(); i++) {
reactionButtons.get(i).detach();
}
if (!animatedReactions.isEmpty()) {
for (ImageReceiver imageReceiver : animatedReactions.values()) {
imageReceiver.onDetachedFromWindow();
}
}
animatedReactions.clear();
}
public void animateReaction(VisibleReaction reaction) {
if (reaction.documentId == 0 && animatedReactions.get(reaction) == null) {
ImageReceiver imageReceiver = new ImageReceiver();
imageReceiver.setParentView(parentView);
imageReceiver.setUniqKeyPrefix(Integer.toString(animationUniq++));
TLRPC.TL_availableReaction r = MediaDataController.getInstance(currentAccount).getReactionsMap().get(reaction.emojicon);
if (r != null) {
imageReceiver.setImage(ImageLocation.getForDocument(r.center_icon), "40_40_nolimit", null, "tgs", r, 1);
}
imageReceiver.setAutoRepeat(0);
imageReceiver.onAttachedToWindow();
animatedReactions.put(reaction, imageReceiver);
}
}
public static class VisibleReaction {
public String emojicon;
public long documentId;
public static VisibleReaction fromTLReaction(TLRPC.Reaction reaction) {
VisibleReaction visibleReaction = new VisibleReaction();
if (reaction instanceof TLRPC.TL_reactionEmoji) {
visibleReaction.emojicon = ((TLRPC.TL_reactionEmoji) reaction).emoticon;
} else if (reaction instanceof TLRPC.TL_reactionCustomEmoji) {
visibleReaction.documentId = ((TLRPC.TL_reactionCustomEmoji) reaction).document_id;
}
return visibleReaction;
}
public static VisibleReaction fromEmojicon(TLRPC.TL_availableReaction reaction) {
VisibleReaction visibleReaction = new VisibleReaction();
visibleReaction.emojicon = reaction.reaction;
return visibleReaction;
}
public static VisibleReaction fromEmojicon(String reaction) {
VisibleReaction visibleReaction = new VisibleReaction();
if (reaction.startsWith("animated_")) {
try {
visibleReaction.documentId = Long.parseLong(reaction.substring(9));
} catch (Exception ignore) {
visibleReaction.emojicon = reaction;
}
} else {
visibleReaction.emojicon = reaction;
}
return visibleReaction;
}
public static VisibleReaction fromCustomEmoji(Long documentId) {
VisibleReaction visibleReaction = new VisibleReaction();
visibleReaction.documentId = documentId;
return visibleReaction;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
VisibleReaction that = (VisibleReaction) o;
return documentId == that.documentId && Objects.equals(emojicon, that.emojicon);
}
@Override
public int hashCode() {
return Objects.hash(emojicon, documentId);
}
}
}