2021-07-15 16:24:57 +02:00
|
|
|
package org.telegram.ui;
|
|
|
|
|
|
|
|
import android.animation.Animator;
|
|
|
|
import android.animation.AnimatorListenerAdapter;
|
|
|
|
import android.animation.ValueAnimator;
|
|
|
|
import android.annotation.SuppressLint;
|
|
|
|
import android.graphics.Bitmap;
|
|
|
|
import android.graphics.Canvas;
|
|
|
|
import android.graphics.Color;
|
|
|
|
import android.graphics.LinearGradient;
|
|
|
|
import android.graphics.Matrix;
|
|
|
|
import android.graphics.Paint;
|
|
|
|
import android.graphics.PorterDuff;
|
|
|
|
import android.graphics.PorterDuffXfermode;
|
|
|
|
import android.graphics.Shader;
|
|
|
|
import android.graphics.drawable.Drawable;
|
|
|
|
import android.os.Build;
|
|
|
|
import android.text.Layout;
|
2021-07-19 17:56:43 +02:00
|
|
|
import android.text.Spannable;
|
2021-07-15 16:24:57 +02:00
|
|
|
import android.text.SpannableString;
|
|
|
|
import android.text.StaticLayout;
|
|
|
|
import android.text.TextPaint;
|
|
|
|
import android.text.TextUtils;
|
|
|
|
import android.view.View;
|
|
|
|
import android.view.animation.LinearInterpolator;
|
|
|
|
|
|
|
|
import androidx.core.graphics.ColorUtils;
|
|
|
|
import androidx.recyclerview.widget.ChatListItemAnimator;
|
|
|
|
|
|
|
|
import org.telegram.messenger.AndroidUtilities;
|
|
|
|
import org.telegram.messenger.Emoji;
|
|
|
|
import org.telegram.messenger.MessageObject;
|
|
|
|
import org.telegram.messenger.NotificationCenter;
|
|
|
|
import org.telegram.messenger.SharedConfig;
|
|
|
|
import org.telegram.messenger.UserConfig;
|
|
|
|
import org.telegram.tgnet.TLRPC;
|
|
|
|
import org.telegram.ui.ActionBar.SimpleTextView;
|
|
|
|
import org.telegram.ui.ActionBar.Theme;
|
|
|
|
import org.telegram.ui.Cells.ChatMessageCell;
|
|
|
|
import org.telegram.ui.Components.ChatActivityEnterView;
|
|
|
|
import org.telegram.ui.Components.CubicBezierInterpolator;
|
|
|
|
import org.telegram.ui.Components.EmptyStubSpan;
|
|
|
|
import org.telegram.ui.Components.RecyclerListView;
|
2021-12-30 11:52:40 +01:00
|
|
|
import org.telegram.ui.Components.spoilers.SpoilerEffect;
|
2021-07-15 16:24:57 +02:00
|
|
|
|
|
|
|
public class TextMessageEnterTransition implements MessageEnterTransitionContainer.Transition {
|
|
|
|
float fromRadius;
|
|
|
|
float progress;
|
|
|
|
|
|
|
|
Paint bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
|
|
|
Bitmap textLayoutBitmap;
|
|
|
|
Bitmap textLayoutBitmapRtl;
|
|
|
|
Bitmap crossfadeTextBitmap;
|
|
|
|
|
|
|
|
boolean hasReply;
|
|
|
|
private ValueAnimator animator;
|
|
|
|
boolean initBitmaps = false;
|
|
|
|
|
|
|
|
float replyFromStartX;
|
|
|
|
float replyFromStartY;
|
|
|
|
float replyFromObjectStartY;
|
|
|
|
int replayFromColor;
|
|
|
|
int replayObjectFromColor;
|
|
|
|
float crossfadeTextOffset;
|
|
|
|
|
|
|
|
float drawableFromTop;
|
|
|
|
|
|
|
|
MessageObject currentMessageObject;
|
|
|
|
|
|
|
|
boolean drawBitmaps = false;
|
|
|
|
float toXOffset;
|
|
|
|
float toXOffsetRtl;
|
|
|
|
|
|
|
|
boolean crossfade;
|
2021-07-30 16:49:55 +02:00
|
|
|
boolean changeColor;
|
2021-07-15 16:24:57 +02:00
|
|
|
|
|
|
|
StaticLayout layout;
|
|
|
|
StaticLayout rtlLayout;
|
|
|
|
|
|
|
|
ChatMessageCell messageView;
|
|
|
|
RecyclerListView listView;
|
|
|
|
MessageEnterTransitionContainer container;
|
|
|
|
private Matrix gradientMatrix;
|
|
|
|
private Paint gradientPaint;
|
|
|
|
private int messageId;
|
|
|
|
private float drawableFromBottom;
|
|
|
|
private float scaleY;
|
|
|
|
private float fromStartX;
|
|
|
|
private float fromStartY;
|
|
|
|
private ChatActivity chatActivity;
|
|
|
|
private LinearGradient gradientShader;
|
|
|
|
private float scaleFrom;
|
|
|
|
|
|
|
|
private final int currentAccount;
|
|
|
|
private int animationIndex = -1;
|
|
|
|
MessageObject.TextLayoutBlock textLayoutBlock;
|
|
|
|
Drawable fromMessageDrawable;
|
|
|
|
ChatActivityEnterView enterView;
|
|
|
|
|
|
|
|
float textX;
|
|
|
|
float textY;
|
|
|
|
|
|
|
|
float replyNameDx;
|
|
|
|
float replyMessageDx;
|
|
|
|
|
2021-07-30 16:49:55 +02:00
|
|
|
int fromColor;
|
|
|
|
int toColor;
|
2021-09-20 07:54:41 +02:00
|
|
|
private final Theme.ResourcesProvider resourcesProvider;
|
2021-07-30 16:49:55 +02:00
|
|
|
|
2021-07-15 16:24:57 +02:00
|
|
|
@SuppressLint("WrongConstant")
|
2021-09-20 07:54:41 +02:00
|
|
|
public TextMessageEnterTransition(ChatMessageCell messageView, ChatActivity chatActivity, RecyclerListView listView, MessageEnterTransitionContainer container, Theme.ResourcesProvider resourcesProvider) {
|
|
|
|
this.resourcesProvider = resourcesProvider;
|
2021-07-15 16:24:57 +02:00
|
|
|
currentAccount = UserConfig.selectedAccount;
|
2021-12-07 14:02:02 +01:00
|
|
|
if (messageView.getMessageObject().textLayoutBlocks.size() > 1 || messageView.getMessageObject().textLayoutBlocks.isEmpty() || messageView.getMessageObject().textLayoutBlocks.get(0).textLayout.getLineCount() > 10) {
|
2021-07-15 16:24:57 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.messageView = messageView;
|
|
|
|
this.listView = listView;
|
|
|
|
this.container = container;
|
|
|
|
this.chatActivity = chatActivity;
|
|
|
|
enterView = chatActivity.getChatActivityEnterView();
|
|
|
|
|
|
|
|
ChatActivityEnterView chatActivityEnterView = chatActivity.getChatActivityEnterView();
|
2021-07-19 17:56:43 +02:00
|
|
|
if (chatActivityEnterView == null || chatActivityEnterView.getEditField() == null || chatActivityEnterView.getEditField().getLayout() == null) {
|
|
|
|
return;
|
|
|
|
}
|
2021-07-15 16:24:57 +02:00
|
|
|
|
|
|
|
fromRadius = chatActivityEnterView.getRecordCicle().drawingCircleRadius;
|
|
|
|
bitmapPaint.setFilterBitmap(true);
|
|
|
|
currentMessageObject = messageView.getMessageObject();
|
|
|
|
|
|
|
|
if (!messageView.getTransitionParams().wasDraw) {
|
|
|
|
messageView.draw(new Canvas());
|
|
|
|
}
|
|
|
|
|
|
|
|
messageView.setEnterTransitionInProgress(true);
|
|
|
|
|
|
|
|
CharSequence editText = chatActivityEnterView.getEditField().getLayout().getText();
|
|
|
|
CharSequence text = messageView.getMessageObject().messageText;
|
|
|
|
|
|
|
|
crossfade = false;
|
|
|
|
int linesOffset = 0;
|
|
|
|
int layoutH = chatActivityEnterView.getEditField().getLayout().getHeight();
|
|
|
|
TextPaint textPaint = Theme.chat_msgTextPaint;
|
|
|
|
int emojiSize = AndroidUtilities.dp(20);
|
|
|
|
if (messageView.getMessageObject().getEmojiOnlyCount() != 0) {
|
|
|
|
if (messageView.getMessageObject().getEmojiOnlyCount() == 1) {
|
|
|
|
textPaint = Theme.chat_msgTextPaintOneEmoji;
|
|
|
|
emojiSize = AndroidUtilities.dp(32);
|
|
|
|
} else if (messageView.getMessageObject().getEmojiOnlyCount() == 2) {
|
|
|
|
textPaint = Theme.chat_msgTextPaintTwoEmoji;
|
|
|
|
emojiSize = AndroidUtilities.dp(28);
|
|
|
|
} else if (messageView.getMessageObject().getEmojiOnlyCount() == 3) {
|
|
|
|
textPaint = Theme.chat_msgTextPaintThreeEmoji;
|
|
|
|
emojiSize = AndroidUtilities.dp(24);
|
|
|
|
}
|
|
|
|
}
|
2021-07-19 17:56:43 +02:00
|
|
|
boolean containsSpans = false;
|
|
|
|
if (text instanceof Spannable) {
|
|
|
|
Spannable spannable = (Spannable) text;
|
|
|
|
Object[] objects = spannable.getSpans(0, text.length(), Object.class);
|
|
|
|
for (int i = 0; i < objects.length; i++) {
|
|
|
|
if (!(objects[i] instanceof Emoji.EmojiSpan)) {
|
|
|
|
containsSpans = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (editText.length() != text.length() || containsSpans) {
|
2021-07-15 16:24:57 +02:00
|
|
|
crossfade = true;
|
|
|
|
String str = editText.toString();
|
|
|
|
String trimmedStr = str.trim();
|
|
|
|
int i = str.indexOf(trimmedStr);
|
|
|
|
if (i > 0) {
|
|
|
|
linesOffset = chatActivityEnterView.getEditField().getLayout().getLineTop(chatActivityEnterView.getEditField().getLayout().getLineForOffset(i));
|
|
|
|
layoutH = chatActivityEnterView.getEditField().getLayout().getLineBottom(chatActivityEnterView.getEditField().getLayout().getLineForOffset(i + trimmedStr.length())) - linesOffset;
|
|
|
|
}
|
|
|
|
text = Emoji.replaceEmoji(trimmedStr, textPaint.getFontMetricsInt(), emojiSize, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
scaleFrom = chatActivityEnterView.getEditField().getTextSize() / textPaint.getTextSize();
|
|
|
|
|
|
|
|
int n = chatActivityEnterView.getEditField().getLayout().getLineCount();
|
|
|
|
int width = (int) (chatActivityEnterView.getEditField().getLayout().getWidth() / scaleFrom);
|
|
|
|
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
|
|
layout = StaticLayout.Builder.obtain(text, 0, text.length(), textPaint, width)
|
|
|
|
.setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY)
|
|
|
|
.setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE)
|
|
|
|
.setAlignment(Layout.Alignment.ALIGN_NORMAL)
|
|
|
|
.build();
|
|
|
|
} else {
|
|
|
|
layout = new StaticLayout(text, textPaint, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
|
|
|
|
}
|
|
|
|
float textViewY = chatActivityEnterView.getY() + chatActivityEnterView.getEditField().getY() + ((View) chatActivityEnterView.getEditField().getParent()).getY() + ((View) chatActivityEnterView.getEditField().getParent().getParent()).getY();
|
|
|
|
fromStartX = chatActivityEnterView.getX() + chatActivityEnterView.getEditField().getX() + ((View) chatActivityEnterView.getEditField().getParent()).getX() + ((View) chatActivityEnterView.getEditField().getParent().getParent()).getX();
|
|
|
|
fromStartY = textViewY + AndroidUtilities.dp(10) - chatActivityEnterView.getEditField().getScrollY() + linesOffset;
|
|
|
|
toXOffset = 0;
|
|
|
|
float minX = Float.MAX_VALUE;
|
|
|
|
for (int i = 0; i < layout.getLineCount(); i++) {
|
|
|
|
float begin = layout.getLineLeft(i);
|
|
|
|
if (begin < minX) {
|
|
|
|
minX = begin;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (minX != Float.MAX_VALUE) {
|
|
|
|
toXOffset = minX;
|
|
|
|
}
|
|
|
|
|
|
|
|
scaleY = (layoutH) / (layout.getHeight() * scaleFrom);
|
|
|
|
|
|
|
|
drawableFromTop = textViewY + AndroidUtilities.dp(4);
|
|
|
|
if (enterView.isTopViewVisible()) {
|
|
|
|
drawableFromTop -= AndroidUtilities.dp(12);
|
|
|
|
}
|
|
|
|
drawableFromBottom = textViewY + chatActivityEnterView.getEditField().getMeasuredHeight();
|
|
|
|
textLayoutBlock = messageView.getMessageObject().textLayoutBlocks.get(0);
|
|
|
|
StaticLayout messageTextLayout = textLayoutBlock.textLayout;
|
|
|
|
int normalLinesCount = 0;
|
|
|
|
int rtlLinesCount = 0;
|
|
|
|
|
2021-09-20 07:54:41 +02:00
|
|
|
if (Math.abs(ColorUtils.calculateLuminance(getThemedColor(Theme.key_chat_messageTextOut)) - ColorUtils.calculateLuminance(getThemedColor(Theme.key_chat_messagePanelText))) > 0.2f) {
|
2021-07-30 16:49:55 +02:00
|
|
|
crossfade = true;
|
|
|
|
changeColor = true;
|
|
|
|
}
|
|
|
|
|
2021-09-20 07:54:41 +02:00
|
|
|
fromColor = getThemedColor(Theme.key_chat_messagePanelText);
|
|
|
|
toColor = getThemedColor(Theme.key_chat_messageTextOut);
|
2021-08-31 21:06:39 +02:00
|
|
|
|
2021-07-15 16:24:57 +02:00
|
|
|
if (messageTextLayout.getLineCount() == layout.getLineCount()) {
|
|
|
|
n = messageTextLayout.getLineCount();
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
if (isRtlLine(layout, i)) {
|
|
|
|
rtlLinesCount++;
|
|
|
|
} else {
|
|
|
|
normalLinesCount++;
|
|
|
|
}
|
|
|
|
if (messageTextLayout.getLineEnd(i) != layout.getLineEnd(i)) {
|
|
|
|
crossfade = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
crossfade = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
minX = Float.MAX_VALUE;
|
|
|
|
if (!crossfade && rtlLinesCount > 0 && normalLinesCount > 0) {
|
|
|
|
SpannableString normalText = new SpannableString(text);
|
|
|
|
SpannableString rtlText = new SpannableString(text);
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
if (isRtlLine(layout, i)) {
|
|
|
|
normalText.setSpan(new EmptyStubSpan(), layout.getLineStart(i), layout.getLineEnd(i), 0);
|
|
|
|
float begin = layout.getLineLeft(i);
|
|
|
|
if (begin < minX) {
|
|
|
|
minX = begin;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
rtlText.setSpan(new EmptyStubSpan(), layout.getLineStart(i), layout.getLineEnd(i), 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
|
|
layout = StaticLayout.Builder.obtain(normalText, 0, normalText.length(), textPaint, width)
|
|
|
|
.setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY)
|
|
|
|
.setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE)
|
|
|
|
.setAlignment(Layout.Alignment.ALIGN_NORMAL)
|
|
|
|
.build();
|
|
|
|
|
|
|
|
rtlLayout = StaticLayout.Builder.obtain(rtlText, 0, rtlText.length(), textPaint, width)
|
|
|
|
.setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY)
|
|
|
|
.setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE)
|
|
|
|
.setAlignment(Layout.Alignment.ALIGN_NORMAL)
|
|
|
|
.build();
|
|
|
|
} else {
|
|
|
|
layout = new StaticLayout(normalText, textPaint, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0, false);
|
|
|
|
rtlLayout = new StaticLayout(rtlText, textPaint, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
toXOffsetRtl = layout.getWidth() - messageView.getMessageObject().textLayoutBlocks.get(0).textLayout.getWidth();
|
|
|
|
|
|
|
|
try {
|
|
|
|
if (drawBitmaps) {
|
|
|
|
textLayoutBitmap = Bitmap.createBitmap(layout.getWidth(), layout.getHeight(), Bitmap.Config.ARGB_8888);
|
|
|
|
Canvas bitmapCanvas = new Canvas(textLayoutBitmap);
|
|
|
|
layout.draw(bitmapCanvas);
|
|
|
|
|
|
|
|
if (rtlLayout != null) {
|
|
|
|
textLayoutBitmapRtl = Bitmap.createBitmap(rtlLayout.getWidth(), rtlLayout.getHeight(), Bitmap.Config.ARGB_8888);
|
|
|
|
bitmapCanvas = new Canvas(textLayoutBitmapRtl);
|
|
|
|
rtlLayout.draw(bitmapCanvas);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (crossfade) {
|
|
|
|
if (messageView.getMeasuredHeight() < listView.getMeasuredHeight()) {
|
|
|
|
crossfadeTextOffset = 0;
|
|
|
|
crossfadeTextBitmap = Bitmap.createBitmap(messageView.getMeasuredWidth(), messageView.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
|
|
|
|
} else {
|
|
|
|
crossfadeTextOffset = messageView.getTop();
|
|
|
|
crossfadeTextBitmap = Bitmap.createBitmap(messageView.getMeasuredWidth(), listView.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
drawBitmaps = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
hasReply = messageView.getMessageObject().getReplyMsgId() != 0 && messageView.replyNameLayout != null;
|
|
|
|
|
|
|
|
if (hasReply) {
|
|
|
|
SimpleTextView replyNameTextView = chatActivity.getReplyNameTextView();
|
|
|
|
replyFromStartX = replyNameTextView.getX() + ((View) replyNameTextView.getParent()).getX();
|
|
|
|
replyFromStartY = replyNameTextView.getY() + ((View) replyNameTextView.getParent().getParent()).getY() + ((View) replyNameTextView.getParent().getParent().getParent()).getY();
|
|
|
|
replyNameTextView = chatActivity.getReplyObjectTextView();
|
|
|
|
replyFromObjectStartY = replyNameTextView.getY() + ((View) replyNameTextView.getParent().getParent()).getY() + ((View) replyNameTextView.getParent().getParent().getParent()).getY();
|
|
|
|
|
|
|
|
replayFromColor = chatActivity.getReplyNameTextView().getTextColor();
|
|
|
|
replayObjectFromColor = chatActivity.getReplyObjectTextView().getTextColor();
|
|
|
|
drawableFromTop -= AndroidUtilities.dp(46);
|
|
|
|
}
|
|
|
|
|
|
|
|
gradientMatrix = new Matrix();
|
|
|
|
gradientPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
|
|
|
gradientPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
|
|
|
|
|
|
|
|
gradientShader = new LinearGradient(0, AndroidUtilities.dp(12), 0, 0, 0, 0xFF000000, Shader.TileMode.CLAMP);
|
|
|
|
gradientPaint.setShader(gradientShader);
|
|
|
|
|
|
|
|
messageId = messageView.getMessageObject().stableId;
|
|
|
|
|
|
|
|
chatActivityEnterView.getEditField().setAlpha(0f);
|
|
|
|
chatActivityEnterView.setTextTransitionIsRunning(true);
|
|
|
|
|
|
|
|
if (messageView.replyNameLayout != null && messageView.replyNameLayout.getText().length() > 1) {
|
|
|
|
if (messageView.replyNameLayout.getPrimaryHorizontal(0) != 0) {
|
|
|
|
replyNameDx = messageView.replyNameLayout.getWidth() - messageView.replyNameLayout.getLineWidth(0);
|
|
|
|
}
|
|
|
|
}
|
2021-08-31 21:06:39 +02:00
|
|
|
if (messageView.replyTextLayout != null && messageView.replyTextLayout.getText().length() >= 1) {
|
2021-07-15 16:24:57 +02:00
|
|
|
if (messageView.replyTextLayout.getPrimaryHorizontal(0) != 0) {
|
|
|
|
replyMessageDx = messageView.replyTextLayout.getWidth() - messageView.replyTextLayout.getLineWidth(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
animator = ValueAnimator.ofFloat(0f, 1f);
|
|
|
|
animator.addUpdateListener(valueAnimator -> {
|
|
|
|
progress = (float) valueAnimator.getAnimatedValue();
|
|
|
|
chatActivityEnterView.getEditField().setAlpha(progress);
|
|
|
|
container.invalidate();
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
animator.setInterpolator(new LinearInterpolator());
|
|
|
|
animator.setDuration(ChatListItemAnimator.DEFAULT_DURATION);
|
|
|
|
|
|
|
|
container.addTransition(this);
|
|
|
|
animationIndex = NotificationCenter.getInstance(currentAccount).setAnimationInProgress(animationIndex, null);
|
|
|
|
|
|
|
|
animator.addListener(new AnimatorListenerAdapter() {
|
|
|
|
@Override
|
|
|
|
public void onAnimationEnd(Animator animation) {
|
|
|
|
NotificationCenter.getInstance(currentAccount).onAnimationFinish(animationIndex);
|
|
|
|
container.removeTransition(TextMessageEnterTransition.this);
|
|
|
|
messageView.setEnterTransitionInProgress(false);
|
|
|
|
chatActivityEnterView.setTextTransitionIsRunning(false);
|
|
|
|
chatActivityEnterView.getEditField().setAlpha(1f);
|
|
|
|
chatActivity.getReplyNameTextView().setAlpha(1f);
|
|
|
|
chatActivity.getReplyObjectTextView().setAlpha(1f);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
if (SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_HIGH) {
|
2021-08-31 21:06:39 +02:00
|
|
|
Theme.MessageDrawable drawable = messageView.getCurrentBackgroundDrawable(true);
|
|
|
|
if (drawable != null) {
|
2021-09-20 07:54:41 +02:00
|
|
|
fromMessageDrawable = drawable.getTransitionDrawable(getThemedColor(Theme.key_chat_messagePanelBackground));
|
2021-08-31 21:06:39 +02:00
|
|
|
}
|
2021-07-15 16:24:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void start() {
|
|
|
|
if (animator != null) {
|
|
|
|
animator.start();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean isRtlLine(Layout layout, int line) {
|
|
|
|
return layout.getLineRight(line) == layout.getWidth() && layout.getLineLeft(line) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
float lastMessageX;
|
|
|
|
float lastMessageY;
|
|
|
|
|
|
|
|
public void onDraw(Canvas canvas) {
|
|
|
|
if (drawBitmaps && !initBitmaps && crossfadeTextBitmap != null && messageView.getTransitionParams().wasDraw) {
|
|
|
|
initBitmaps = true;
|
|
|
|
Canvas bitmapCanvas = new Canvas(crossfadeTextBitmap);
|
|
|
|
bitmapCanvas.translate(0, crossfadeTextOffset);
|
|
|
|
messageView.drawMessageText(bitmapCanvas, messageView.getMessageObject().textLayoutBlocks, true, 1f, true);
|
|
|
|
}
|
|
|
|
float listViewBottom = listView.getY() - container.getY() + listView.getMeasuredHeight();
|
|
|
|
|
|
|
|
float fromX = fromStartX - container.getX();
|
|
|
|
float fromY = fromStartY - container.getY();
|
|
|
|
|
|
|
|
textX = messageView.getTextX();
|
|
|
|
textY = messageView.getTextY();
|
|
|
|
|
|
|
|
float messageViewX;
|
|
|
|
float messageViewY;
|
|
|
|
|
|
|
|
if (messageView.getMessageObject().stableId != messageId) {
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
messageViewX = messageView.getX() + listView.getX() - container.getX();
|
|
|
|
messageViewY = messageView.getTop() + listView.getTop() - container.getY();
|
|
|
|
messageViewY += enterView.getTopViewHeight();
|
|
|
|
|
|
|
|
lastMessageX = messageViewX;
|
|
|
|
lastMessageY = messageViewY;
|
|
|
|
}
|
|
|
|
|
|
|
|
float progress = ChatListItemAnimator.DEFAULT_INTERPOLATOR.getInterpolation(this.progress);
|
2021-08-31 21:06:39 +02:00
|
|
|
float alphaProgress = this.progress > 0.4f ? 1f : this.progress / 0.4f;
|
2021-07-15 16:24:57 +02:00
|
|
|
|
|
|
|
float p2 = CubicBezierInterpolator.EASE_OUT_QUINT.getInterpolation(this.progress);
|
|
|
|
float progressX = CubicBezierInterpolator.EASE_OUT.getInterpolation(p2);
|
|
|
|
|
|
|
|
float toX = messageViewX + textX;
|
|
|
|
float toY = messageViewY + textY;
|
|
|
|
|
|
|
|
int clipBottom = (int) (container.getMeasuredHeight() * (1f - progressX) + listViewBottom * progressX);
|
|
|
|
boolean messageViewOverscrolled = messageView.getBottom() - AndroidUtilities.dp(4) > listView.getMeasuredHeight();
|
|
|
|
boolean clipBottomWithAlpha = messageViewOverscrolled && (messageViewY + messageView.getMeasuredHeight() - AndroidUtilities.dp(8) > clipBottom) && container.getMeasuredHeight() > 0;
|
|
|
|
|
|
|
|
if (clipBottomWithAlpha) {
|
|
|
|
canvas.saveLayerAlpha(0, Math.max(0, messageViewY), container.getMeasuredWidth(), container.getMeasuredHeight(), 255, Canvas.ALL_SAVE_FLAG);
|
|
|
|
}
|
|
|
|
canvas.save();
|
2021-07-30 16:49:55 +02:00
|
|
|
canvas.clipRect(0, listView.getY() + chatActivity.getChatListViewPadding() - container.getY() - AndroidUtilities.dp(3), container.getMeasuredWidth(), container.getMeasuredHeight());
|
2021-07-15 16:24:57 +02:00
|
|
|
canvas.save();
|
|
|
|
float drawableX = messageViewX + messageView.getBackgroundDrawableLeft() + (fromX - (toX - toXOffset)) * (1f - progressX);
|
|
|
|
float drawableToTop = messageViewY + messageView.getBackgroundDrawableTop();
|
|
|
|
float drawableTop = (drawableFromTop - container.getY()) * (1f - progress) + (drawableToTop) * progress;
|
|
|
|
float drawableH = messageView.getBackgroundDrawableBottom() - messageView.getBackgroundDrawableTop();
|
|
|
|
float drawableBottom = (drawableFromBottom - container.getY()) * (1f - progress) + (drawableToTop + drawableH) * progress;
|
|
|
|
int drawableRight = (int) (messageViewX + messageView.getBackgroundDrawableRight() + AndroidUtilities.dp(4) * (1f - progressX));
|
|
|
|
Theme.MessageDrawable drawable = messageView.getCurrentBackgroundDrawable(true);
|
|
|
|
|
|
|
|
if (drawable != null) {
|
2021-08-31 21:06:39 +02:00
|
|
|
messageView.setBackgroundTopY(listView.getTop() - container.getTop());
|
2021-07-15 16:24:57 +02:00
|
|
|
Drawable shadowDrawable = drawable.getShadowDrawable();
|
|
|
|
|
|
|
|
if (alphaProgress != 1f && fromMessageDrawable != null) {
|
2021-08-31 21:06:39 +02:00
|
|
|
fromMessageDrawable.setBounds((int) drawableX, (int) drawableTop, drawableRight, (int) drawableBottom);
|
2021-07-15 16:24:57 +02:00
|
|
|
fromMessageDrawable.draw(canvas);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (shadowDrawable != null) {
|
|
|
|
shadowDrawable.setAlpha((int) (255 * progressX));
|
2021-08-31 21:06:39 +02:00
|
|
|
shadowDrawable.setBounds((int) drawableX, (int) drawableTop, drawableRight, (int) drawableBottom);
|
2021-07-15 16:24:57 +02:00
|
|
|
shadowDrawable.draw(canvas);
|
|
|
|
shadowDrawable.setAlpha(255);
|
|
|
|
}
|
|
|
|
|
|
|
|
drawable.setAlpha((int) (255 * alphaProgress));
|
2021-08-31 21:06:39 +02:00
|
|
|
drawable.setBounds((int) drawableX, (int) drawableTop, drawableRight, (int) drawableBottom);
|
|
|
|
drawable.setDrawFullBubble(true);
|
2021-07-15 16:24:57 +02:00
|
|
|
drawable.draw(canvas);
|
2021-08-31 21:06:39 +02:00
|
|
|
drawable.setDrawFullBubble(false);
|
2021-07-15 16:24:57 +02:00
|
|
|
drawable.setAlpha(255);
|
|
|
|
}
|
|
|
|
canvas.restore();
|
|
|
|
|
|
|
|
|
|
|
|
canvas.save();
|
|
|
|
if (currentMessageObject.isOutOwner()) {
|
|
|
|
canvas.clipRect(
|
|
|
|
drawableX + AndroidUtilities.dp(4), drawableTop + AndroidUtilities.dp(4),
|
|
|
|
drawableRight - AndroidUtilities.dp(10), drawableBottom - AndroidUtilities.dp(4)
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
canvas.clipRect(
|
|
|
|
drawableX + AndroidUtilities.dp(4), drawableTop + AndroidUtilities.dp(4),
|
|
|
|
drawableRight - AndroidUtilities.dp(4), drawableBottom - AndroidUtilities.dp(4)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
canvas.translate(messageView.getLeft() + listView.getX() - container.getX(), messageViewY + (fromY - toY) * (1f - progress));
|
|
|
|
messageView.drawTime(canvas, alphaProgress, false);
|
|
|
|
messageView.drawNamesLayout(canvas, alphaProgress);
|
|
|
|
messageView.drawCommentButton(canvas, alphaProgress);
|
|
|
|
messageView.drawCaptionLayout(canvas, false, alphaProgress);
|
|
|
|
messageView.drawLinkPreview(canvas, alphaProgress);
|
|
|
|
canvas.restore();
|
|
|
|
|
|
|
|
|
|
|
|
if (hasReply) {
|
|
|
|
chatActivity.getReplyNameTextView().setAlpha(0f);
|
|
|
|
chatActivity.getReplyObjectTextView().setAlpha(0f);
|
|
|
|
|
|
|
|
float fromReplayX = replyFromStartX - container.getX();
|
|
|
|
float fromReplayY = replyFromStartY - container.getY();
|
|
|
|
float toReplayX = messageViewX + messageView.replyStartX;
|
|
|
|
float toReplayY = messageViewY + messageView.replyStartY;
|
|
|
|
|
|
|
|
int replyMessageColor;
|
|
|
|
int replyOwnerMessageColor;
|
|
|
|
int replyLineColor;
|
|
|
|
if (currentMessageObject.hasValidReplyMessageObject() && (currentMessageObject.replyMessageObject.type == 0 || !TextUtils.isEmpty(currentMessageObject.replyMessageObject.caption)) && !(currentMessageObject.replyMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGame || currentMessageObject.replyMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaInvoice)) {
|
2021-09-20 07:54:41 +02:00
|
|
|
replyMessageColor = getThemedColor(Theme.key_chat_outReplyMessageText);
|
2021-07-15 16:24:57 +02:00
|
|
|
} else {
|
2021-09-20 07:54:41 +02:00
|
|
|
replyMessageColor = getThemedColor(Theme.key_chat_outReplyMediaMessageText);
|
2021-07-15 16:24:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (currentMessageObject.isOutOwner()) {
|
2021-09-20 07:54:41 +02:00
|
|
|
replyOwnerMessageColor = getThemedColor(Theme.key_chat_outReplyNameText);
|
|
|
|
replyLineColor = getThemedColor(Theme.key_chat_outReplyLine);
|
2021-07-15 16:24:57 +02:00
|
|
|
} else {
|
2021-09-20 07:54:41 +02:00
|
|
|
replyOwnerMessageColor = getThemedColor(Theme.key_chat_inReplyNameText);
|
|
|
|
replyLineColor = getThemedColor(Theme.key_chat_inReplyLine);
|
2021-07-15 16:24:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Theme.chat_replyTextPaint.setColor(ColorUtils.blendARGB(replayObjectFromColor, replyMessageColor, progress));
|
|
|
|
Theme.chat_replyNamePaint.setColor(ColorUtils.blendARGB(replayFromColor, replyOwnerMessageColor, progress));
|
|
|
|
|
|
|
|
if (messageView.needReplyImage) {
|
|
|
|
fromReplayX -= AndroidUtilities.dp(44);
|
|
|
|
}
|
|
|
|
float replyX = fromReplayX * (1f - progressX) + toReplayX * progressX;
|
|
|
|
float replyY = (fromReplayY + AndroidUtilities.dp(12) * progress) * (1f - progress) + toReplayY * progress;
|
|
|
|
|
|
|
|
Theme.chat_replyLinePaint.setColor(ColorUtils.setAlphaComponent(replyLineColor, (int) (Color.alpha(replyLineColor) * progressX)));
|
|
|
|
canvas.drawRect(replyX, replyY, replyX + AndroidUtilities.dp(2), replyY + AndroidUtilities.dp(35), Theme.chat_replyLinePaint);
|
|
|
|
|
|
|
|
canvas.save();
|
|
|
|
canvas.translate(AndroidUtilities.dp(10) * progressX, 0);
|
|
|
|
|
|
|
|
if (messageView.needReplyImage) {
|
|
|
|
canvas.save();
|
|
|
|
messageView.replyImageReceiver.setImageCoords(replyX, replyY, AndroidUtilities.dp(35), AndroidUtilities.dp(35));
|
|
|
|
messageView.replyImageReceiver.draw(canvas);
|
|
|
|
canvas.translate(replyX, replyY);
|
|
|
|
canvas.restore();
|
|
|
|
canvas.translate(AndroidUtilities.dp(44), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
float replyToMessageX = toReplayX - replyMessageDx;
|
|
|
|
float replyToNameX = toReplayX - replyNameDx;
|
|
|
|
|
2021-08-31 21:06:39 +02:00
|
|
|
float replyMessageX =(fromReplayX - replyMessageDx) * (1f - progressX) + replyToMessageX * progressX;
|
2021-07-15 16:24:57 +02:00
|
|
|
float replyNameX = fromReplayX * (1f - progressX) + replyToNameX * progressX;
|
|
|
|
|
2021-08-31 21:06:39 +02:00
|
|
|
if (messageView.replyNameLayout != null) {
|
|
|
|
canvas.save();
|
|
|
|
canvas.translate(replyNameX, replyY);
|
|
|
|
messageView.replyNameLayout.draw(canvas);
|
|
|
|
canvas.restore();
|
|
|
|
}
|
2021-07-15 16:24:57 +02:00
|
|
|
|
2021-08-31 21:06:39 +02:00
|
|
|
if (messageView.replyTextLayout != null) {
|
|
|
|
canvas.save();
|
|
|
|
canvas.translate(replyMessageX, replyY + AndroidUtilities.dp(19));
|
2021-12-30 11:52:40 +01:00
|
|
|
|
|
|
|
canvas.save();
|
|
|
|
SpoilerEffect.clipOutCanvas(canvas, messageView.replySpoilers);
|
2021-08-31 21:06:39 +02:00
|
|
|
messageView.replyTextLayout.draw(canvas);
|
|
|
|
canvas.restore();
|
2021-12-30 11:52:40 +01:00
|
|
|
|
|
|
|
for (SpoilerEffect eff : messageView.replySpoilers) {
|
|
|
|
if (eff.shouldInvalidateColor()) eff.setColor(messageView.replyTextLayout.getPaint().getColor());
|
|
|
|
eff.draw(canvas);
|
|
|
|
}
|
|
|
|
|
|
|
|
canvas.restore();
|
2021-08-31 21:06:39 +02:00
|
|
|
}
|
2021-07-15 16:24:57 +02:00
|
|
|
|
|
|
|
canvas.restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
canvas.save();
|
|
|
|
|
2021-07-19 17:56:43 +02:00
|
|
|
canvas.clipRect(drawableX + AndroidUtilities.dp(4), drawableTop + AndroidUtilities.dp(4), drawableRight - AndroidUtilities.dp(4), drawableBottom - AndroidUtilities.dp(4));
|
|
|
|
|
|
|
|
float scale = progressX + scaleFrom * (1f - progressX);
|
|
|
|
float scale2;
|
|
|
|
if (drawBitmaps) {
|
|
|
|
scale2 = progressX + scaleY * (1f - progressX);
|
|
|
|
} else {
|
|
|
|
scale2 = 1f;
|
|
|
|
}
|
|
|
|
|
|
|
|
canvas.save();
|
|
|
|
canvas.translate(fromX * (1f - progressX) + (toX - toXOffset) * progressX, fromY * (1f - progress) + (toY + textLayoutBlock.textYOffset) * progress);
|
|
|
|
canvas.scale(scale, scale * scale2, 0, 0);
|
2021-07-30 16:49:55 +02:00
|
|
|
|
2021-07-19 17:56:43 +02:00
|
|
|
if (drawBitmaps) {
|
|
|
|
if (crossfade) {
|
|
|
|
bitmapPaint.setAlpha((int) (255 * (1f - alphaProgress)));
|
|
|
|
}
|
|
|
|
canvas.drawBitmap(textLayoutBitmap, 0, 0, bitmapPaint);
|
|
|
|
} else {
|
2021-07-30 16:49:55 +02:00
|
|
|
if (crossfade && changeColor) {
|
2021-09-20 07:54:41 +02:00
|
|
|
int oldColor = layout.getPaint().getColor();
|
|
|
|
int oldAlpha = Color.alpha(oldColor);
|
|
|
|
layout.getPaint().setColor(ColorUtils.setAlphaComponent(ColorUtils.blendARGB(fromColor, toColor, alphaProgress), (int) (oldAlpha * (1f - alphaProgress))));
|
2021-07-30 16:49:55 +02:00
|
|
|
layout.draw(canvas);
|
2021-09-20 07:54:41 +02:00
|
|
|
layout.getPaint().setColor(oldColor);
|
2021-07-30 16:49:55 +02:00
|
|
|
} else if (crossfade) {
|
2021-07-19 17:56:43 +02:00
|
|
|
int oldAlpha = Theme.chat_msgTextPaint.getAlpha();
|
|
|
|
Theme.chat_msgTextPaint.setAlpha((int) (oldAlpha * (1f - alphaProgress)));
|
|
|
|
layout.draw(canvas);
|
|
|
|
Theme.chat_msgTextPaint.setAlpha(oldAlpha);
|
2021-07-15 16:24:57 +02:00
|
|
|
} else {
|
2021-07-19 17:56:43 +02:00
|
|
|
layout.draw(canvas);
|
2021-07-15 16:24:57 +02:00
|
|
|
}
|
2021-07-19 17:56:43 +02:00
|
|
|
}
|
|
|
|
canvas.restore();
|
|
|
|
|
|
|
|
if (rtlLayout != null) {
|
2021-07-15 16:24:57 +02:00
|
|
|
canvas.save();
|
2021-07-19 17:56:43 +02:00
|
|
|
canvas.translate(fromX * (1f - progressX) + (toX - toXOffsetRtl) * progressX, fromY * (1f - progress) + (toY + textLayoutBlock.textYOffset) * progress);
|
2021-07-15 16:24:57 +02:00
|
|
|
canvas.scale(scale, scale * scale2, 0, 0);
|
|
|
|
if (drawBitmaps) {
|
|
|
|
if (crossfade) {
|
|
|
|
bitmapPaint.setAlpha((int) (255 * (1f - alphaProgress)));
|
|
|
|
}
|
2021-07-19 17:56:43 +02:00
|
|
|
canvas.drawBitmap(textLayoutBitmapRtl, 0, 0, bitmapPaint);
|
2021-07-15 16:24:57 +02:00
|
|
|
} else {
|
2021-07-30 16:49:55 +02:00
|
|
|
if (crossfade && changeColor) {
|
2021-09-20 07:54:41 +02:00
|
|
|
int oldColor = rtlLayout.getPaint().getColor();
|
|
|
|
int oldAlpha = Color.alpha(oldColor);
|
|
|
|
rtlLayout.getPaint().setColor(ColorUtils.setAlphaComponent(ColorUtils.blendARGB(fromColor, toColor, alphaProgress), (int) (oldAlpha * (1f - alphaProgress))));
|
2021-07-30 16:49:55 +02:00
|
|
|
rtlLayout.draw(canvas);
|
2021-09-20 07:54:41 +02:00
|
|
|
rtlLayout.getPaint().setColor(oldColor);
|
2021-07-30 16:49:55 +02:00
|
|
|
} else if (crossfade) {
|
2021-09-20 07:54:41 +02:00
|
|
|
int oldAlpha = rtlLayout.getPaint().getAlpha();
|
|
|
|
rtlLayout.getPaint().setAlpha((int) (oldAlpha * (1f - alphaProgress)));
|
2021-07-19 17:56:43 +02:00
|
|
|
rtlLayout.draw(canvas);
|
2021-09-20 07:54:41 +02:00
|
|
|
rtlLayout.getPaint().setAlpha(oldAlpha);
|
2021-07-15 16:24:57 +02:00
|
|
|
} else {
|
2021-07-19 17:56:43 +02:00
|
|
|
rtlLayout.draw(canvas);
|
2021-07-15 16:24:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
canvas.restore();
|
2021-07-19 17:56:43 +02:00
|
|
|
}
|
2021-07-15 16:24:57 +02:00
|
|
|
|
2021-07-19 17:56:43 +02:00
|
|
|
if (crossfade) {
|
|
|
|
canvas.save();
|
|
|
|
canvas.translate(messageView.getLeft() + listView.getX() - container.getX() + (fromX - toX) * (1f - progressX), messageViewY + (fromY - toY) * (1f - progress));
|
|
|
|
canvas.scale(scale, scale * scale2, messageView.getTextX(), messageView.getTextY());
|
|
|
|
canvas.translate(0, -crossfadeTextOffset);
|
2021-07-15 16:24:57 +02:00
|
|
|
|
2021-07-19 17:56:43 +02:00
|
|
|
if (crossfadeTextBitmap != null) {
|
|
|
|
bitmapPaint.setAlpha((int) (255 * alphaProgress));
|
|
|
|
canvas.drawBitmap(crossfadeTextBitmap, 0, 0, bitmapPaint);
|
|
|
|
} else {
|
2021-08-31 21:06:39 +02:00
|
|
|
int oldColor = Theme.chat_msgTextPaint.getColor();
|
|
|
|
Theme.chat_msgTextPaint.setColor(toColor);
|
|
|
|
messageView.drawMessageText(canvas, messageView.getMessageObject().textLayoutBlocks, false, alphaProgress, true);
|
|
|
|
if (Theme.chat_msgTextPaint.getColor() != oldColor) {
|
|
|
|
Theme.chat_msgTextPaint.setColor(oldColor);
|
|
|
|
}
|
2021-07-15 16:24:57 +02:00
|
|
|
}
|
2021-07-19 17:56:43 +02:00
|
|
|
canvas.restore();
|
|
|
|
}
|
2021-07-15 16:24:57 +02:00
|
|
|
|
|
|
|
canvas.restore();
|
|
|
|
|
|
|
|
if (clipBottomWithAlpha) {
|
|
|
|
gradientMatrix.setTranslate(0, clipBottom);
|
|
|
|
gradientShader.setLocalMatrix(gradientMatrix);
|
|
|
|
canvas.drawRect(0, clipBottom, container.getMeasuredWidth(), container.getMeasuredHeight(), gradientPaint);
|
|
|
|
canvas.restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
float sendProgress = this.progress > 0.4f ? 1f : this.progress / 0.4f;
|
|
|
|
if (sendProgress == 1f) {
|
|
|
|
enterView.setTextTransitionIsRunning(false);
|
|
|
|
}
|
|
|
|
if (enterView.getSendButton().getVisibility() == View.VISIBLE && sendProgress < 1f) {
|
|
|
|
canvas.save();
|
2021-07-19 17:56:43 +02:00
|
|
|
canvas.translate(enterView.getX() + enterView.getSendButton().getX() + ((View) enterView.getSendButton().getParent()).getX() + ((View) enterView.getSendButton().getParent().getParent()).getX() - container.getX() + AndroidUtilities.dp(52) * sendProgress, enterView.getY() + enterView.getSendButton().getY() + ((View) enterView.getSendButton().getParent()).getY() + ((View) enterView.getSendButton().getParent().getParent()).getY() - container.getY());
|
2021-07-15 16:24:57 +02:00
|
|
|
enterView.getSendButton().draw(canvas);
|
|
|
|
canvas.restore();
|
|
|
|
canvas.restore();
|
|
|
|
}
|
|
|
|
}
|
2021-09-20 07:54:41 +02:00
|
|
|
|
|
|
|
private int getThemedColor(String key) {
|
|
|
|
Integer color = resourcesProvider != null ? resourcesProvider.getColor(key) : null;
|
|
|
|
return color != null ? color : Theme.getColor(key);
|
|
|
|
}
|
2021-07-15 16:24:57 +02:00
|
|
|
}
|