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

279 lines
9.7 KiB
Java

package org.telegram.ui.Components;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.SystemClock;
import android.view.View;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.ApplicationLoader;
import org.telegram.messenger.BuildVars;
import org.telegram.messenger.R;
import org.telegram.messenger.SharedConfig;
import org.telegram.messenger.Utilities;
import java.util.ArrayList;
import java.util.Calendar;
public class FireworksOverlay extends View {
private static Paint[] paint;
private static Paint[] heartPaint;
private RectF rect = new RectF();
private long lastUpdateTime;
private boolean started;
private boolean startedFall;
private float speedCoef = 1.0f;
private int fallingDownCount;
private static Drawable[] heartDrawable;
private static final int particlesCount = SharedConfig.getDevicePerfomanceClass() == SharedConfig.PERFORMANCE_CLASS_LOW ? 50 : 60;
private static final int fallParticlesCount = SharedConfig.getDevicePerfomanceClass() == SharedConfig.PERFORMANCE_CLASS_LOW ? 20 : 30;
private boolean isFebruary14;
private static int[] colors = new int[] {
0xff2CBCE8,
0xff9E04D0,
0xffFECB02,
0xffFD2357,
0xff278CFE,
0xff59B86C
};
private static int[] heartColors = new int[] {
0xffE2557B,
0xff5FCDF2,
0xffFFDA69,
0xffDB6363,
0xffE376B0
};
static {
paint = new Paint[colors.length];
for (int a = 0; a < paint.length; a++) {
paint[a] = new Paint(Paint.ANTI_ALIAS_FLAG);
paint[a].setColor(colors[a]);
}
}
private class Particle {
byte type;
byte colorType;
byte side;
byte typeSize;
byte xFinished;
byte finishedStart;
float x;
float y;
short rotation;
float moveX;
float moveY;
private void draw(Canvas canvas) {
if (type == 0) {
canvas.drawCircle(x, y, AndroidUtilities.dp(typeSize), paint[colorType]);
} else if (type == 1) {
rect.set(x - AndroidUtilities.dp(typeSize), y - AndroidUtilities.dp(2), x + AndroidUtilities.dp(typeSize), y + AndroidUtilities.dp(2));
canvas.save();
canvas.rotate(rotation, rect.centerX(), rect.centerY());
canvas.drawRoundRect(rect, AndroidUtilities.dp(2), AndroidUtilities.dp(2), paint[colorType]);
canvas.restore();
} else if (type == 2) {
Drawable drawable = heartDrawable[colorType];
int w = drawable.getIntrinsicWidth() / 2;
int h = drawable.getIntrinsicHeight() / 2;
drawable.setBounds((int) x - w, (int) y - h, (int) x + w, (int) y + h);
canvas.save();
canvas.rotate(rotation, x, y);
canvas.scale(typeSize / 6.0f, typeSize / 6.0f, x, y);
drawable.draw(canvas);
canvas.restore();
}
}
private boolean update(int dt) {
float moveCoef = dt / 16.0f;
x += moveX * moveCoef;
y += moveY * moveCoef;
if (xFinished != 0) {
float dp = AndroidUtilities.dp(1) * 0.5f;
if (xFinished == 1) {
moveX += dp * moveCoef * 0.05f;
if (moveX >= dp) {
xFinished = 2;
}
} else {
moveX -= dp * moveCoef * 0.05f;
if (moveX <= -dp) {
xFinished = 1;
}
}
} else {
if (side == 0) {
if (moveX > 0) {
moveX -= moveCoef * 0.05f;
if (moveX <= 0) {
moveX = 0;
xFinished = finishedStart;
}
}
} else {
if (moveX < 0) {
moveX += moveCoef * 0.05f;
if (moveX >= 0) {
moveX = 0;
xFinished = finishedStart;
}
}
}
}
float yEdge = -AndroidUtilities.dp(1.0f) / 2.0f;
boolean wasNegative = moveY < yEdge;
if (moveY > yEdge) {
moveY += AndroidUtilities.dp(1.0f) / 3.0f * moveCoef * speedCoef;
} else {
moveY += AndroidUtilities.dp(1.0f) / 3.0f * moveCoef;
}
if (wasNegative && moveY > yEdge) {
fallingDownCount++;
}
if (type == 1 || type == 2) {
rotation += moveCoef * 10;
if (rotation > 360) {
rotation -= 360;
}
}
return y >= getMeasuredHeight();
}
}
private ArrayList<Particle> particles = new ArrayList<>(particlesCount + fallParticlesCount);
public FireworksOverlay(Context context) {
super(context);
}
private void loadHeartDrawables() {
if (heartDrawable != null) {
return;
}
heartDrawable = new Drawable[heartColors.length];
for (int a = 0; a < heartDrawable.length; a++) {
heartDrawable[a] = ApplicationLoader.applicationContext.getResources().getDrawable(R.drawable.heart_confetti).mutate();
heartDrawable[a].setColorFilter(new PorterDuffColorFilter(heartColors[a], PorterDuff.Mode.MULTIPLY));
}
}
private Particle createParticle(boolean fall) {
Particle particle = new Particle();
particle.type = (byte) Utilities.random.nextInt(2);
if (isFebruary14 && particle.type == 0) {
particle.type = 2;
particle.colorType = (byte) Utilities.random.nextInt(heartColors.length);
} else {
particle.colorType = (byte) Utilities.random.nextInt(colors.length);
}
particle.side = (byte) Utilities.random.nextInt(2);
particle.finishedStart = (byte) (1 + Utilities.random.nextInt(2));
if (particle.type == 0 || particle.type == 2) {
particle.typeSize = (byte) (4 + Utilities.random.nextFloat() * 2);
} else {
particle.typeSize = (byte) (4 + Utilities.random.nextFloat() * 4);
}
if (fall) {
particle.y = -Utilities.random.nextFloat() * getMeasuredHeight() * 1.2f;
particle.x = AndroidUtilities.dp(5) + Utilities.random.nextInt(getMeasuredWidth() - AndroidUtilities.dp(10));
particle.xFinished = particle.finishedStart;
} else {
int xOffset = AndroidUtilities.dp(4 + Utilities.random.nextInt(10));
int yOffset = getMeasuredHeight() / 4;
if (particle.side == 0) {
particle.x = -xOffset;
} else {
particle.x = getMeasuredWidth() + xOffset;
}
particle.moveX = (particle.side == 0 ? 1 : -1) * (AndroidUtilities.dp(1.2f) + Utilities.random.nextFloat() * AndroidUtilities.dp(4));
particle.moveY = -(AndroidUtilities.dp(4) + Utilities.random.nextFloat() * AndroidUtilities.dp(4));
particle.y = yOffset / 2 + Utilities.random.nextInt(yOffset * 2);
}
return particle;
}
public void start() {
particles.clear();
if (Build.VERSION.SDK_INT >= 18) {
setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
started = true;
startedFall = false;
fallingDownCount = 0;
speedCoef = 1.0f;
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
int day = calendar.get(Calendar.DAY_OF_MONTH);
int month = calendar.get(Calendar.MONTH);
isFebruary14 = month == 1 && (BuildVars.DEBUG_PRIVATE_VERSION || day == 14);
if (isFebruary14) {
loadHeartDrawables();
}
for (int a = 0; a < particlesCount; a++) {
particles.add(createParticle(false));
}
invalidate();
}
private void startFall() {
if (startedFall) {
return;
}
startedFall = true;
for (int a = 0; a < fallParticlesCount; a++) {
particles.add(createParticle(true));
}
}
@Override
protected void onDraw(Canvas canvas) {
long newTime = SystemClock.elapsedRealtime();
int dt = (int) (newTime - lastUpdateTime);
lastUpdateTime = newTime;
if (dt > 18) {
dt = 16;
}
for (int a = 0, N = particles.size(); a < N; a++) {
Particle p = particles.get(a);
p.draw(canvas);
if (p.update(dt)) {
particles.remove(a);
a--;
N--;
}
}
if (fallingDownCount >= particlesCount / 2 && speedCoef > 0.2f) {
startFall();
speedCoef -= dt / 16.0f * 0.15f;
if (speedCoef < 0.2f) {
speedCoef = 0.2f;
}
}
if (!particles.isEmpty()) {
invalidate();
} else {
started = false;
if (Build.VERSION.SDK_INT >= 18) {
AndroidUtilities.runOnUIThread(() -> {
if (!started) {
setLayerType(View.LAYER_TYPE_NONE, null);
}
});
}
}
}
}