2014-11-11 23:16:17 +01:00
|
|
|
/*
|
2019-01-23 18:03:33 +01:00
|
|
|
* This is the source code of Telegram for Android v. 5.x.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).
|
2014-11-11 23:16:17 +01:00
|
|
|
*
|
2019-01-23 18:03:33 +01:00
|
|
|
* Copyright Nikolai Kudashov, 2013-2018.
|
2014-11-11 23:16:17 +01:00
|
|
|
*/
|
|
|
|
|
2014-12-01 18:56:31 +01:00
|
|
|
package org.telegram.ui.Components;
|
2014-11-11 23:16:17 +01:00
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
import android.animation.Animator;
|
|
|
|
import android.animation.AnimatorListenerAdapter;
|
2016-06-24 12:27:15 +02:00
|
|
|
import android.animation.ObjectAnimator;
|
2014-11-11 23:16:17 +01:00
|
|
|
import android.content.Context;
|
|
|
|
import android.graphics.Canvas;
|
2019-01-23 18:03:33 +01:00
|
|
|
import android.graphics.Color;
|
|
|
|
import android.graphics.Paint;
|
2014-11-11 23:16:17 +01:00
|
|
|
import android.graphics.PorterDuff;
|
|
|
|
import android.graphics.PorterDuffColorFilter;
|
2019-01-23 18:03:33 +01:00
|
|
|
import android.graphics.RectF;
|
2014-11-11 23:16:17 +01:00
|
|
|
import android.graphics.drawable.Drawable;
|
2018-07-30 04:07:02 +02:00
|
|
|
import android.support.annotation.Keep;
|
2019-01-23 18:03:33 +01:00
|
|
|
import android.view.View;
|
2014-11-11 23:16:17 +01:00
|
|
|
|
2015-09-24 22:52:02 +02:00
|
|
|
import org.telegram.messenger.AndroidUtilities;
|
2017-03-31 01:58:05 +02:00
|
|
|
import org.telegram.ui.ActionBar.Theme;
|
2014-11-11 23:16:17 +01:00
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
public class Switch extends View {
|
2014-11-11 23:16:17 +01:00
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
private RectF rectF;
|
2014-11-11 23:16:17 +01:00
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
private float progress;
|
|
|
|
private ObjectAnimator checkAnimator;
|
|
|
|
private ObjectAnimator iconAnimator;
|
2014-11-11 23:16:17 +01:00
|
|
|
|
|
|
|
private boolean attachedToWindow;
|
2019-01-23 18:03:33 +01:00
|
|
|
private boolean isChecked;
|
|
|
|
private Paint paint;
|
|
|
|
private Paint paint2;
|
2014-11-11 23:16:17 +01:00
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
private int drawIconType;
|
|
|
|
private float iconProgress = 1.0f;
|
2014-11-11 23:16:17 +01:00
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
private OnCheckedChangeListener onCheckedChangeListener;
|
2014-11-11 23:16:17 +01:00
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
private String trackColorKey = Theme.key_switch2Track;
|
|
|
|
private String trackCheckedColorKey = Theme.key_switch2TrackChecked;
|
|
|
|
private String thumbColorKey = Theme.key_windowBackgroundWhite;
|
|
|
|
private String thumbCheckedColorKey = Theme.key_windowBackgroundWhite;
|
2014-11-11 23:16:17 +01:00
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
private Drawable iconDrawable;
|
|
|
|
private int lastIconColor;
|
2014-11-11 23:16:17 +01:00
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
public interface OnCheckedChangeListener {
|
|
|
|
void onCheckedChanged(Switch view, boolean isChecked);
|
2014-11-11 23:16:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
public Switch(Context context) {
|
|
|
|
super(context);
|
|
|
|
rectF = new RectF();
|
2014-11-11 23:16:17 +01:00
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
|
|
|
paint2 = new Paint(Paint.ANTI_ALIAS_FLAG);
|
|
|
|
paint2.setStyle(Paint.Style.STROKE);
|
|
|
|
paint2.setStrokeCap(Paint.Cap.ROUND);
|
|
|
|
paint2.setStrokeWidth(AndroidUtilities.dp(2));
|
2014-11-11 23:16:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
@Keep
|
|
|
|
public void setProgress(float value) {
|
|
|
|
if (progress == value) {
|
|
|
|
return;
|
2014-11-11 23:16:17 +01:00
|
|
|
}
|
2019-01-23 18:03:33 +01:00
|
|
|
progress = value;
|
2014-11-11 23:16:17 +01:00
|
|
|
invalidate();
|
|
|
|
}
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
@Keep
|
|
|
|
public float getProgress() {
|
|
|
|
return progress;
|
2014-11-11 23:16:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
@Keep
|
|
|
|
public void setIconProgress(float value) {
|
|
|
|
if (iconProgress == value) {
|
|
|
|
return;
|
2014-11-11 23:16:17 +01:00
|
|
|
}
|
2019-01-23 18:03:33 +01:00
|
|
|
iconProgress = value;
|
|
|
|
invalidate();
|
2014-11-11 23:16:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
@Keep
|
|
|
|
public float getIconProgress() {
|
|
|
|
return iconProgress;
|
2014-11-11 23:16:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
private void cancelCheckAnimator() {
|
|
|
|
if (checkAnimator != null) {
|
|
|
|
checkAnimator.cancel();
|
|
|
|
checkAnimator = null;
|
2014-11-11 23:16:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
private void cancelIconAnimator() {
|
|
|
|
if (iconAnimator != null) {
|
|
|
|
iconAnimator.cancel();
|
|
|
|
iconAnimator = null;
|
2014-11-11 23:16:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
public void setDrawIconType(int type) {
|
|
|
|
drawIconType = type;
|
2014-11-11 23:16:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
public void setColors(String track, String trackChecked, String thumb, String thumbChecked) {
|
|
|
|
trackColorKey = track;
|
|
|
|
trackCheckedColorKey = trackChecked;
|
|
|
|
thumbColorKey = thumb;
|
|
|
|
thumbCheckedColorKey = thumbChecked;
|
2014-11-11 23:16:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
private void animateToCheckedState(boolean newCheckedState) {
|
|
|
|
checkAnimator = ObjectAnimator.ofFloat(this, "progress", newCheckedState ? 1 : 0);
|
|
|
|
checkAnimator.setDuration(250);
|
|
|
|
checkAnimator.addListener(new AnimatorListenerAdapter() {
|
|
|
|
@Override
|
|
|
|
public void onAnimationEnd(Animator animation) {
|
|
|
|
checkAnimator = null;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
checkAnimator.start();
|
2014-11-11 23:16:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
private void animateIcon(boolean newCheckedState) {
|
|
|
|
iconAnimator = ObjectAnimator.ofFloat(this, "iconProgress", newCheckedState ? 1 : 0);
|
|
|
|
iconAnimator.setDuration(250);
|
|
|
|
iconAnimator.addListener(new AnimatorListenerAdapter() {
|
|
|
|
@Override
|
|
|
|
public void onAnimationEnd(Animator animation) {
|
|
|
|
iconAnimator = null;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
iconAnimator.start();
|
2014-11-11 23:16:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onAttachedToWindow() {
|
|
|
|
super.onAttachedToWindow();
|
|
|
|
attachedToWindow = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onDetachedFromWindow() {
|
|
|
|
super.onDetachedFromWindow();
|
|
|
|
attachedToWindow = false;
|
|
|
|
}
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
|
|
|
|
onCheckedChangeListener = listener;
|
2014-11-19 16:17:24 +01:00
|
|
|
}
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
public void setChecked(boolean checked, boolean animated) {
|
|
|
|
setChecked(checked, drawIconType, animated);
|
2017-03-31 01:58:05 +02:00
|
|
|
}
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
public void setChecked(boolean checked, int iconType, boolean animated) {
|
|
|
|
if (checked != isChecked) {
|
|
|
|
isChecked = checked;
|
|
|
|
if (attachedToWindow && animated) {
|
|
|
|
animateToCheckedState(checked);
|
2014-11-11 23:16:17 +01:00
|
|
|
} else {
|
2019-01-23 18:03:33 +01:00
|
|
|
cancelCheckAnimator();
|
|
|
|
setProgress(checked ? 1.0f : 0.0f);
|
2014-11-11 23:16:17 +01:00
|
|
|
}
|
2019-01-23 18:03:33 +01:00
|
|
|
if (onCheckedChangeListener != null) {
|
|
|
|
onCheckedChangeListener.onCheckedChanged(this, checked);
|
2014-11-11 23:16:17 +01:00
|
|
|
}
|
|
|
|
}
|
2019-01-23 18:03:33 +01:00
|
|
|
if (drawIconType != iconType) {
|
|
|
|
drawIconType = iconType;
|
|
|
|
if (attachedToWindow && animated) {
|
|
|
|
animateIcon(iconType == 0);
|
2014-11-11 23:16:17 +01:00
|
|
|
} else {
|
2019-01-23 18:03:33 +01:00
|
|
|
cancelIconAnimator();
|
|
|
|
setIconProgress(iconType == 0 ? 1.0f : 0.0f);
|
2014-11-11 23:16:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
public void setIcon(int icon) {
|
|
|
|
if (icon != 0) {
|
|
|
|
iconDrawable = getResources().getDrawable(icon).mutate();
|
|
|
|
if (iconDrawable != null) {
|
|
|
|
iconDrawable.setColorFilter(new PorterDuffColorFilter(lastIconColor = Theme.getColor(isChecked ? trackCheckedColorKey : trackColorKey), PorterDuff.Mode.MULTIPLY));
|
2014-11-11 23:16:17 +01:00
|
|
|
}
|
|
|
|
} else {
|
2019-01-23 18:03:33 +01:00
|
|
|
iconDrawable = null;
|
2014-11-11 23:16:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
public boolean hasIcon() {
|
|
|
|
return iconDrawable != null;
|
2014-11-11 23:16:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
public boolean isChecked() {
|
|
|
|
return isChecked;
|
2014-11-11 23:16:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2019-01-23 18:03:33 +01:00
|
|
|
protected void onDraw(Canvas canvas) {
|
|
|
|
if (getVisibility() != VISIBLE) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int width = AndroidUtilities.dp(31);
|
|
|
|
int thumb = AndroidUtilities.dp(20);
|
|
|
|
int x = (getMeasuredWidth() - width) / 2;
|
|
|
|
int y = (getMeasuredHeight() - AndroidUtilities.dp(14)) / 2;
|
|
|
|
int tx = x + AndroidUtilities.dp(7) + (int) (AndroidUtilities.dp(17) * progress);
|
|
|
|
int ty = getMeasuredHeight() / 2;
|
|
|
|
|
|
|
|
int color1 = Theme.getColor(trackColorKey);
|
|
|
|
int color2 = Theme.getColor(trackCheckedColorKey);
|
|
|
|
if (iconDrawable != null && lastIconColor != (isChecked ? color2 : color1)) {
|
|
|
|
iconDrawable.setColorFilter(new PorterDuffColorFilter(lastIconColor = (isChecked ? color2 : color1), PorterDuff.Mode.MULTIPLY));
|
|
|
|
}
|
|
|
|
|
|
|
|
int r1 = Color.red(color1);
|
|
|
|
int r2 = Color.red(color2);
|
|
|
|
int g1 = Color.green(color1);
|
|
|
|
int g2 = Color.green(color2);
|
|
|
|
int b1 = Color.blue(color1);
|
|
|
|
int b2 = Color.blue(color2);
|
|
|
|
int a1 = Color.alpha(color1);
|
|
|
|
int a2 = Color.alpha(color2);
|
|
|
|
|
|
|
|
int red = (int) (r1 + (r2 - r1) * progress);
|
|
|
|
int green = (int) (g1 + (g2 - g1) * progress);
|
|
|
|
int blue = (int) (b1 + (b2 - b1) * progress);
|
|
|
|
int alpha = (int) (a1 + (a2 - a1) * progress);
|
|
|
|
int color = ((alpha & 0xff) << 24) | ((red & 0xff) << 16) | ((green & 0xff) << 8) | (blue & 0xff);
|
|
|
|
paint.setColor(color);
|
|
|
|
paint2.setColor(color);
|
|
|
|
|
|
|
|
rectF.set(x, y, x + width, y + AndroidUtilities.dp(14));
|
|
|
|
canvas.drawRoundRect(rectF, AndroidUtilities.dp(7), AndroidUtilities.dp(7), paint);
|
|
|
|
canvas.drawCircle(tx, ty, AndroidUtilities.dp(10), paint);
|
|
|
|
|
|
|
|
color1 = Theme.getColor(thumbColorKey);
|
|
|
|
color2 = Theme.getColor(thumbCheckedColorKey);
|
|
|
|
r1 = Color.red(color1);
|
|
|
|
r2 = Color.red(color2);
|
|
|
|
g1 = Color.green(color1);
|
|
|
|
g2 = Color.green(color2);
|
|
|
|
b1 = Color.blue(color1);
|
|
|
|
b2 = Color.blue(color2);
|
|
|
|
a1 = Color.alpha(color1);
|
|
|
|
a2 = Color.alpha(color2);
|
|
|
|
|
|
|
|
red = (int) (r1 + (r2 - r1) * progress);
|
|
|
|
green = (int) (g1 + (g2 - g1) * progress);
|
|
|
|
blue = (int) (b1 + (b2 - b1) * progress);
|
|
|
|
alpha = (int) (a1 + (a2 - a1) * progress);
|
|
|
|
paint.setColor(((alpha & 0xff) << 24) | ((red & 0xff) << 16) | ((green & 0xff) << 8) | (blue & 0xff));
|
|
|
|
|
|
|
|
canvas.drawCircle(tx, ty, AndroidUtilities.dp(8), paint);
|
|
|
|
|
|
|
|
if (iconDrawable != null) {
|
|
|
|
iconDrawable.setBounds(tx - iconDrawable.getIntrinsicWidth() / 2, ty - iconDrawable.getIntrinsicHeight() / 2, tx + iconDrawable.getIntrinsicWidth() / 2, ty + iconDrawable.getIntrinsicHeight() / 2);
|
|
|
|
iconDrawable.draw(canvas);
|
|
|
|
} else if (drawIconType == 1) {
|
|
|
|
tx -= AndroidUtilities.dp(10.8f) - AndroidUtilities.dp(1.3f) * progress;
|
|
|
|
ty -= AndroidUtilities.dp(8.5f) - AndroidUtilities.dp(0.5f) * progress;
|
|
|
|
int startX2 = (int) AndroidUtilities.dpf2(4.6f) + tx;
|
|
|
|
int startY2 = (int) (AndroidUtilities.dpf2(9.5f) + ty);
|
|
|
|
int endX2 = startX2 + AndroidUtilities.dp(2);
|
|
|
|
int endY2 = startY2 + AndroidUtilities.dp(2);
|
|
|
|
|
|
|
|
int startX = (int) AndroidUtilities.dpf2(7.5f) + tx;
|
|
|
|
int startY = (int) AndroidUtilities.dpf2(5.4f) + ty;
|
|
|
|
int endX = startX + AndroidUtilities.dp(7);
|
|
|
|
int endY = startY + AndroidUtilities.dp(7);
|
|
|
|
|
|
|
|
startX = (int) (startX + (startX2 - startX) * progress);
|
|
|
|
startY = (int) (startY + (startY2 - startY) * progress);
|
|
|
|
endX = (int) (endX + (endX2 - endX) * progress);
|
|
|
|
endY = (int) (endY + (endY2 - endY) * progress);
|
|
|
|
canvas.drawLine(startX, startY, endX, endY, paint2);
|
|
|
|
|
|
|
|
startX = (int) AndroidUtilities.dpf2(7.5f) + tx;
|
|
|
|
startY = (int) AndroidUtilities.dpf2(12.5f) + ty;
|
|
|
|
endX = startX + AndroidUtilities.dp(7);
|
|
|
|
endY = startY - AndroidUtilities.dp(7);
|
|
|
|
canvas.drawLine(startX, startY, endX, endY, paint2);
|
|
|
|
} else if (drawIconType == 2 || iconAnimator != null) {
|
|
|
|
paint2.setAlpha((int) (255 * (1.0f - iconProgress)));
|
|
|
|
canvas.drawLine(tx, ty, tx, ty - AndroidUtilities.dp(5), paint2);
|
|
|
|
canvas.save();
|
|
|
|
canvas.rotate(-90 * iconProgress, tx, ty);
|
|
|
|
canvas.drawLine(tx, ty, tx + AndroidUtilities.dp(4), ty, paint2);
|
|
|
|
canvas.restore();
|
2014-11-11 23:16:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|