mirror of https://github.com/NekoX-Dev/NekoX.git
442 lines
20 KiB
Java
442 lines
20 KiB
Java
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.Canvas;
|
|
import android.graphics.Paint;
|
|
import android.graphics.PorterDuff;
|
|
import android.graphics.PorterDuffXfermode;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.os.SystemClock;
|
|
import android.widget.FrameLayout;
|
|
|
|
import androidx.core.graphics.ColorUtils;
|
|
|
|
import org.telegram.messenger.AccountInstance;
|
|
import org.telegram.messenger.AndroidUtilities;
|
|
import org.telegram.messenger.ImageLocation;
|
|
import org.telegram.messenger.ImageReceiver;
|
|
import org.telegram.messenger.MessageObject;
|
|
import org.telegram.messenger.MessagesController;
|
|
import org.telegram.messenger.UserConfig;
|
|
import org.telegram.messenger.voip.VoIPService;
|
|
import org.telegram.tgnet.ConnectionsManager;
|
|
import org.telegram.tgnet.TLObject;
|
|
import org.telegram.tgnet.TLRPC;
|
|
import org.telegram.ui.ActionBar.Theme;
|
|
import org.telegram.ui.Cells.GroupCallUserCell;
|
|
|
|
import java.util.Random;
|
|
|
|
public class AvatarsImageView extends FrameLayout {
|
|
|
|
DrawingState[] currentStates = new DrawingState[3];
|
|
DrawingState[] animatingStates = new DrawingState[3];
|
|
boolean wasDraw;
|
|
|
|
float transitionProgress = 1f;
|
|
ValueAnimator transitionProgressAnimator;
|
|
boolean updateAfterTransition;
|
|
|
|
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
|
private Paint xRefP = new Paint(Paint.ANTI_ALIAS_FLAG);
|
|
|
|
Runnable updateDelegate;
|
|
int currentStyle;
|
|
boolean centered;
|
|
|
|
public void commitTransition(boolean animated) {
|
|
if (!wasDraw || !animated) {
|
|
transitionProgress = 1f;
|
|
swapStates();
|
|
return;
|
|
}
|
|
|
|
DrawingState[] removedStates = new DrawingState[3];
|
|
boolean changed = false;
|
|
for (int i = 0; i < 3; i++) {
|
|
removedStates[i] = currentStates[i];
|
|
if (currentStates[i].id != animatingStates[i].id) {
|
|
changed = true;
|
|
} else {
|
|
currentStates[i].lastSpeakTime = animatingStates[i].lastSpeakTime;
|
|
}
|
|
}
|
|
if (!changed) {
|
|
transitionProgress = 1f;
|
|
return;
|
|
}
|
|
for (int i = 0; i < 3; i++) {
|
|
boolean found = false;
|
|
for (int j = 0; j < 3; j++) {
|
|
if (currentStates[j].id == animatingStates[i].id) {
|
|
found = true;
|
|
removedStates[j] = null;
|
|
if (i == j) {
|
|
animatingStates[i].animationType = DrawingState.ANIMATION_TYPE_NONE;
|
|
GroupCallUserCell.AvatarWavesDrawable wavesDrawable = animatingStates[i].wavesDrawable;
|
|
animatingStates[i].wavesDrawable = currentStates[i].wavesDrawable;
|
|
currentStates[i].wavesDrawable = wavesDrawable;
|
|
} else {
|
|
animatingStates[i].animationType = DrawingState.ANIMATION_TYPE_MOVE;
|
|
animatingStates[i].moveFromIndex = j;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
animatingStates[i].animationType = DrawingState.ANIMATION_TYPE_IN;
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
if (removedStates[i] != null) {
|
|
removedStates[i].animationType = DrawingState.ANIMATION_TYPE_OUT;
|
|
}
|
|
}
|
|
if (transitionProgressAnimator != null) {
|
|
transitionProgressAnimator.cancel();
|
|
}
|
|
transitionProgress = 0;
|
|
transitionProgressAnimator = ValueAnimator.ofFloat(0, 1f);
|
|
transitionProgressAnimator.addUpdateListener(valueAnimator -> {
|
|
transitionProgress = (float) valueAnimator.getAnimatedValue();
|
|
invalidate();
|
|
});
|
|
transitionProgressAnimator.addListener(new AnimatorListenerAdapter() {
|
|
@Override
|
|
public void onAnimationEnd(Animator animation) {
|
|
if (transitionProgressAnimator != null) {
|
|
transitionProgress = 1f;
|
|
swapStates();
|
|
if (updateAfterTransition) {
|
|
updateAfterTransition = false;
|
|
if (updateDelegate != null) {
|
|
updateDelegate.run();
|
|
}
|
|
}
|
|
invalidate();
|
|
}
|
|
transitionProgressAnimator = null;
|
|
}
|
|
});
|
|
transitionProgressAnimator.setDuration(220);
|
|
transitionProgressAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT);
|
|
transitionProgressAnimator.start();
|
|
invalidate();
|
|
}
|
|
|
|
private void swapStates() {
|
|
for (int i = 0; i < 3; i++) {
|
|
DrawingState state = currentStates[i];
|
|
currentStates[i] = animatingStates[i];
|
|
animatingStates[i] = state;
|
|
}
|
|
}
|
|
|
|
public void updateAfterTransitionEnd() {
|
|
updateAfterTransition = true;
|
|
}
|
|
|
|
public void setDelegate(Runnable delegate) {
|
|
updateDelegate = delegate;
|
|
}
|
|
|
|
public void setStyle(int currentStyle) {
|
|
this.currentStyle = currentStyle;
|
|
invalidate();
|
|
}
|
|
|
|
private static class DrawingState {
|
|
|
|
public static final int ANIMATION_TYPE_NONE = -1;
|
|
public static final int ANIMATION_TYPE_IN = 0;
|
|
public static final int ANIMATION_TYPE_OUT = 1;
|
|
public static final int ANIMATION_TYPE_MOVE = 2;
|
|
|
|
private AvatarDrawable avatarDrawable;
|
|
private GroupCallUserCell.AvatarWavesDrawable wavesDrawable;
|
|
private long lastUpdateTime;
|
|
private long lastSpeakTime;
|
|
private ImageReceiver imageReceiver;
|
|
TLRPC.TL_groupCallParticipant participant;
|
|
|
|
private int id;
|
|
|
|
private int animationType;
|
|
private int moveFromIndex;
|
|
}
|
|
|
|
Random random = new Random();
|
|
|
|
public AvatarsImageView(Context context) {
|
|
super(context);
|
|
for (int a = 0; a < 3; a++) {
|
|
currentStates[a] = new DrawingState();
|
|
currentStates[a].imageReceiver = new ImageReceiver(this);
|
|
currentStates[a].imageReceiver.setRoundRadius(AndroidUtilities.dp(12));
|
|
currentStates[a].avatarDrawable = new AvatarDrawable();
|
|
currentStates[a].avatarDrawable.setTextSize(AndroidUtilities.dp(9));
|
|
|
|
animatingStates[a] = new DrawingState();
|
|
animatingStates[a].imageReceiver = new ImageReceiver(this);
|
|
animatingStates[a].imageReceiver.setRoundRadius(AndroidUtilities.dp(12));
|
|
animatingStates[a].avatarDrawable = new AvatarDrawable();
|
|
animatingStates[a].avatarDrawable.setTextSize(AndroidUtilities.dp(9));
|
|
}
|
|
setWillNotDraw(false);
|
|
xRefP.setColor(0);
|
|
xRefP.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
|
|
}
|
|
|
|
public void setObject(int index, int account, TLObject object) {
|
|
animatingStates[index].id = 0;
|
|
animatingStates[index].participant = null;
|
|
if (object == null) {
|
|
animatingStates[index].imageReceiver.setImageBitmap((Drawable) null);
|
|
invalidate();
|
|
return;
|
|
}
|
|
TLRPC.User currentUser = null;
|
|
TLRPC.Chat currentChat = null;
|
|
animatingStates[index].lastSpeakTime = -1;
|
|
if (object instanceof TLRPC.TL_groupCallParticipant) {
|
|
TLRPC.TL_groupCallParticipant participant = (TLRPC.TL_groupCallParticipant) object;
|
|
animatingStates[index].participant = participant;
|
|
int id = MessageObject.getPeerId(participant.peer);
|
|
if (id > 0) {
|
|
currentUser = MessagesController.getInstance(account).getUser(id);
|
|
animatingStates[index].avatarDrawable.setInfo(currentUser);
|
|
} else {
|
|
currentChat = MessagesController.getInstance(account).getChat(-id);
|
|
animatingStates[index].avatarDrawable.setInfo(currentChat);
|
|
}
|
|
if (currentStyle == 4) {
|
|
if (id == AccountInstance.getInstance(account).getUserConfig().getClientUserId()) {
|
|
animatingStates[index].lastSpeakTime = 0;
|
|
} else {
|
|
animatingStates[index].lastSpeakTime = participant.active_date;
|
|
}
|
|
} else {
|
|
animatingStates[index].lastSpeakTime = participant.active_date;
|
|
}
|
|
animatingStates[index].id = id;
|
|
} else if (object instanceof TLRPC.User) {
|
|
currentUser = (TLRPC.User) object;
|
|
animatingStates[index].avatarDrawable.setInfo(currentUser);
|
|
animatingStates[index].id = currentUser.id;
|
|
} else {
|
|
currentChat = (TLRPC.Chat) object;
|
|
animatingStates[index].avatarDrawable.setInfo(currentChat);
|
|
animatingStates[index].id = -currentChat.id;
|
|
}
|
|
if (currentUser != null) {
|
|
animatingStates[index].imageReceiver.setImage(ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(currentUser, ImageLocation.TYPE_STRIPPED), "50_50", animatingStates[index].avatarDrawable, currentUser, 0);
|
|
} else {
|
|
animatingStates[index].imageReceiver.setImage(ImageLocation.getForUserOrChat(currentChat, ImageLocation.TYPE_SMALL), "50_50", ImageLocation.getForUserOrChat(currentChat, ImageLocation.TYPE_STRIPPED), "50_50", animatingStates[index].avatarDrawable, currentChat, 0);
|
|
}
|
|
animatingStates[index].imageReceiver.setRoundRadius(AndroidUtilities.dp(currentStyle == 4 ? 16 : 12));
|
|
int size = AndroidUtilities.dp(currentStyle == 4 ? 32 : 24);
|
|
animatingStates[index].imageReceiver.setImageCoords(0, 0, size, size);
|
|
invalidate();
|
|
}
|
|
|
|
@SuppressLint("DrawAllocation")
|
|
@Override
|
|
protected void onDraw(Canvas canvas) {
|
|
wasDraw = true;
|
|
|
|
int size = AndroidUtilities.dp(currentStyle == 4 ? 32 : 24);
|
|
int toAdd = AndroidUtilities.dp(currentStyle == 4 ? 24 : 20);
|
|
int drawCount = 0;
|
|
for (int i = 0; i < 3; i++) {
|
|
if (currentStates[i].id != 0) {
|
|
drawCount++;
|
|
}
|
|
}
|
|
int ax = centered ? (getMeasuredWidth() - drawCount * toAdd - AndroidUtilities.dp(currentStyle == 4 ? 8 : 4)) / 2 : (currentStyle == 0 ? 0 : AndroidUtilities.dp(10));
|
|
boolean isMuted = VoIPService.getSharedInstance() != null && VoIPService.getSharedInstance().isMicMute();
|
|
if (currentStyle == 4) {
|
|
paint.setColor(Theme.getColor(Theme.key_inappPlayerBackground));
|
|
} else if (currentStyle != 3) {
|
|
paint.setColor(Theme.getColor(isMuted ? Theme.key_returnToCallMutedBackground : Theme.key_returnToCallBackground));
|
|
}
|
|
|
|
int animateToDrawCount = 0;
|
|
for (int i = 0; i < 3; i++) {
|
|
if (animatingStates[i].id != 0) {
|
|
animateToDrawCount++;
|
|
}
|
|
}
|
|
boolean useAlphaLayer = currentStyle == 0 || currentStyle == 1 || currentStyle == 3 || currentStyle == 4 || currentStyle == 5;
|
|
if (useAlphaLayer) {
|
|
canvas.saveLayerAlpha(0, 0, getMeasuredWidth(), getMeasuredHeight(), 255, Canvas.ALL_SAVE_FLAG);
|
|
}
|
|
for (int a = 2; a >= 0; a--) {
|
|
for (int k = 0; k < 2; k++) {
|
|
if (k == 0 && transitionProgress == 1f) {
|
|
continue;
|
|
}
|
|
DrawingState[] states = k == 0 ? animatingStates : currentStates;
|
|
|
|
|
|
if (k == 1 && transitionProgress != 1f && states[a].animationType != DrawingState.ANIMATION_TYPE_OUT) {
|
|
continue;
|
|
}
|
|
ImageReceiver imageReceiver = states[a].imageReceiver;
|
|
if (!imageReceiver.hasImageSet()) {
|
|
continue;
|
|
}
|
|
if (k == 0) {
|
|
int toAx = centered ? (getMeasuredWidth() - animateToDrawCount * toAdd - AndroidUtilities.dp(currentStyle == 4 ? 8 : 4)) / 2 : AndroidUtilities.dp(10);
|
|
imageReceiver.setImageX(toAx + toAdd * a);
|
|
} else {
|
|
imageReceiver.setImageX(ax + toAdd * a);
|
|
}
|
|
|
|
if (currentStyle == 0) {
|
|
imageReceiver.setImageY((getMeasuredHeight() - size) / 2f);
|
|
} else {
|
|
imageReceiver.setImageY(AndroidUtilities.dp(currentStyle == 4 ? 8 : 6));
|
|
}
|
|
|
|
boolean needRestore = false;
|
|
float alpha = 1f;
|
|
if (transitionProgress != 1f) {
|
|
if (states[a].animationType == DrawingState.ANIMATION_TYPE_OUT) {
|
|
canvas.save();
|
|
canvas.scale(1f - transitionProgress, 1f - transitionProgress, imageReceiver.getCenterX(), imageReceiver.getCenterY());
|
|
needRestore = true;
|
|
alpha = 1f - transitionProgress;
|
|
} else if (states[a].animationType == DrawingState.ANIMATION_TYPE_IN) {
|
|
canvas.save();
|
|
canvas.scale(transitionProgress, transitionProgress, imageReceiver.getCenterX(), imageReceiver.getCenterY());
|
|
alpha = transitionProgress;
|
|
needRestore = true;
|
|
} else if (states[a].animationType == DrawingState.ANIMATION_TYPE_MOVE) {
|
|
int toAx = centered ? (getMeasuredWidth() - animateToDrawCount * toAdd - AndroidUtilities.dp(currentStyle == 4 ? 8 : 4)) / 2 : AndroidUtilities.dp(10);
|
|
int toX = toAx + toAdd * a;
|
|
int fromX = ax + toAdd * states[a].moveFromIndex;
|
|
imageReceiver.setImageX((int) (toX * transitionProgress + fromX * (1f - transitionProgress)));
|
|
} else if (states[a].animationType == DrawingState.ANIMATION_TYPE_NONE && centered) {
|
|
int toAx = (getMeasuredWidth() - animateToDrawCount * toAdd - AndroidUtilities.dp(currentStyle == 4 ? 8 : 4)) / 2;
|
|
int toX = toAx + toAdd * a;
|
|
int fromX = ax + toAdd * a;
|
|
imageReceiver.setImageX((int) (toX * transitionProgress + fromX * (1f - transitionProgress)));
|
|
}
|
|
}
|
|
|
|
float avatarScale = 1f;
|
|
if (a != states.length - 1) {
|
|
if (currentStyle == 1 || currentStyle == 3 || currentStyle == 5) {
|
|
canvas.drawCircle(imageReceiver.getCenterX(), imageReceiver.getCenterY(), AndroidUtilities.dp(13), xRefP);
|
|
if (states[a].wavesDrawable == null) {
|
|
if (currentStyle == 5) {
|
|
states[a].wavesDrawable = new GroupCallUserCell.AvatarWavesDrawable(AndroidUtilities.dp(14), AndroidUtilities.dp(16));
|
|
} else {
|
|
states[a].wavesDrawable = new GroupCallUserCell.AvatarWavesDrawable(AndroidUtilities.dp(17), AndroidUtilities.dp(21));
|
|
}
|
|
}
|
|
if (currentStyle == 5) {
|
|
states[a].wavesDrawable.setColor(ColorUtils.setAlphaComponent(Theme.getColor(Theme.key_voipgroup_speakingText), (int) (255 * 0.3f * alpha)));
|
|
}
|
|
if (states[a].participant != null && states[a].participant.amplitude > 0) {
|
|
states[a].wavesDrawable.setShowWaves(true, this);
|
|
float amplitude = states[a].participant.amplitude * 15f;
|
|
states[a].wavesDrawable.setAmplitude(amplitude);
|
|
} else {
|
|
states[a].wavesDrawable.setShowWaves(false, this);
|
|
}
|
|
if (currentStyle == 5 && (SystemClock.uptimeMillis() - states[a].participant.lastSpeakTime) > 500) {
|
|
updateDelegate.run();
|
|
}
|
|
states[a].wavesDrawable.update();
|
|
if (currentStyle == 5) {
|
|
states[a].wavesDrawable.draw(canvas, imageReceiver.getCenterX(), imageReceiver.getCenterY(), this);
|
|
invalidate();
|
|
}
|
|
avatarScale = states[a].wavesDrawable.getAvatarScale();
|
|
} else if (currentStyle == 4) {
|
|
canvas.drawCircle(imageReceiver.getCenterX(), imageReceiver.getCenterY(), AndroidUtilities.dp(17), xRefP);
|
|
if (states[a].wavesDrawable == null) {
|
|
states[a].wavesDrawable = new GroupCallUserCell.AvatarWavesDrawable(AndroidUtilities.dp(17), AndroidUtilities.dp(21));
|
|
}
|
|
states[a].wavesDrawable.setColor(ColorUtils.setAlphaComponent(Theme.getColor(Theme.key_voipgroup_listeningText), (int) (255 * 0.3f * alpha)));
|
|
long currentTime = System.currentTimeMillis();
|
|
if (currentTime - states[a].lastUpdateTime > 100) {
|
|
states[a].lastUpdateTime = currentTime;
|
|
if (ConnectionsManager.getInstance(UserConfig.selectedAccount).getCurrentTime() - states[a].lastSpeakTime <= 5) {
|
|
states[a].wavesDrawable.setShowWaves(true, this);
|
|
states[a].wavesDrawable.setAmplitude(random.nextInt() % 100);
|
|
} else {
|
|
states[a].wavesDrawable.setShowWaves(false, this);
|
|
states[a].wavesDrawable.setAmplitude(0);
|
|
}
|
|
}
|
|
states[a].wavesDrawable.update();
|
|
states[a].wavesDrawable.draw(canvas, imageReceiver.getCenterX(), imageReceiver.getCenterY(), this);
|
|
avatarScale = states[a].wavesDrawable.getAvatarScale();
|
|
} else {
|
|
if (useAlphaLayer) {
|
|
canvas.drawCircle(imageReceiver.getCenterX(), imageReceiver.getCenterY(), AndroidUtilities.dp(currentStyle == 4 ? 17 : 13), xRefP);
|
|
} else {
|
|
int paintAlpha = paint.getAlpha();
|
|
if (alpha != 1f) {
|
|
paint.setAlpha((int) (paintAlpha * alpha));
|
|
}
|
|
canvas.drawCircle(imageReceiver.getCenterX(), imageReceiver.getCenterY(), AndroidUtilities.dp(currentStyle == 4 ? 17 : 13), paint);
|
|
if (alpha != 1f) {
|
|
paint.setAlpha(paintAlpha);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
imageReceiver.setAlpha(alpha);
|
|
if (avatarScale != 1f) {
|
|
canvas.save();
|
|
canvas.scale(avatarScale, avatarScale, imageReceiver.getCenterX(), imageReceiver.getCenterY());
|
|
imageReceiver.draw(canvas);
|
|
canvas.restore();
|
|
} else {
|
|
imageReceiver.draw(canvas);
|
|
}
|
|
if (needRestore) {
|
|
canvas.restore();
|
|
}
|
|
}
|
|
}
|
|
if (useAlphaLayer) {
|
|
canvas.restore();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onDetachedFromWindow() {
|
|
super.onDetachedFromWindow();
|
|
wasDraw = false;
|
|
for (int a = 0; a < 3; a++) {
|
|
currentStates[a].imageReceiver.onDetachedFromWindow();
|
|
animatingStates[a].imageReceiver.onDetachedFromWindow();
|
|
}
|
|
if (currentStyle == 3) {
|
|
Theme.getFragmentContextViewWavesDrawable().setAmplitude(0);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onAttachedToWindow() {
|
|
super.onAttachedToWindow();
|
|
for (int a = 0; a < 3; a++) {
|
|
currentStates[a].imageReceiver.onAttachedToWindow();
|
|
animatingStates[a].imageReceiver.onAttachedToWindow();
|
|
}
|
|
}
|
|
|
|
public void setCentered(boolean centered) {
|
|
this.centered = centered;
|
|
}
|
|
}
|