mirror of https://github.com/NekoX-Dev/NekoX.git
313 lines
13 KiB
Java
313 lines
13 KiB
Java
package org.telegram.ui.Components;
|
|
|
|
import android.animation.Animator;
|
|
import android.animation.AnimatorListenerAdapter;
|
|
import android.animation.ValueAnimator;
|
|
import android.content.Context;
|
|
import android.graphics.Canvas;
|
|
import android.graphics.Paint;
|
|
import android.graphics.RectF;
|
|
import android.text.Layout;
|
|
import android.text.SpannableString;
|
|
import android.text.SpannableStringBuilder;
|
|
import android.text.StaticLayout;
|
|
import android.text.TextPaint;
|
|
import android.text.TextUtils;
|
|
import android.view.Gravity;
|
|
import android.view.View;
|
|
|
|
import org.telegram.messenger.AndroidUtilities;
|
|
import org.telegram.messenger.LocaleController;
|
|
import org.telegram.ui.ActionBar.Theme;
|
|
|
|
public class SearchCounterView extends View {
|
|
|
|
private final static int ANIMATION_TYPE_REPLACE = 2;
|
|
|
|
int animationType = -1;
|
|
|
|
TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
|
|
RectF rectF = new RectF();
|
|
|
|
int currentCount;
|
|
private boolean countAnimationIncrement;
|
|
private ValueAnimator countAnimator;
|
|
private float countChangeProgress = 1f;
|
|
private StaticLayout countLayout;
|
|
private StaticLayout countOldLayout;
|
|
private StaticLayout countAnimationStableLayout;
|
|
private StaticLayout countAnimationStableLayout2;
|
|
private StaticLayout countAnimationInLayout;
|
|
|
|
private int countWidthOld;
|
|
private int countWidth;
|
|
|
|
private int textColor;
|
|
private String textColorKey = Theme.key_chat_searchPanelText;
|
|
|
|
int lastH;
|
|
int gravity = Gravity.CENTER;
|
|
float countLeft;
|
|
float x;
|
|
|
|
public float horizontalPadding;
|
|
|
|
String currentString;
|
|
|
|
|
|
public SearchCounterView(Context context) {
|
|
super(context);
|
|
textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
|
|
textPaint.setTextSize(AndroidUtilities.dp(15));
|
|
}
|
|
|
|
@Override
|
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
|
if (getMeasuredHeight() != lastH) {
|
|
int count = currentCount;
|
|
String str = currentString;
|
|
currentString = null;
|
|
setCount(str, count, false);
|
|
lastH = getMeasuredHeight();
|
|
}
|
|
}
|
|
|
|
float dx = 0;
|
|
|
|
public void setCount(String newStr, int count, boolean animated) {
|
|
if (currentString != null && currentString.equals(newStr)) {
|
|
return;
|
|
}
|
|
if (countAnimator != null) {
|
|
countAnimator.cancel();
|
|
}
|
|
if (currentCount == 0 || count <= 0 || newStr == null || LocaleController.isRTL || TextUtils.isEmpty(newStr)) {
|
|
animated = false;
|
|
}
|
|
|
|
if (animated && newStr != null && !newStr.contains("**")) {
|
|
animated = false;
|
|
}
|
|
|
|
if (!animated) {
|
|
if (newStr != null) {
|
|
newStr = newStr.replaceAll("\\*\\*", "");
|
|
}
|
|
currentCount = count;
|
|
if (newStr == null) {
|
|
countWidth = 0;
|
|
countLayout = null;
|
|
} else {
|
|
countWidth = Math.max(AndroidUtilities.dp(12), (int) Math.ceil(textPaint.measureText(newStr)));
|
|
countLayout = new StaticLayout(newStr, textPaint, countWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
|
|
}
|
|
invalidate();
|
|
}
|
|
|
|
dx = 0;
|
|
if (animated) {
|
|
if (countAnimator != null) {
|
|
countAnimator.cancel();
|
|
}
|
|
countChangeProgress = 0f;
|
|
countAnimator = ValueAnimator.ofFloat(0, 1f);
|
|
countAnimator.addUpdateListener(valueAnimator -> {
|
|
countChangeProgress = (float) valueAnimator.getAnimatedValue();
|
|
invalidate();
|
|
});
|
|
countAnimator.addListener(new AnimatorListenerAdapter() {
|
|
@Override
|
|
public void onAnimationEnd(Animator animation) {
|
|
animationType = -1;
|
|
countChangeProgress = 1f;
|
|
countOldLayout = null;
|
|
countAnimationStableLayout = null;
|
|
countAnimationInLayout = null;
|
|
invalidate();
|
|
}
|
|
});
|
|
|
|
animationType = ANIMATION_TYPE_REPLACE;
|
|
countAnimator.setDuration(200);
|
|
countAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT);
|
|
|
|
if (countLayout != null) {
|
|
String oldStr = currentString;
|
|
|
|
int countStartIndex = newStr.indexOf("**");
|
|
if (countStartIndex >= 0) {
|
|
newStr = newStr.replaceAll("\\*\\*", "");
|
|
} else {
|
|
countStartIndex = 0;
|
|
}
|
|
|
|
SpannableStringBuilder oldSpannableStr = new SpannableStringBuilder(oldStr);
|
|
SpannableStringBuilder newSpannableStr = new SpannableStringBuilder(newStr);
|
|
SpannableStringBuilder stableStr = new SpannableStringBuilder(newStr);
|
|
|
|
boolean replaceAllDigits = Integer.toString(currentCount).length() != Integer.toString(count).length();
|
|
boolean newEndReached = false;
|
|
boolean oldEndReached = false;
|
|
int n = Math.min(oldStr.length(), newStr.length());
|
|
int cutIndexNew = 0;
|
|
int cutIndexOld = 0;
|
|
if (countStartIndex > 0) {
|
|
oldSpannableStr.setSpan(new EmptyStubSpan(), 0, countStartIndex, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
newSpannableStr.setSpan(new EmptyStubSpan(), 0, countStartIndex, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
stableStr.setSpan(new EmptyStubSpan(), 0, countStartIndex, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
}
|
|
for (int i = countStartIndex; i < n; i++) {
|
|
if (!newEndReached && !oldEndReached) {
|
|
if (replaceAllDigits) {
|
|
stableStr.setSpan(new EmptyStubSpan(), i, i + 1, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
} else if (oldStr.charAt(i) == newStr.charAt(i)) {
|
|
oldSpannableStr.setSpan(new EmptyStubSpan(), i, i + 1, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
newSpannableStr.setSpan(new EmptyStubSpan(), i, i + 1, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
} else {
|
|
stableStr.setSpan(new EmptyStubSpan(), i, i + 1, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
}
|
|
}
|
|
if (!Character.isDigit(newStr.charAt(i))) {
|
|
newSpannableStr.setSpan(new EmptyStubSpan(), i, newStr.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
newEndReached = true;
|
|
cutIndexNew = i;
|
|
}
|
|
|
|
if (!Character.isDigit(oldStr.charAt(i))) {
|
|
oldSpannableStr.setSpan(new EmptyStubSpan(), i, oldStr.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
oldEndReached = true;
|
|
cutIndexOld = i;
|
|
}
|
|
}
|
|
|
|
int countOldWidth = Math.max(AndroidUtilities.dp(12), (int) Math.ceil(textPaint.measureText(oldStr)));
|
|
int countNewWidth = Math.max(AndroidUtilities.dp(12), (int) Math.ceil(textPaint.measureText(newStr)));
|
|
countOldLayout = new StaticLayout(oldSpannableStr, textPaint, countOldWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
|
|
countAnimationStableLayout = new StaticLayout(stableStr, textPaint, countNewWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
|
|
countAnimationInLayout = new StaticLayout(newSpannableStr, textPaint, countNewWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
|
|
|
|
if (countStartIndex > 0) {
|
|
SpannableStringBuilder stableString2 = new SpannableStringBuilder(newStr);
|
|
stableString2.setSpan(new EmptyStubSpan(), countStartIndex, newStr.length(), 0);
|
|
countAnimationStableLayout2 = new StaticLayout(stableString2, textPaint, countNewWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
|
|
} else {
|
|
countAnimationStableLayout2 = null;
|
|
}
|
|
|
|
dx = countOldLayout.getPrimaryHorizontal(cutIndexOld) - countAnimationStableLayout.getPrimaryHorizontal(cutIndexNew);
|
|
}
|
|
countWidthOld = countWidth;
|
|
countAnimationIncrement = count < currentCount;
|
|
countAnimator.start();
|
|
}
|
|
if (count > 0) {
|
|
countWidth = Math.max(AndroidUtilities.dp(12), (int) Math.ceil(textPaint.measureText(newStr)));
|
|
countLayout = new StaticLayout(newStr, textPaint, countWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
|
|
}
|
|
|
|
currentCount = count;
|
|
invalidate();
|
|
currentString = newStr;
|
|
}
|
|
|
|
@Override
|
|
protected void onDraw(Canvas canvas) {
|
|
super.onDraw(canvas);
|
|
int textColor = Theme.getColor(textColorKey);
|
|
|
|
if (this.textColor != textColor) {
|
|
this.textColor = textColor;
|
|
textPaint.setColor(textColor);
|
|
}
|
|
|
|
if (countChangeProgress != 1f) {
|
|
|
|
float countTop = (getMeasuredHeight() - AndroidUtilities.dp(23)) / 2f;
|
|
float countWidth;
|
|
if (this.countWidth == this.countWidthOld) {
|
|
countWidth = this.countWidth;
|
|
} else {
|
|
countWidth = this.countWidth * countChangeProgress + this.countWidthOld * (1f - countChangeProgress);
|
|
}
|
|
updateX(countWidth);
|
|
|
|
rectF.set(x, countTop, x + countWidth + AndroidUtilities.dp(11), countTop + AndroidUtilities.dp(23));
|
|
|
|
boolean increment = countAnimationIncrement;
|
|
if (countAnimationInLayout != null) {
|
|
canvas.save();
|
|
canvas.translate(countLeft, countTop + AndroidUtilities.dp(4) + (increment ? AndroidUtilities.dp(13) : -AndroidUtilities.dp(13)) * (1f - countChangeProgress));
|
|
textPaint.setAlpha((int) (255 * countChangeProgress));
|
|
countAnimationInLayout.draw(canvas);
|
|
canvas.restore();
|
|
} else if (countLayout != null) {
|
|
canvas.save();
|
|
canvas.translate(countLeft, countTop + AndroidUtilities.dp(4) + (increment ? AndroidUtilities.dp(13) : -AndroidUtilities.dp(13)) * (1f - countChangeProgress));
|
|
textPaint.setAlpha((int) (255 * countChangeProgress));
|
|
countLayout.draw(canvas);
|
|
canvas.restore();
|
|
}
|
|
|
|
if (countOldLayout != null) {
|
|
canvas.save();
|
|
canvas.translate(countLeft, countTop + AndroidUtilities.dp(4) + (increment ? -AndroidUtilities.dp(13) : AndroidUtilities.dp(13)) * (countChangeProgress));
|
|
textPaint.setAlpha((int) (255 * (1f - countChangeProgress)));
|
|
countOldLayout.draw(canvas);
|
|
canvas.restore();
|
|
}
|
|
|
|
if (countAnimationStableLayout != null) {
|
|
canvas.save();
|
|
canvas.translate(countLeft + dx * (1f - countChangeProgress), countTop + AndroidUtilities.dp(4));
|
|
textPaint.setAlpha(255);
|
|
countAnimationStableLayout.draw(canvas);
|
|
canvas.restore();
|
|
}
|
|
|
|
if (countAnimationStableLayout2 != null) {
|
|
canvas.save();
|
|
canvas.translate(countLeft, countTop + AndroidUtilities.dp(4));
|
|
textPaint.setAlpha(255);
|
|
countAnimationStableLayout2.draw(canvas);
|
|
canvas.restore();
|
|
}
|
|
textPaint.setAlpha(255);
|
|
} else {
|
|
drawInternal(canvas);
|
|
}
|
|
}
|
|
|
|
private void updateX(float countWidth) {
|
|
if (gravity == Gravity.RIGHT) {
|
|
countLeft = getMeasuredWidth() - AndroidUtilities.dp(5.5f);
|
|
if (horizontalPadding != 0) {
|
|
countLeft -= Math.max(horizontalPadding + countWidth / 2f, countWidth);
|
|
} else {
|
|
countLeft -= countWidth;
|
|
}
|
|
} else if (gravity == Gravity.LEFT) {
|
|
countLeft = AndroidUtilities.dp(5.5f);
|
|
} else {
|
|
countLeft = (int) ((getMeasuredWidth() - countWidth) / 2f);
|
|
}
|
|
x = countLeft - AndroidUtilities.dp(5.5f);
|
|
}
|
|
|
|
private void drawInternal(Canvas canvas) {
|
|
float countTop = (getMeasuredHeight() - AndroidUtilities.dp(23)) / 2f;
|
|
updateX(countWidth);
|
|
if (countLayout != null) {
|
|
canvas.save();
|
|
canvas.translate(countLeft, countTop + AndroidUtilities.dp(4));
|
|
countLayout.draw(canvas);
|
|
canvas.restore();
|
|
}
|
|
}
|
|
|
|
public void setGravity(int gravity) {
|
|
this.gravity = gravity;
|
|
}
|
|
|
|
}
|