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

278 lines
11 KiB
Java

package org.telegram.ui.Components;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.Editable;
import android.text.TextPaint;
import android.view.GestureDetector;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SoundEffectConstants;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageView;
import androidx.core.graphics.ColorUtils;
import androidx.core.view.GestureDetectorCompat;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.R;
import org.telegram.ui.ActionBar.Theme;
public class CustomPhoneKeyboardView extends ViewGroup {
public final static int KEYBOARD_HEIGHT_DP = 230;
private final static int SIDE_PADDING = 10, BUTTON_PADDING = 6;
private ImageView backButton;
private EditText editText;
private View[] views = new View[12];
private boolean dispatchBackWhenEmpty;
private boolean runningLongClick;
private Runnable onBackButton = () -> {
if (editText == null || editText.length() == 0 && !dispatchBackWhenEmpty) return;
performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
playSoundEffect(SoundEffectConstants.CLICK);
editText.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL));
editText.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL));
if (runningLongClick) {
postDelayed(this.onBackButton, 50);
}
};
private boolean postedLongClick;
private Runnable detectLongClick = () -> {
postedLongClick = false;
runningLongClick = true;
onBackButton.run();
};
public CustomPhoneKeyboardView(Context context) {
super(context);
for (int i = 0; i < 11; i++) {
if (i == 9) continue;
String symbols;
switch (i) {
default:
case 0:
symbols = "";
break;
case 1:
symbols = "ABC";
break;
case 2:
symbols = "DEF";
break;
case 3:
symbols = "GHI";
break;
case 4:
symbols = "JKL";
break;
case 5:
symbols = "MNO";
break;
case 6:
symbols = "PQRS";
break;
case 7:
symbols = "TUV";
break;
case 8:
symbols = "WXYZ";
break;
case 10:
symbols = "+";
break;
}
String num = String.valueOf(i != 10 ? i + 1 : 0);
views[i] = new NumberButtonView(context, num, symbols);
views[i].setOnClickListener(v -> {
if (editText == null) return;
performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
if (editText instanceof EditTextBoldCursor) {
((EditTextBoldCursor) editText).setTextWatchersSuppressed(true, false);
}
Editable text = editText.getText();
int newSelection = editText.getSelectionEnd() == editText.length() ? -1 : editText.getSelectionStart() + num.length();
if (editText.getSelectionStart() != -1 && editText.getSelectionEnd() != -1) {
editText.setText(text.replace(editText.getSelectionStart(), editText.getSelectionEnd(), num));
editText.setSelection(newSelection == -1 ? editText.length() : newSelection);
} else {
editText.setText(num);
editText.setSelection(editText.length());
}
if (editText instanceof EditTextBoldCursor) {
((EditTextBoldCursor) editText).setTextWatchersSuppressed(false, true);
}
});
addView(views[i]);
}
GestureDetectorCompat backDetector = setupBackButtonDetector(context);
backButton = new ImageView(context) {
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
if (postedLongClick || runningLongClick) {
postedLongClick = false;
runningLongClick = false;
removeCallbacks(detectLongClick);
removeCallbacks(onBackButton);
}
}
super.onTouchEvent(event);
return backDetector.onTouchEvent(event);
}
};
backButton.setImageResource(R.drawable.msg_clear_input);
backButton.setColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
backButton.setBackground(getButtonDrawable());
int pad = AndroidUtilities.dp(11);
backButton.setPadding(pad, pad, pad, pad);
backButton.setOnClickListener(v -> {});
addView(views[11] = backButton);
}
@Override
public boolean canScrollHorizontally(int direction) {
return true;
}
public void setDispatchBackWhenEmpty(boolean dispatchBackWhenEmpty) {
this.dispatchBackWhenEmpty = dispatchBackWhenEmpty;
}
private GestureDetectorCompat setupBackButtonDetector(Context context) {
int touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
return new GestureDetectorCompat(context, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDown(MotionEvent e) {
if (postedLongClick) {
removeCallbacks(detectLongClick);
}
postedLongClick = true;
postDelayed(detectLongClick, 200);
onBackButton.run();
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if ((postedLongClick || runningLongClick) && (Math.abs(distanceX) >= touchSlop || Math.abs(distanceY) >= touchSlop)) {
postedLongClick = false;
runningLongClick = false;
removeCallbacks(detectLongClick);
removeCallbacks(onBackButton);
}
return false;
}
});
}
public void setEditText(EditText editText) {
this.editText = editText;
dispatchBackWhenEmpty = false;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int btnWidth = (getWidth() - AndroidUtilities.dp(SIDE_PADDING * 2 + BUTTON_PADDING * 2)) / 3;
int btnHeight = (getHeight() - AndroidUtilities.dp(SIDE_PADDING * 3 + BUTTON_PADDING * 2)) / 4;
for (int i = 0; i < views.length; i++) {
int rowX = i % 3, rowY = i / 3;
int left = rowX * (btnWidth + AndroidUtilities.dp(BUTTON_PADDING)) + AndroidUtilities.dp(SIDE_PADDING);
int top = rowY * (btnHeight + AndroidUtilities.dp(BUTTON_PADDING)) + AndroidUtilities.dp(SIDE_PADDING);
if (views[i] != null) {
views[i].layout(left, top, left + btnWidth, top + btnHeight);
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec));
int btnWidth = (getWidth() - AndroidUtilities.dp(SIDE_PADDING * 2 + BUTTON_PADDING * 2)) / 3;
int btnHeight = (getHeight() - AndroidUtilities.dp(SIDE_PADDING * 3 + BUTTON_PADDING * 2)) / 4;
for (View v : views) {
if (v != null) {
v.measure(MeasureSpec.makeMeasureSpec(btnWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(btnHeight, MeasureSpec.EXACTLY));
}
}
}
private static Drawable getButtonDrawable() {
return Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(6), Theme.getColor(Theme.key_listSelector), ColorUtils.setAlphaComponent(Theme.getColor(Theme.key_listSelector), 60));
}
public void updateColors() {
backButton.setColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
for (View v : views) {
if (v != null) {
v.setBackground(getButtonDrawable());
if (v instanceof NumberButtonView) {
((NumberButtonView) v).updateColors();
}
}
}
}
private final static class NumberButtonView extends View {
private TextPaint numberTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
private TextPaint symbolsTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
private String mNumber, mSymbols;
private Rect rect = new Rect();
public NumberButtonView(Context context, String number, String symbols) {
super(context);
mNumber = number;
mSymbols = symbols;
numberTextPaint.setTextSize(AndroidUtilities.dp(24));
symbolsTextPaint.setTextSize(AndroidUtilities.dp(14));
setBackground(getButtonDrawable());
updateColors();
}
private void updateColors() {
numberTextPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
symbolsTextPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteHintText));
}
@Override
protected void onDraw(Canvas canvas) {
float symbolsWidth = symbolsTextPaint.measureText(mSymbols);
float numberWidth = numberTextPaint.measureText(mNumber);
numberTextPaint.getTextBounds(mNumber, 0, mNumber.length(), rect);
float textOffsetNumber = rect.height() / 2f;
symbolsTextPaint.getTextBounds(mSymbols, 0, mSymbols.length(), rect);
float textOffsetSymbols = rect.height() / 2f;
canvas.drawText(mNumber, getWidth() * 0.25f - numberWidth / 2f, getHeight() / 2f + textOffsetNumber, numberTextPaint);
canvas.drawText(mSymbols, getWidth() * 0.7f - symbolsWidth / 2f, getHeight() / 2f + textOffsetSymbols, symbolsTextPaint);
}
}
}