mirror of https://github.com/NekoX-Dev/NekoX.git
403 lines
18 KiB
Java
403 lines
18 KiB
Java
package org.telegram.ui.Components.Reactions;
|
|
|
|
import android.content.Context;
|
|
import android.graphics.Canvas;
|
|
import android.graphics.PixelFormat;
|
|
import android.view.View;
|
|
import android.view.WindowManager;
|
|
import android.widget.FrameLayout;
|
|
|
|
import org.telegram.messenger.AndroidUtilities;
|
|
import org.telegram.messenger.ImageLocation;
|
|
import org.telegram.messenger.MediaDataController;
|
|
import org.telegram.messenger.MessagesController;
|
|
import org.telegram.tgnet.TLRPC;
|
|
import org.telegram.ui.ActionBar.BaseFragment;
|
|
import org.telegram.ui.Cells.ChatMessageCell;
|
|
import org.telegram.ui.ChatActivity;
|
|
import org.telegram.ui.Components.BackupImageView;
|
|
import org.telegram.ui.Components.CubicBezierInterpolator;
|
|
import org.telegram.ui.Components.ReactionsContainerLayout;
|
|
|
|
public class ReactionsEffectOverlay {
|
|
|
|
public static ReactionsEffectOverlay currentOverlay;
|
|
|
|
private final AnimationView effectImageView;
|
|
private final AnimationView emojiImageView;
|
|
private final AnimationView emojiStaticImageView;
|
|
private final FrameLayout container;
|
|
boolean animateIn;
|
|
float animateInProgress;
|
|
float animateOutProgress;
|
|
|
|
FrameLayout windowView;
|
|
BackupImageView backupImageView;
|
|
private static int unicPrefix;
|
|
|
|
int[] loc = new int[2];
|
|
private WindowManager windowManager;
|
|
private boolean dismissed;
|
|
private float dismissProgress;
|
|
private final int messageId;
|
|
private final long groupId;
|
|
private final String reaction;
|
|
private float lastDrawnToX;
|
|
private float lastDrawnToY;
|
|
private boolean started;
|
|
private ReactionsContainerLayout.ReactionHolderView holderView = null;
|
|
private boolean wasScrolled;
|
|
|
|
|
|
private ReactionsEffectOverlay(Context context, BaseFragment fragment, ReactionsContainerLayout reactionsLayout, ChatMessageCell cell, float x, float y, String reaction, int currentAccount) {
|
|
this.messageId = cell.getMessageObject().getId();
|
|
this.groupId = cell.getMessageObject().getGroupId();
|
|
this.reaction = reaction;
|
|
ReactionsLayoutInBubble.ReactionButton reactionButton = cell.getReactionButton(reaction);
|
|
float fromX, fromY, fromHeight, fromWidth;
|
|
ChatActivity chatActivity = (fragment instanceof ChatActivity) ? (ChatActivity) fragment : null;
|
|
if (reactionsLayout != null) {
|
|
for (int i = 0; i < reactionsLayout.recyclerListView.getChildCount(); i++) {
|
|
if (((ReactionsContainerLayout.ReactionHolderView) reactionsLayout.recyclerListView.getChildAt(i)).currentReaction.reaction.equals(reaction)) {
|
|
holderView = ((ReactionsContainerLayout.ReactionHolderView) reactionsLayout.recyclerListView.getChildAt(i));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
boolean fromHolder = holderView != null || (x != 0 && y != 0);
|
|
if (holderView != null) {
|
|
reactionsLayout.getLocationOnScreen(loc);
|
|
fromX = loc[0] + holderView.getX() + holderView.backupImageView.getX() + AndroidUtilities.dp(16);
|
|
fromY = loc[1] + holderView.getY() + holderView.backupImageView.getY() + AndroidUtilities.dp(16);
|
|
fromHeight = holderView.backupImageView.getWidth();
|
|
} else if (reactionButton != null) {
|
|
cell.getLocationInWindow(loc);
|
|
fromX = loc[0] + cell.reactionsLayoutInBubble.x + reactionButton.x + reactionButton.imageReceiver.getImageX();
|
|
fromY = loc[1] + cell.reactionsLayoutInBubble.y + reactionButton.y + reactionButton.imageReceiver.getImageY();
|
|
fromHeight = reactionButton.imageReceiver.getImageHeight();
|
|
fromWidth = reactionButton.imageReceiver.getImageWidth();
|
|
} else {
|
|
((View) cell.getParent()).getLocationInWindow(loc);
|
|
fromX = loc[0] + x;
|
|
fromY = loc[1] + y;
|
|
fromHeight = 0;
|
|
fromWidth = 0;
|
|
}
|
|
|
|
int size = Math.round(Math.min(AndroidUtilities.dp(350), Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y)) * 0.8f);
|
|
int sizeForFilter = (int) (2f * size / AndroidUtilities.density);
|
|
int emojiSize = size >> 1;
|
|
int emojiSizeForFilter = sizeForFilter >> 1;
|
|
|
|
float fromScale = fromHeight / (float) emojiSize;
|
|
animateInProgress = 0f;
|
|
animateOutProgress = 0f;
|
|
|
|
container = new FrameLayout(context);
|
|
windowView = new FrameLayout(context) {
|
|
|
|
@Override
|
|
protected void dispatchDraw(Canvas canvas) {
|
|
if (dismissed) {
|
|
if (dismissProgress != 1f) {
|
|
dismissProgress += 16 / 150f;
|
|
if (dismissProgress > 1f) {
|
|
dismissProgress = 1f;
|
|
AndroidUtilities.runOnUIThread(() -> {
|
|
try {
|
|
windowManager.removeView(windowView);
|
|
} catch (Exception e) {
|
|
|
|
}
|
|
});
|
|
}
|
|
}
|
|
if (dismissProgress != 1f) {
|
|
setAlpha(1f - dismissProgress);
|
|
super.dispatchDraw(canvas);
|
|
}
|
|
invalidate();
|
|
return;
|
|
}
|
|
if (!started) {
|
|
invalidate();
|
|
return;
|
|
} else {
|
|
if (holderView != null) {
|
|
holderView.backupImageView.setAlpha(0);
|
|
}
|
|
}
|
|
ChatMessageCell drawingCell;
|
|
if (fragment instanceof ChatActivity) {
|
|
drawingCell = ((ChatActivity) fragment).findMessageCell(messageId);
|
|
} else {
|
|
drawingCell = cell;
|
|
}
|
|
float toX, toY;
|
|
if (drawingCell != null) {
|
|
cell.getLocationInWindow(loc);
|
|
|
|
ReactionsLayoutInBubble.ReactionButton reactionButton = cell.getReactionButton(reaction);
|
|
toX = loc[0] + cell.reactionsLayoutInBubble.x;
|
|
toY = loc[1] + cell.reactionsLayoutInBubble.y;
|
|
if (reactionButton != null) {
|
|
toX += reactionButton.x + reactionButton.imageReceiver.getImageX();
|
|
toY += reactionButton.y + reactionButton.imageReceiver.getImageY();
|
|
}
|
|
if (chatActivity != null) {
|
|
toY += chatActivity.drawingChatLisViewYoffset;
|
|
}
|
|
|
|
lastDrawnToX = toX;
|
|
lastDrawnToY = toY;
|
|
} else {
|
|
toX = lastDrawnToX;
|
|
toY = lastDrawnToY;
|
|
}
|
|
float previewX = toX - emojiSize / 2f;
|
|
float previewY = toY - emojiSize / 2f;
|
|
if (fragment.getParentActivity() != null && fragment.getFragmentView().getParent() != null && fragment.getFragmentView().getVisibility() == View.VISIBLE && fragment.getFragmentView() != null) {
|
|
fragment.getFragmentView().getLocationOnScreen(loc);
|
|
setAlpha(((View) fragment.getFragmentView().getParent()).getAlpha());
|
|
} else {
|
|
return;
|
|
}
|
|
if (previewX < loc[0]) {
|
|
previewX = loc[0];
|
|
}
|
|
if (previewX + emojiSize > loc[0] + getMeasuredWidth()) {
|
|
previewX = loc[0] + getMeasuredWidth() - emojiSize;
|
|
}
|
|
|
|
float animateInProgressX, animateInProgressY;
|
|
float animateOutProgress = CubicBezierInterpolator.DEFAULT.getInterpolation(ReactionsEffectOverlay.this.animateOutProgress);
|
|
if (fromHolder) {
|
|
animateInProgressX = CubicBezierInterpolator.EASE_OUT_QUINT.getInterpolation(animateInProgress);
|
|
animateInProgressY = CubicBezierInterpolator.DEFAULT.getInterpolation(animateInProgress);
|
|
} else {
|
|
animateInProgressX = animateInProgressY = animateInProgress;
|
|
}
|
|
|
|
float scale = animateInProgressX + (1f - animateInProgressX) * fromScale;
|
|
|
|
float toScale;
|
|
if (cell.getMessageObject().shouldDrawReactionsInLayout()) {
|
|
toScale = AndroidUtilities.dp(20) / (float) emojiSize;
|
|
} else {
|
|
toScale = AndroidUtilities.dp(14) / (float) emojiSize;
|
|
}
|
|
|
|
|
|
float x = fromX * (1f - animateInProgressX) + previewX * animateInProgressX;
|
|
float y = fromY * (1f - animateInProgressY) + previewY * animateInProgressY;
|
|
|
|
effectImageView.setTranslationX(x);
|
|
effectImageView.setTranslationY(y);
|
|
effectImageView.setAlpha((1f - animateOutProgress));
|
|
effectImageView.setScaleX(scale);
|
|
effectImageView.setScaleY(scale);
|
|
|
|
if (animateOutProgress != 0) {
|
|
scale = scale * (1f - animateOutProgress) + toScale * animateOutProgress;
|
|
x = x * (1f - animateOutProgress) + toX * animateOutProgress;
|
|
y = y * (1f - animateOutProgress) + toY * animateOutProgress;
|
|
}
|
|
|
|
|
|
emojiStaticImageView.setAlpha(animateOutProgress > 0.7f ? (animateOutProgress - 0.7f) / 0.3f : 0);
|
|
//emojiImageView.setAlpha(animateOutProgress < 0.5f ? 1f - (animateOutProgress / 0.5f) : 0f);
|
|
container.setTranslationX(x);
|
|
container.setTranslationY(y);
|
|
|
|
container.setScaleX(scale);
|
|
container.setScaleY(scale);
|
|
|
|
super.dispatchDraw(canvas);
|
|
|
|
if (emojiImageView.wasPlaying && animateInProgress != 1f) {
|
|
if (fromHolder) {
|
|
animateInProgress += 16f / 350f;
|
|
} else {
|
|
animateInProgress += 16f / 220f;
|
|
}
|
|
if (animateInProgress > 1f) {
|
|
animateInProgress = 1f;
|
|
}
|
|
}
|
|
|
|
if (wasScrolled || (emojiImageView.wasPlaying && emojiImageView.getImageReceiver().getLottieAnimation() != null && !emojiImageView.getImageReceiver().getLottieAnimation().isRunning())) {
|
|
if (ReactionsEffectOverlay.this.animateOutProgress != 1f) {
|
|
ReactionsEffectOverlay.this.animateOutProgress += 16f / 220f;
|
|
if (ReactionsEffectOverlay.this.animateOutProgress > 1f) {
|
|
ReactionsEffectOverlay.this.animateOutProgress = 1f;
|
|
currentOverlay = null;
|
|
cell.invalidate();
|
|
if (cell.getCurrentMessagesGroup() != null && cell.getParent() != null) {
|
|
((View) cell.getParent()).invalidate();
|
|
}
|
|
AndroidUtilities.runOnUIThread(() -> {
|
|
try {
|
|
windowManager.removeView(windowView);
|
|
} catch (Exception e) {
|
|
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
invalidate();
|
|
}
|
|
};
|
|
effectImageView = new AnimationView(context);
|
|
emojiImageView = new AnimationView(context);
|
|
emojiStaticImageView = new AnimationView(context);
|
|
TLRPC.TL_availableReaction availableReaction = MediaDataController.getInstance(currentAccount).getReactionsMap().get(reaction);
|
|
if (availableReaction != null) {
|
|
TLRPC.Document document = availableReaction.effect_animation;
|
|
|
|
effectImageView.getImageReceiver().setUniqKeyPrefix((unicPrefix++) + "_" + cell.getMessageObject().getId() + "_");
|
|
effectImageView.setImage(ImageLocation.getForDocument(document), sizeForFilter + "_" + sizeForFilter + "_pcache", null, null, 0, null);
|
|
|
|
effectImageView.getImageReceiver().setAutoRepeat(0);
|
|
effectImageView.getImageReceiver().setAllowStartAnimation(false);
|
|
|
|
if (effectImageView.getImageReceiver().getLottieAnimation() != null) {
|
|
effectImageView.getImageReceiver().getLottieAnimation().setCurrentFrame(0, false);
|
|
effectImageView.getImageReceiver().getLottieAnimation().start();
|
|
}
|
|
|
|
document = availableReaction.activate_animation;
|
|
emojiImageView.getImageReceiver().setUniqKeyPrefix((unicPrefix++) + "_" + cell.getMessageObject().getId() + "_");
|
|
emojiImageView.setImage(ImageLocation.getForDocument(document), emojiSizeForFilter + "_" + emojiSizeForFilter, null, null, 0, null);
|
|
|
|
emojiImageView.getImageReceiver().setAutoRepeat(0);
|
|
emojiImageView.getImageReceiver().setAllowStartAnimation(false);
|
|
|
|
if (emojiImageView.getImageReceiver().getLottieAnimation() != null) {
|
|
emojiImageView.getImageReceiver().getLottieAnimation().setCurrentFrame(0, false);
|
|
emojiImageView.getImageReceiver().getLottieAnimation().start();
|
|
}
|
|
|
|
int topOffset = (size - emojiSize) >> 1;
|
|
int leftOffset = size - emojiSize;
|
|
container.addView(emojiImageView);
|
|
emojiImageView.getLayoutParams().width = emojiSize;
|
|
emojiImageView.getLayoutParams().height = emojiSize;
|
|
((FrameLayout.LayoutParams) emojiImageView.getLayoutParams()).topMargin = topOffset;
|
|
((FrameLayout.LayoutParams) emojiImageView.getLayoutParams()).leftMargin = leftOffset;
|
|
|
|
emojiStaticImageView.getImageReceiver().setImage(ImageLocation.getForDocument(availableReaction.static_icon), "40_40", null, "webp", availableReaction, 1);
|
|
|
|
container.addView(emojiStaticImageView);
|
|
emojiStaticImageView.getLayoutParams().width = emojiSize;
|
|
emojiStaticImageView.getLayoutParams().height = emojiSize;
|
|
((FrameLayout.LayoutParams) emojiStaticImageView.getLayoutParams()).topMargin = topOffset;
|
|
((FrameLayout.LayoutParams) emojiStaticImageView.getLayoutParams()).leftMargin = leftOffset;
|
|
|
|
|
|
windowView.addView(container);
|
|
container.getLayoutParams().width = size;
|
|
container.getLayoutParams().height = size;
|
|
((FrameLayout.LayoutParams) container.getLayoutParams()).topMargin = -topOffset;
|
|
((FrameLayout.LayoutParams) container.getLayoutParams()).leftMargin = -leftOffset;
|
|
|
|
windowView.addView(effectImageView);
|
|
effectImageView.getLayoutParams().width = size;
|
|
effectImageView.getLayoutParams().height = size;
|
|
|
|
effectImageView.getLayoutParams().width = size;
|
|
effectImageView.getLayoutParams().height = size;
|
|
((FrameLayout.LayoutParams) effectImageView.getLayoutParams()).topMargin = -topOffset;
|
|
((FrameLayout.LayoutParams) effectImageView.getLayoutParams()).leftMargin = -leftOffset;
|
|
|
|
container.setPivotX(leftOffset);
|
|
container.setPivotY(topOffset);
|
|
}
|
|
}
|
|
|
|
public static void show(BaseFragment baseFragment, ReactionsContainerLayout reactionsLayout, ChatMessageCell cell, float x, float y, String reaction, int currentAccount) {
|
|
if (cell == null) {
|
|
return;
|
|
}
|
|
boolean animationEnabled = MessagesController.getGlobalMainSettings().getBoolean("view_animations", true);
|
|
if (!animationEnabled) {
|
|
return;
|
|
}
|
|
ReactionsEffectOverlay reactionsEffectOverlay = new ReactionsEffectOverlay(baseFragment.getParentActivity(), baseFragment, reactionsLayout, cell, x, y, reaction, currentAccount);
|
|
currentOverlay = reactionsEffectOverlay;
|
|
|
|
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
|
|
lp.width = lp.height = WindowManager.LayoutParams.MATCH_PARENT;
|
|
lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
|
|
lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
|
|
lp.format = PixelFormat.TRANSLUCENT;
|
|
|
|
reactionsEffectOverlay.windowManager = baseFragment.getParentActivity().getWindowManager();
|
|
reactionsEffectOverlay.windowManager.addView(reactionsEffectOverlay.windowView, lp);
|
|
cell.invalidate();
|
|
if (cell.getCurrentMessagesGroup() != null && cell.getParent() != null) {
|
|
((View) cell.getParent()).invalidate();
|
|
}
|
|
}
|
|
|
|
public static void startAnimation() {
|
|
if (currentOverlay != null) {
|
|
currentOverlay.started = true;
|
|
}
|
|
}
|
|
|
|
public static void removeCurrent(boolean instant) {
|
|
if (currentOverlay != null) {
|
|
if (instant) {
|
|
try {
|
|
currentOverlay.windowManager.removeView(currentOverlay.windowView);
|
|
} catch (Exception e) {
|
|
|
|
}
|
|
} else {
|
|
currentOverlay.dismissed = true;
|
|
}
|
|
}
|
|
currentOverlay = null;
|
|
}
|
|
|
|
public static boolean isPlaying(int messageId, long groupId, String reaction) {
|
|
if (currentOverlay != null) {
|
|
return ((currentOverlay.groupId != 0 && groupId == currentOverlay.groupId) || messageId == currentOverlay.messageId) && currentOverlay.reaction.equals(reaction);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
private class AnimationView extends BackupImageView {
|
|
|
|
public AnimationView(Context context) {
|
|
super(context);
|
|
}
|
|
|
|
boolean wasPlaying;
|
|
|
|
@Override
|
|
protected void onDraw(Canvas canvas) {
|
|
if (getImageReceiver().getLottieAnimation() != null && getImageReceiver().getLottieAnimation().isRunning()) {
|
|
wasPlaying = true;
|
|
}
|
|
if (!wasPlaying && getImageReceiver().getLottieAnimation() != null && !getImageReceiver().getLottieAnimation().isRunning()) {
|
|
getImageReceiver().getLottieAnimation().setCurrentFrame(0, false);
|
|
getImageReceiver().getLottieAnimation().start();
|
|
}
|
|
super.onDraw(canvas);
|
|
}
|
|
}
|
|
|
|
public static void onScrolled(int dy) {
|
|
if (currentOverlay != null) {
|
|
currentOverlay.lastDrawnToY -= dy;
|
|
if (dy != 0) {
|
|
currentOverlay.wasScrolled = true;
|
|
}
|
|
}
|
|
}
|
|
}
|