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

508 lines
20 KiB
Java

/*
* This is the source code of Telegram for Android v. 2.0.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2018.
*/
package org.telegram.ui.Components;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.ui.ActionBar.Theme;
public class RadialProgress {
private long lastUpdateTime = 0;
private float radOffset = 0;
private float currentProgress = 0;
private float animationProgressStart = 0;
private long currentProgressTime = 0;
private float animatedProgressValue = 0;
private RectF progressRect = new RectF();
private RectF cicleRect = new RectF();
private View parent;
private float animatedAlphaValue = 1.0f;
private boolean previousCheckDrawable;
private boolean currentMiniWithRound;
private boolean previousMiniWithRound;
private boolean currentWithRound;
private boolean previousWithRound;
private Drawable currentMiniDrawable;
private Drawable previousMiniDrawable;
private Drawable currentDrawable;
private Drawable previousDrawable;
private boolean hideCurrentDrawable;
private int progressColor = 0xffffffff;
private Paint progressPaint;
private Paint miniProgressPaint;
private Paint miniProgressBackgroundPaint;
private boolean drawMiniProgress;
private CheckDrawable checkDrawable;
private Drawable checkBackgroundDrawable;
private int diff = AndroidUtilities.dp(4);
private static DecelerateInterpolator decelerateInterpolator;
private boolean alphaForPrevious = true;
private boolean alphaForMiniPrevious = true;
private Bitmap miniDrawBitmap;
private Canvas miniDrawCanvas;
private float overrideAlpha = 1.0f;
private class CheckDrawable extends Drawable {
private Paint paint;
private float progress;
public CheckDrawable() {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(AndroidUtilities.dp(3));
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setColor(0xffffffff);
}
public void resetProgress(boolean animated) {
progress = animated ? 0.0f : 1.0f;
}
public boolean updateAnimation(long dt) {
if (progress < 1.0f) {
progress += dt / 700.0f;
if (progress > 1.0f) {
progress = 1.0f;
}
return true;
}
return false;
}
@Override
public void draw(Canvas canvas) {
int x = getBounds().centerX() - AndroidUtilities.dp(12);
int y = getBounds().centerY() - AndroidUtilities.dp(6);
float p = progress != 1.0f ? decelerateInterpolator.getInterpolation(progress) : 1.0f;
int endX = (int) (AndroidUtilities.dp(7.0f) - AndroidUtilities.dp(6) * p);
int endY = (int) (AndroidUtilities.dpf2(13.0f) - AndroidUtilities.dp(6) * p);
canvas.drawLine(x + AndroidUtilities.dp(7.0f), y + (int) AndroidUtilities.dpf2(13.0f), x + endX, y + endY, paint);
endX = (int) (AndroidUtilities.dpf2(7.0f) + AndroidUtilities.dp(13) * p);
endY = (int) (AndroidUtilities.dpf2(13.0f) - AndroidUtilities.dp(13) * p);
canvas.drawLine(x + (int) AndroidUtilities.dpf2(7.0f), y + (int) AndroidUtilities.dpf2(13.0f), x + endX, y + endY, paint);
}
@Override
public void setAlpha(int alpha) {
paint.setAlpha(alpha);
}
@Override
public void setColorFilter(ColorFilter cf) {
paint.setColorFilter(cf);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSPARENT;
}
@Override
public int getIntrinsicWidth() {
return AndroidUtilities.dp(48);
}
@Override
public int getIntrinsicHeight() {
return AndroidUtilities.dp(48);
}
}
public RadialProgress(View parentView) {
if (decelerateInterpolator == null) {
decelerateInterpolator = new DecelerateInterpolator();
}
progressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
progressPaint.setStyle(Paint.Style.STROKE);
progressPaint.setStrokeCap(Paint.Cap.ROUND);
progressPaint.setStrokeWidth(AndroidUtilities.dp(3));
miniProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
miniProgressPaint.setStyle(Paint.Style.STROKE);
miniProgressPaint.setStrokeCap(Paint.Cap.ROUND);
miniProgressPaint.setStrokeWidth(AndroidUtilities.dp(2));
miniProgressBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
parent = parentView;
}
public void setStrokeWidth(int width) {
progressPaint.setStrokeWidth(width);
}
public void setProgressRect(int left, int top, int right, int bottom) {
progressRect.set(left, top, right, bottom);
}
public RectF getProgressRect() {
return progressRect;
}
public void setAlphaForPrevious(boolean value) {
alphaForPrevious = value;
}
public void setAlphaForMiniPrevious(boolean value) {
alphaForMiniPrevious = value;
}
private void updateAnimation(boolean progress) {
long newTime = System.currentTimeMillis();
long dt = newTime - lastUpdateTime;
lastUpdateTime = newTime;
if (checkBackgroundDrawable != null && (currentDrawable == checkBackgroundDrawable || previousDrawable == checkBackgroundDrawable)) {
if (checkDrawable.updateAnimation(dt)) {
invalidateParent();
}
}
if (progress) {
if (animatedProgressValue != 1) {
radOffset += 360 * dt / 3000.0f;
float progressDiff = currentProgress - animationProgressStart;
if (progressDiff > 0) {
currentProgressTime += dt;
if (currentProgressTime >= 300) {
animatedProgressValue = currentProgress;
animationProgressStart = currentProgress;
currentProgressTime = 0;
} else {
animatedProgressValue = animationProgressStart + progressDiff * decelerateInterpolator.getInterpolation(currentProgressTime / 300.0f);
}
}
invalidateParent();
}
if (drawMiniProgress) {
if (animatedProgressValue >= 1 && previousMiniDrawable != null) {
animatedAlphaValue -= dt / 200.0f;
if (animatedAlphaValue <= 0) {
animatedAlphaValue = 0.0f;
previousMiniDrawable = null;
drawMiniProgress = currentMiniDrawable != null;
}
invalidateParent();
}
} else {
if (animatedProgressValue >= 1 && previousDrawable != null) {
animatedAlphaValue -= dt / 200.0f;
if (animatedAlphaValue <= 0) {
animatedAlphaValue = 0.0f;
previousDrawable = null;
}
invalidateParent();
}
}
} else {
if (drawMiniProgress) {
if (previousMiniDrawable != null) {
animatedAlphaValue -= dt / 200.0f;
if (animatedAlphaValue <= 0) {
animatedAlphaValue = 0.0f;
previousMiniDrawable = null;
drawMiniProgress = currentMiniDrawable != null;
}
invalidateParent();
}
} else {
if (previousDrawable != null) {
animatedAlphaValue -= dt / 200.0f;
if (animatedAlphaValue <= 0) {
animatedAlphaValue = 0.0f;
previousDrawable = null;
}
invalidateParent();
}
}
}
}
public void setDiff(int value) {
diff = value;
}
public void setProgressColor(int color) {
progressColor = color;
}
public void setMiniProgressBackgroundColor(int color) {
miniProgressBackgroundPaint.setColor(color);
}
public void setHideCurrentDrawable(boolean value) {
hideCurrentDrawable = value;
}
public void setProgress(float value, boolean animated) {
if (drawMiniProgress) {
if (value != 1 && animatedAlphaValue != 0 && previousMiniDrawable != null) {
animatedAlphaValue = 0.0f;
previousMiniDrawable = null;
drawMiniProgress = currentMiniDrawable != null;
}
} else {
if (value != 1 && animatedAlphaValue != 0 && previousDrawable != null) {
animatedAlphaValue = 0.0f;
previousDrawable = null;
}
}
if (!animated) {
animatedProgressValue = value;
animationProgressStart = value;
} else {
if (animatedProgressValue > value) {
animatedProgressValue = value;
}
animationProgressStart = animatedProgressValue;
}
currentProgress = value;
currentProgressTime = 0;
invalidateParent();
}
private void invalidateParent() {
int offset = AndroidUtilities.dp(2);
parent.invalidate((int) progressRect.left - offset, (int) progressRect.top - offset, (int) progressRect.right + offset * 2, (int) progressRect.bottom + offset * 2);
}
public void setCheckBackground(boolean withRound, boolean animated) {
if (checkDrawable == null) {
checkDrawable = new CheckDrawable();
checkBackgroundDrawable = Theme.createCircleDrawableWithIcon(AndroidUtilities.dp(48), checkDrawable, 0);
}
Theme.setCombinedDrawableColor(checkBackgroundDrawable, Theme.getColor(Theme.key_chat_mediaLoaderPhoto), false);
Theme.setCombinedDrawableColor(checkBackgroundDrawable, Theme.getColor(Theme.key_chat_mediaLoaderPhotoIcon), true);
if (currentDrawable != checkBackgroundDrawable) {
setBackground(checkBackgroundDrawable, withRound, animated);
checkDrawable.resetProgress(animated);
}
}
public boolean isDrawCheckDrawable() {
return currentDrawable == checkBackgroundDrawable;
}
public void setBackground(Drawable drawable, boolean withRound, boolean animated) {
lastUpdateTime = System.currentTimeMillis();
if (animated && currentDrawable != drawable) {
previousDrawable = currentDrawable;
previousWithRound = currentWithRound;
animatedAlphaValue = 1.0f;
setProgress(1, animated);
} else {
previousDrawable = null;
previousWithRound = false;
}
currentWithRound = withRound;
currentDrawable = drawable;
if (!animated) {
parent.invalidate();
} else {
invalidateParent();
}
}
public void setMiniBackground(Drawable drawable, boolean withRound, boolean animated) {
lastUpdateTime = System.currentTimeMillis();
if (animated && currentMiniDrawable != drawable) {
previousMiniDrawable = currentMiniDrawable;
previousMiniWithRound = currentMiniWithRound;
animatedAlphaValue = 1.0f;
setProgress(1, animated);
} else {
previousMiniDrawable = null;
previousMiniWithRound = false;
}
currentMiniWithRound = withRound;
currentMiniDrawable = drawable;
drawMiniProgress = previousMiniDrawable != null || currentMiniDrawable != null;
if (drawMiniProgress && miniDrawBitmap == null) {
try {
miniDrawBitmap = Bitmap.createBitmap(AndroidUtilities.dp(48), AndroidUtilities.dp(48), Bitmap.Config.ARGB_8888);
miniDrawCanvas = new Canvas(miniDrawBitmap);
} catch (Throwable ignore) {
}
}
if (!animated) {
parent.invalidate();
} else {
invalidateParent();
}
}
public boolean swapBackground(Drawable drawable) {
if (currentDrawable != drawable) {
currentDrawable = drawable;
return true;
}
return false;
}
public boolean swapMiniBackground(Drawable drawable) {
if (currentMiniDrawable != drawable) {
currentMiniDrawable = drawable;
drawMiniProgress = previousMiniDrawable != null || currentMiniDrawable != null;
return true;
}
return false;
}
public float getAlpha() {
return previousDrawable != null || currentDrawable != null ? animatedAlphaValue : 0.0f;
}
public void setOverrideAlpha(float alpha) {
overrideAlpha = alpha;
}
public void draw(Canvas canvas) {
if (drawMiniProgress && currentDrawable != null) {
if (miniDrawCanvas != null) {
miniDrawBitmap.eraseColor(0);
}
currentDrawable.setAlpha((int) (255 * overrideAlpha));
if (miniDrawCanvas != null) {
currentDrawable.setBounds(0, 0, (int) progressRect.width(), (int) progressRect.height());
currentDrawable.draw(miniDrawCanvas);
} else {
currentDrawable.setBounds((int) progressRect.left, (int) progressRect.top, (int) progressRect.right, (int) progressRect.bottom);
currentDrawable.draw(canvas);
}
int offset;
int size;
float cx;
float cy;
if (Math.abs(progressRect.width() - AndroidUtilities.dp(44)) < AndroidUtilities.density) {
offset = 0;
size = 20;
cx = progressRect.centerX() + AndroidUtilities.dp(16 + offset);
cy = progressRect.centerY() + AndroidUtilities.dp(16 + offset);
} else {
offset = 2;
size = 22;
cx = progressRect.centerX() + AndroidUtilities.dp(18);
cy = progressRect.centerY() + AndroidUtilities.dp(18);
}
int halfSize = size / 2;
float alpha = 1.0f;
if (previousMiniDrawable != null && alphaForMiniPrevious) {
alpha = animatedAlphaValue * overrideAlpha;
}
if (miniDrawCanvas != null) {
miniDrawCanvas.drawCircle(AndroidUtilities.dp(18 + size + offset), AndroidUtilities.dp(18 + size + offset), AndroidUtilities.dp(halfSize + 1) * alpha, Theme.checkboxSquare_eraserPaint);
} else {
miniProgressBackgroundPaint.setColor(progressColor);
if (previousMiniDrawable != null && currentMiniDrawable == null) {
miniProgressBackgroundPaint.setAlpha((int) (255 * animatedAlphaValue * overrideAlpha));
} else {
miniProgressBackgroundPaint.setAlpha(255);
}
canvas.drawCircle(cx, cy, AndroidUtilities.dp(12), miniProgressBackgroundPaint);
}
if (miniDrawCanvas != null) {
canvas.drawBitmap(miniDrawBitmap, (int) progressRect.left, (int) progressRect.top, null);
}
if (previousMiniDrawable != null) {
if (alphaForMiniPrevious) {
previousMiniDrawable.setAlpha((int) (255 * animatedAlphaValue * overrideAlpha));
} else {
previousMiniDrawable.setAlpha((int) (255 * overrideAlpha));
}
previousMiniDrawable.setBounds((int) (cx - AndroidUtilities.dp(halfSize) * alpha), (int) (cy - AndroidUtilities.dp(halfSize) * alpha), (int) (cx + AndroidUtilities.dp(halfSize) * alpha), (int) (cy + AndroidUtilities.dp(halfSize) * alpha));
previousMiniDrawable.draw(canvas);
}
if (!hideCurrentDrawable && currentMiniDrawable != null) {
if (previousMiniDrawable != null) {
currentMiniDrawable.setAlpha((int) (255 * (1.0f - animatedAlphaValue) * overrideAlpha));
} else {
currentMiniDrawable.setAlpha((int) (255 * overrideAlpha));
}
currentMiniDrawable.setBounds((int) (cx - AndroidUtilities.dp(halfSize)), (int) (cy - AndroidUtilities.dp(halfSize)), (int) (cx + AndroidUtilities.dp(halfSize)), (int) (cy + AndroidUtilities.dp(halfSize)));
currentMiniDrawable.draw(canvas);
}
if (currentMiniWithRound || previousMiniWithRound) {
miniProgressPaint.setColor(progressColor);
if (previousMiniWithRound) {
miniProgressPaint.setAlpha((int) (255 * animatedAlphaValue * overrideAlpha));
} else {
miniProgressPaint.setAlpha((int) (255 * overrideAlpha));
}
cicleRect.set(cx - AndroidUtilities.dp(halfSize - 2) * alpha, cy - AndroidUtilities.dp(halfSize - 2) * alpha, cx + AndroidUtilities.dp(halfSize - 2) * alpha, cy + AndroidUtilities.dp(halfSize - 2) * alpha);
canvas.drawArc(cicleRect, -90 + radOffset, Math.max(4, 360 * animatedProgressValue), false, miniProgressPaint);
updateAnimation(true);
} else {
updateAnimation(false);
}
} else {
if (previousDrawable != null) {
if (alphaForPrevious) {
previousDrawable.setAlpha((int) (255 * animatedAlphaValue * overrideAlpha));
} else {
previousDrawable.setAlpha((int) (255 * overrideAlpha));
}
previousDrawable.setBounds((int) progressRect.left, (int) progressRect.top, (int) progressRect.right, (int) progressRect.bottom);
previousDrawable.draw(canvas);
}
if (!hideCurrentDrawable && currentDrawable != null) {
if (previousDrawable != null) {
currentDrawable.setAlpha((int) (255 * (1.0f - animatedAlphaValue) * overrideAlpha));
} else {
currentDrawable.setAlpha((int) (255 * overrideAlpha));
}
currentDrawable.setBounds((int) progressRect.left, (int) progressRect.top, (int) progressRect.right, (int) progressRect.bottom);
currentDrawable.draw(canvas);
}
if (currentWithRound || previousWithRound) {
progressPaint.setColor(progressColor);
if (previousWithRound) {
progressPaint.setAlpha((int) (255 * animatedAlphaValue * overrideAlpha));
} else {
progressPaint.setAlpha((int) (255 * overrideAlpha));
}
cicleRect.set(progressRect.left + diff, progressRect.top + diff, progressRect.right - diff, progressRect.bottom - diff);
canvas.drawArc(cicleRect, -90 + radOffset, Math.max(4, 360 * animatedProgressValue), false, progressPaint);
updateAnimation(true);
} else {
updateAnimation(false);
}
}
}
}