2017-03-31 01:58:05 +02:00
|
|
|
/*
|
2019-01-23 18:03:33 +01:00
|
|
|
* This is the source code of Telegram for Android v. 5.x.x.
|
2017-03-31 01:58:05 +02:00
|
|
|
* It is licensed under GNU GPL v. 2 or later.
|
|
|
|
* You should have received a copy of the license in this archive (see LICENSE).
|
|
|
|
*
|
2019-01-23 18:03:33 +01:00
|
|
|
* Copyright Nikolai Kudashov, 2013-2018.
|
2017-03-31 01:58:05 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
package org.telegram.ui.Components;
|
|
|
|
|
|
|
|
import android.annotation.SuppressLint;
|
|
|
|
import android.content.Context;
|
|
|
|
import android.graphics.Canvas;
|
|
|
|
import android.graphics.Paint;
|
2019-12-31 14:08:08 +01:00
|
|
|
import android.graphics.Rect;
|
2017-03-31 01:58:05 +02:00
|
|
|
import android.os.Build;
|
2020-07-26 10:03:38 +02:00
|
|
|
import android.os.Bundle;
|
2017-03-31 01:58:05 +02:00
|
|
|
import android.text.Editable;
|
|
|
|
import android.text.Layout;
|
|
|
|
import android.text.Spanned;
|
|
|
|
import android.text.StaticLayout;
|
|
|
|
import android.text.TextPaint;
|
|
|
|
import android.text.TextUtils;
|
2020-09-30 15:48:47 +02:00
|
|
|
import android.text.TextWatcher;
|
2018-07-30 04:07:02 +02:00
|
|
|
import android.text.style.CharacterStyle;
|
|
|
|
import android.util.TypedValue;
|
2017-03-31 01:58:05 +02:00
|
|
|
import android.view.ActionMode;
|
2018-07-30 04:07:02 +02:00
|
|
|
import android.view.Gravity;
|
2017-03-31 01:58:05 +02:00
|
|
|
import android.view.Menu;
|
|
|
|
import android.view.MenuItem;
|
2019-12-31 14:08:08 +01:00
|
|
|
import android.view.View;
|
2018-07-30 04:07:02 +02:00
|
|
|
import android.view.ViewGroup;
|
2019-05-14 14:08:05 +02:00
|
|
|
import android.view.accessibility.AccessibilityNodeInfo;
|
2018-07-30 04:07:02 +02:00
|
|
|
import android.view.inputmethod.EditorInfo;
|
|
|
|
import android.widget.FrameLayout;
|
2017-03-31 01:58:05 +02:00
|
|
|
|
2020-07-26 10:03:38 +02:00
|
|
|
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
|
|
|
|
|
2020-06-25 17:28:44 +02:00
|
|
|
import org.jetbrains.annotations.NotNull;
|
2017-03-31 01:58:05 +02:00
|
|
|
import org.telegram.messenger.AndroidUtilities;
|
|
|
|
import org.telegram.messenger.FileLog;
|
2018-07-30 04:07:02 +02:00
|
|
|
import org.telegram.messenger.LocaleController;
|
2019-07-18 15:01:39 +02:00
|
|
|
import org.telegram.messenger.MediaDataController;
|
2017-03-31 01:58:05 +02:00
|
|
|
import org.telegram.messenger.R;
|
2018-07-30 04:07:02 +02:00
|
|
|
import org.telegram.ui.ActionBar.AlertDialog;
|
|
|
|
import org.telegram.ui.ActionBar.Theme;
|
2017-03-31 01:58:05 +02:00
|
|
|
|
2020-11-22 03:57:43 +01:00
|
|
|
import java.util.List;
|
|
|
|
|
2020-06-25 17:28:44 +02:00
|
|
|
import cn.hutool.core.util.StrUtil;
|
2022-01-17 08:45:37 +01:00
|
|
|
import tw.nekomimi.nekogram.NekoConfig;
|
2020-06-25 17:28:44 +02:00
|
|
|
import tw.nekomimi.nekogram.transtale.TranslateDb;
|
|
|
|
import tw.nekomimi.nekogram.transtale.Translator;
|
|
|
|
import tw.nekomimi.nekogram.transtale.TranslatorKt;
|
|
|
|
import tw.nekomimi.nekogram.utils.AlertUtil;
|
|
|
|
|
2017-03-31 01:58:05 +02:00
|
|
|
public class EditTextCaption extends EditTextBoldCursor {
|
|
|
|
|
2020-07-26 10:03:38 +02:00
|
|
|
private static final int ACCESSIBILITY_ACTION_SHARE = 0x10000000;
|
|
|
|
|
2017-03-31 01:58:05 +02:00
|
|
|
private String caption;
|
|
|
|
private StaticLayout captionLayout;
|
|
|
|
private int userNameLength;
|
|
|
|
private int xOffset;
|
|
|
|
private int yOffset;
|
|
|
|
private int triesCount = 0;
|
|
|
|
private boolean copyPasteShowed;
|
|
|
|
private int hintColor;
|
2018-07-30 04:07:02 +02:00
|
|
|
private EditTextCaptionDelegate delegate;
|
|
|
|
private int selectionStart = -1;
|
|
|
|
private int selectionEnd = -1;
|
2019-07-18 15:01:39 +02:00
|
|
|
private boolean allowTextEntitiesIntersection;
|
2020-07-26 10:03:38 +02:00
|
|
|
private float offsetY;
|
2020-09-30 15:48:47 +02:00
|
|
|
private int lineCount;
|
|
|
|
private boolean isInitLineCount;
|
2021-09-20 00:10:42 +02:00
|
|
|
private final Theme.ResourcesProvider resourcesProvider;
|
2018-07-30 04:07:02 +02:00
|
|
|
|
|
|
|
public interface EditTextCaptionDelegate {
|
|
|
|
void onSpansChanged();
|
2020-06-25 17:28:44 +02:00
|
|
|
|
2021-09-20 11:14:20 +02:00
|
|
|
long getCurrentChat();
|
2018-07-30 04:07:02 +02:00
|
|
|
}
|
2017-03-31 01:58:05 +02:00
|
|
|
|
2021-09-20 00:10:42 +02:00
|
|
|
public EditTextCaption(Context context, Theme.ResourcesProvider resourcesProvider) {
|
2017-03-31 01:58:05 +02:00
|
|
|
super(context);
|
2021-09-20 00:10:42 +02:00
|
|
|
this.resourcesProvider = resourcesProvider;
|
2020-09-30 15:48:47 +02:00
|
|
|
addTextChangedListener(new TextWatcher() {
|
|
|
|
@Override
|
|
|
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void afterTextChanged(Editable s) {
|
|
|
|
if (lineCount != getLineCount()) {
|
|
|
|
if (!isInitLineCount && getMeasuredWidth() > 0) {
|
|
|
|
onLineCountChanged(lineCount, getLineCount());
|
|
|
|
}
|
|
|
|
lineCount = getLineCount();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void onLineCountChanged(int oldLineCount, int newLineCount) {
|
|
|
|
|
2017-03-31 01:58:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public void setCaption(String value) {
|
2019-07-18 15:01:39 +02:00
|
|
|
if ((caption == null || caption.length() == 0) && (value == null || value.length() == 0) || caption != null && caption.equals(value)) {
|
2017-03-31 01:58:05 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
caption = value;
|
|
|
|
if (caption != null) {
|
|
|
|
caption = caption.replace('\n', ' ');
|
|
|
|
}
|
|
|
|
requestLayout();
|
|
|
|
}
|
|
|
|
|
2018-07-30 04:07:02 +02:00
|
|
|
public void setDelegate(EditTextCaptionDelegate editTextCaptionDelegate) {
|
|
|
|
delegate = editTextCaptionDelegate;
|
|
|
|
}
|
|
|
|
|
2019-07-18 15:01:39 +02:00
|
|
|
public void setAllowTextEntitiesIntersection(boolean value) {
|
|
|
|
allowTextEntitiesIntersection = value;
|
|
|
|
}
|
|
|
|
|
2018-07-30 04:07:02 +02:00
|
|
|
public void makeSelectedBold() {
|
2019-07-18 15:01:39 +02:00
|
|
|
TextStyleSpan.TextStyleRun run = new TextStyleSpan.TextStyleRun();
|
|
|
|
run.flags |= TextStyleSpan.FLAG_STYLE_BOLD;
|
|
|
|
applyTextStyleToSelection(new TextStyleSpan(run));
|
2017-03-31 01:58:05 +02:00
|
|
|
}
|
|
|
|
|
2021-12-30 11:52:40 +01:00
|
|
|
public void makeSelectedSpoiler() {
|
|
|
|
TextStyleSpan.TextStyleRun run = new TextStyleSpan.TextStyleRun();
|
|
|
|
run.flags |= TextStyleSpan.FLAG_STYLE_SPOILER;
|
|
|
|
applyTextStyleToSelection(new TextStyleSpan(run));
|
|
|
|
}
|
|
|
|
|
2018-07-30 04:07:02 +02:00
|
|
|
public void makeSelectedItalic() {
|
2019-07-18 15:01:39 +02:00
|
|
|
TextStyleSpan.TextStyleRun run = new TextStyleSpan.TextStyleRun();
|
|
|
|
run.flags |= TextStyleSpan.FLAG_STYLE_ITALIC;
|
|
|
|
applyTextStyleToSelection(new TextStyleSpan(run));
|
2017-03-31 01:58:05 +02:00
|
|
|
}
|
|
|
|
|
2018-07-30 04:07:02 +02:00
|
|
|
public void makeSelectedMono() {
|
2019-07-18 15:01:39 +02:00
|
|
|
TextStyleSpan.TextStyleRun run = new TextStyleSpan.TextStyleRun();
|
|
|
|
run.flags |= TextStyleSpan.FLAG_STYLE_MONO;
|
|
|
|
applyTextStyleToSelection(new TextStyleSpan(run));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void makeSelectedStrike() {
|
|
|
|
TextStyleSpan.TextStyleRun run = new TextStyleSpan.TextStyleRun();
|
|
|
|
run.flags |= TextStyleSpan.FLAG_STYLE_STRIKE;
|
|
|
|
applyTextStyleToSelection(new TextStyleSpan(run));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void makeSelectedUnderline() {
|
|
|
|
TextStyleSpan.TextStyleRun run = new TextStyleSpan.TextStyleRun();
|
|
|
|
run.flags |= TextStyleSpan.FLAG_STYLE_UNDERLINE;
|
|
|
|
applyTextStyleToSelection(new TextStyleSpan(run));
|
2018-07-30 04:07:02 +02:00
|
|
|
}
|
|
|
|
|
2020-06-25 17:28:44 +02:00
|
|
|
private String replaceAt(String origin, int start, int end, String translation) {
|
|
|
|
|
|
|
|
String trans = origin.substring(0, start);
|
|
|
|
|
|
|
|
trans += translation;
|
|
|
|
|
|
|
|
trans += origin.substring(end);
|
|
|
|
|
|
|
|
return trans;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
public void makeSelectedTranslate() {
|
|
|
|
|
|
|
|
int start = getSelectionStart();
|
|
|
|
int end = getSelectionEnd();
|
|
|
|
|
|
|
|
String origin = getText().toString();
|
|
|
|
String text = getText().subSequence(start, end).toString();
|
|
|
|
|
|
|
|
if (StrUtil.isBlank(origin)) return;
|
|
|
|
|
|
|
|
TranslateDb db = TranslateDb.currentInputTarget();
|
|
|
|
|
|
|
|
if (db.contains(text)) {
|
|
|
|
|
|
|
|
setText(replaceAt(origin, start, end, TranslateDb.currentInputTarget().query(text)));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
2022-01-17 08:45:37 +01:00
|
|
|
Translator.translate(TranslateDb.getChatLanguage(delegate.getCurrentChat(), TranslatorKt.getCode2Locale(NekoConfig.translateInputLang.String())), text, new Translator.Companion.TranslateCallBack() {
|
2020-06-25 17:28:44 +02:00
|
|
|
|
2020-06-26 06:54:48 +02:00
|
|
|
AlertDialog status = AlertUtil.showProgress(getContext());
|
2020-06-25 17:28:44 +02:00
|
|
|
|
2020-06-26 06:54:48 +02:00
|
|
|
{
|
|
|
|
status.show();
|
|
|
|
}
|
2020-06-25 17:28:44 +02:00
|
|
|
|
2020-06-26 06:54:48 +02:00
|
|
|
@Override
|
|
|
|
public void onSuccess(@NotNull String translation) {
|
|
|
|
status.dismiss();
|
|
|
|
setText(replaceAt(origin, start, end, translation));
|
|
|
|
}
|
2020-06-25 17:28:44 +02:00
|
|
|
|
2020-06-26 06:54:48 +02:00
|
|
|
@Override
|
|
|
|
public void onFailed(boolean unsupported, @NotNull String message) {
|
|
|
|
status.dismiss();
|
|
|
|
AlertUtil.showTransFailedDialog(getContext(), unsupported, message, () -> {
|
|
|
|
status = AlertUtil.showProgress(getContext());
|
|
|
|
status.show();
|
|
|
|
Translator.translate(text, this);
|
|
|
|
});
|
|
|
|
}
|
2020-06-25 17:28:44 +02:00
|
|
|
|
2020-06-26 06:54:48 +02:00
|
|
|
});
|
2020-06-25 17:28:44 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2019-06-20 15:37:50 +02:00
|
|
|
|
|
|
|
public void makeSelectedMention() {
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
|
|
|
builder.setTitle(LocaleController.getString("CreateMention", R.string.CreateMention));
|
|
|
|
|
|
|
|
final EditTextBoldCursor editText = new EditTextBoldCursor(getContext()) {
|
|
|
|
@Override
|
|
|
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
|
|
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(64), MeasureSpec.EXACTLY));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
editText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);
|
|
|
|
editText.setTextColor(Theme.getColor(Theme.key_dialogTextBlack));
|
|
|
|
editText.setHintText("ID");
|
|
|
|
editText.setHeaderHintColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueHeader));
|
|
|
|
editText.setSingleLine(true);
|
|
|
|
editText.setFocusable(true);
|
|
|
|
editText.setTransformHintToHeader(true);
|
|
|
|
editText.setLineColors(Theme.getColor(Theme.key_windowBackgroundWhiteInputField), Theme.getColor(Theme.key_windowBackgroundWhiteInputFieldActivated), Theme.getColor(Theme.key_windowBackgroundWhiteRedText3));
|
|
|
|
editText.setImeOptions(EditorInfo.IME_ACTION_DONE);
|
|
|
|
editText.setBackgroundDrawable(null);
|
|
|
|
editText.requestFocus();
|
|
|
|
editText.setPadding(0, 0, 0, 0);
|
|
|
|
builder.setView(editText);
|
|
|
|
|
|
|
|
final int start;
|
|
|
|
final int end;
|
|
|
|
if (selectionStart >= 0 && selectionEnd >= 0) {
|
|
|
|
start = selectionStart;
|
|
|
|
end = selectionEnd;
|
|
|
|
selectionStart = selectionEnd = -1;
|
|
|
|
} else {
|
|
|
|
start = getSelectionStart();
|
|
|
|
end = getSelectionEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> {
|
|
|
|
Editable editable = getText();
|
|
|
|
CharacterStyle spans[] = editable.getSpans(start, end, CharacterStyle.class);
|
|
|
|
if (spans != null && spans.length > 0) {
|
|
|
|
for (int a = 0; a < spans.length; a++) {
|
|
|
|
CharacterStyle oldSpan = spans[a];
|
|
|
|
int spanStart = editable.getSpanStart(oldSpan);
|
|
|
|
int spanEnd = editable.getSpanEnd(oldSpan);
|
|
|
|
editable.removeSpan(oldSpan);
|
|
|
|
if (spanStart < start) {
|
|
|
|
editable.setSpan(oldSpan, spanStart, start, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
}
|
|
|
|
if (spanEnd > end) {
|
|
|
|
editable.setSpan(oldSpan, end, spanEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
editable.setSpan(new URLSpanUserMention(editText.getText().toString(), 1), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
} catch (Exception ignore) {
|
|
|
|
|
|
|
|
}
|
|
|
|
if (delegate != null) {
|
|
|
|
delegate.onSpansChanged();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null);
|
|
|
|
builder.show().setOnShowListener(dialog -> {
|
|
|
|
editText.requestFocus();
|
|
|
|
AndroidUtilities.showKeyboard(editText);
|
|
|
|
});
|
|
|
|
if (editText != null) {
|
|
|
|
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) editText.getLayoutParams();
|
|
|
|
if (layoutParams != null) {
|
|
|
|
if (layoutParams instanceof FrameLayout.LayoutParams) {
|
|
|
|
((FrameLayout.LayoutParams) layoutParams).gravity = Gravity.CENTER_HORIZONTAL;
|
|
|
|
}
|
|
|
|
layoutParams.rightMargin = layoutParams.leftMargin = AndroidUtilities.dp(24);
|
|
|
|
layoutParams.height = AndroidUtilities.dp(36);
|
|
|
|
editText.setLayoutParams(layoutParams);
|
|
|
|
}
|
|
|
|
editText.setSelection(0, editText.getText().length());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-30 04:07:02 +02:00
|
|
|
public void makeSelectedUrl() {
|
2021-09-20 00:10:42 +02:00
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(getContext(), resourcesProvider);
|
2018-07-30 04:07:02 +02:00
|
|
|
builder.setTitle(LocaleController.getString("CreateLink", R.string.CreateLink));
|
|
|
|
|
|
|
|
final EditTextBoldCursor editText = new EditTextBoldCursor(getContext()) {
|
|
|
|
@Override
|
|
|
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
|
|
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(64), MeasureSpec.EXACTLY));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
editText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);
|
|
|
|
editText.setText("http://");
|
2021-09-20 00:10:42 +02:00
|
|
|
editText.setTextColor(getThemedColor(Theme.key_dialogTextBlack));
|
2018-07-30 04:07:02 +02:00
|
|
|
editText.setHintText(LocaleController.getString("URL", R.string.URL));
|
2021-09-20 00:10:42 +02:00
|
|
|
editText.setHeaderHintColor(getThemedColor(Theme.key_windowBackgroundWhiteBlueHeader));
|
2018-07-30 04:07:02 +02:00
|
|
|
editText.setSingleLine(true);
|
|
|
|
editText.setFocusable(true);
|
|
|
|
editText.setTransformHintToHeader(true);
|
2021-09-20 00:10:42 +02:00
|
|
|
editText.setLineColors(getThemedColor(Theme.key_windowBackgroundWhiteInputField), getThemedColor(Theme.key_windowBackgroundWhiteInputFieldActivated), getThemedColor(Theme.key_windowBackgroundWhiteRedText3));
|
2018-07-30 04:07:02 +02:00
|
|
|
editText.setImeOptions(EditorInfo.IME_ACTION_DONE);
|
|
|
|
editText.setBackgroundDrawable(null);
|
|
|
|
editText.requestFocus();
|
|
|
|
editText.setPadding(0, 0, 0, 0);
|
|
|
|
builder.setView(editText);
|
|
|
|
|
|
|
|
final int start;
|
|
|
|
final int end;
|
|
|
|
if (selectionStart >= 0 && selectionEnd >= 0) {
|
|
|
|
start = selectionStart;
|
|
|
|
end = selectionEnd;
|
|
|
|
selectionStart = selectionEnd = -1;
|
|
|
|
} else {
|
|
|
|
start = getSelectionStart();
|
|
|
|
end = getSelectionEnd();
|
|
|
|
}
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> {
|
|
|
|
Editable editable = getText();
|
2019-07-18 15:01:39 +02:00
|
|
|
CharacterStyle[] spans = editable.getSpans(start, end, CharacterStyle.class);
|
2019-01-23 18:03:33 +01:00
|
|
|
if (spans != null && spans.length > 0) {
|
|
|
|
for (int a = 0; a < spans.length; a++) {
|
|
|
|
CharacterStyle oldSpan = spans[a];
|
|
|
|
int spanStart = editable.getSpanStart(oldSpan);
|
|
|
|
int spanEnd = editable.getSpanEnd(oldSpan);
|
|
|
|
editable.removeSpan(oldSpan);
|
|
|
|
if (spanStart < start) {
|
|
|
|
editable.setSpan(oldSpan, spanStart, start, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
}
|
|
|
|
if (spanEnd > end) {
|
|
|
|
editable.setSpan(oldSpan, end, spanEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
2018-07-30 04:07:02 +02:00
|
|
|
}
|
|
|
|
}
|
2019-01-23 18:03:33 +01:00
|
|
|
}
|
|
|
|
try {
|
2018-07-30 04:07:02 +02:00
|
|
|
editable.setSpan(new URLSpanReplacement(editText.getText().toString()), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
2019-07-18 15:01:39 +02:00
|
|
|
} catch (Exception ignore) {
|
2019-01-23 18:03:33 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
if (delegate != null) {
|
|
|
|
delegate.onSpansChanged();
|
2018-07-30 04:07:02 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null);
|
2019-01-23 18:03:33 +01:00
|
|
|
builder.show().setOnShowListener(dialog -> {
|
|
|
|
editText.requestFocus();
|
|
|
|
AndroidUtilities.showKeyboard(editText);
|
2018-07-30 04:07:02 +02:00
|
|
|
});
|
|
|
|
if (editText != null) {
|
|
|
|
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) editText.getLayoutParams();
|
|
|
|
if (layoutParams != null) {
|
|
|
|
if (layoutParams instanceof FrameLayout.LayoutParams) {
|
|
|
|
((FrameLayout.LayoutParams) layoutParams).gravity = Gravity.CENTER_HORIZONTAL;
|
|
|
|
}
|
|
|
|
layoutParams.rightMargin = layoutParams.leftMargin = AndroidUtilities.dp(24);
|
|
|
|
layoutParams.height = AndroidUtilities.dp(36);
|
|
|
|
editText.setLayoutParams(layoutParams);
|
|
|
|
}
|
|
|
|
editText.setSelection(0, editText.getText().length());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void makeSelectedRegular() {
|
2017-03-31 01:58:05 +02:00
|
|
|
applyTextStyleToSelection(null);
|
|
|
|
}
|
|
|
|
|
2018-07-30 04:07:02 +02:00
|
|
|
public void setSelectionOverride(int start, int end) {
|
|
|
|
selectionStart = start;
|
|
|
|
selectionEnd = end;
|
|
|
|
}
|
2017-03-31 01:58:05 +02:00
|
|
|
|
2019-07-18 15:01:39 +02:00
|
|
|
private void applyTextStyleToSelection(TextStyleSpan span) {
|
2018-07-30 04:07:02 +02:00
|
|
|
int start;
|
|
|
|
int end;
|
|
|
|
if (selectionStart >= 0 && selectionEnd >= 0) {
|
|
|
|
start = selectionStart;
|
|
|
|
end = selectionEnd;
|
|
|
|
selectionStart = selectionEnd = -1;
|
|
|
|
} else {
|
|
|
|
start = getSelectionStart();
|
|
|
|
end = getSelectionEnd();
|
2017-03-31 01:58:05 +02:00
|
|
|
}
|
2019-07-18 15:01:39 +02:00
|
|
|
MediaDataController.addStyleToText(span, start, end, getText(), allowTextEntitiesIntersection);
|
2018-07-30 04:07:02 +02:00
|
|
|
if (delegate != null) {
|
|
|
|
delegate.onSpansChanged();
|
|
|
|
}
|
2017-03-31 01:58:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onWindowFocusChanged(boolean hasWindowFocus) {
|
|
|
|
if (Build.VERSION.SDK_INT < 23 && !hasWindowFocus && copyPasteShowed) {
|
|
|
|
return;
|
|
|
|
}
|
2021-06-25 02:43:10 +02:00
|
|
|
try {
|
|
|
|
super.onWindowFocusChanged(hasWindowFocus);
|
|
|
|
} catch (Throwable e) {
|
|
|
|
FileLog.e(e);
|
|
|
|
}
|
2017-03-31 01:58:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private ActionMode.Callback overrideCallback(final ActionMode.Callback callback) {
|
2019-12-31 14:08:08 +01:00
|
|
|
ActionMode.Callback wrap = new ActionMode.Callback() {
|
2017-03-31 01:58:05 +02:00
|
|
|
@Override
|
|
|
|
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
|
|
|
copyPasteShowed = true;
|
|
|
|
return callback.onCreateActionMode(mode, menu);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
|
|
|
return callback.onPrepareActionMode(mode, menu);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
2020-07-26 10:03:38 +02:00
|
|
|
if (performMenuAction(item.getItemId())) {
|
2020-06-25 17:28:44 +02:00
|
|
|
mode.finish();
|
|
|
|
return true;
|
2017-03-31 01:58:05 +02:00
|
|
|
}
|
2017-12-08 18:35:59 +01:00
|
|
|
try {
|
|
|
|
return callback.onActionItemClicked(mode, item);
|
|
|
|
} catch (Exception ignore) {
|
|
|
|
}
|
|
|
|
return true;
|
2017-03-31 01:58:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onDestroyActionMode(ActionMode mode) {
|
|
|
|
copyPasteShowed = false;
|
|
|
|
callback.onDestroyActionMode(mode);
|
|
|
|
}
|
|
|
|
};
|
2019-12-31 14:08:08 +01:00
|
|
|
if (Build.VERSION.SDK_INT >= 23) {
|
|
|
|
return new ActionMode.Callback2() {
|
|
|
|
@Override
|
|
|
|
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
|
|
|
return wrap.onCreateActionMode(mode, menu);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
|
|
|
return wrap.onPrepareActionMode(mode, menu);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
|
|
|
return wrap.onActionItemClicked(mode, item);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onDestroyActionMode(ActionMode mode) {
|
|
|
|
wrap.onDestroyActionMode(mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onGetContentRect(ActionMode mode, View view, Rect outRect) {
|
|
|
|
if (callback instanceof ActionMode.Callback2) {
|
|
|
|
((ActionMode.Callback2) callback).onGetContentRect(mode, view, outRect);
|
|
|
|
} else {
|
|
|
|
super.onGetContentRect(mode, view, outRect);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
return wrap;
|
|
|
|
}
|
2017-03-31 01:58:05 +02:00
|
|
|
}
|
|
|
|
|
2020-07-26 10:03:38 +02:00
|
|
|
private boolean performMenuAction(int itemId) {
|
|
|
|
if (itemId == R.id.menu_regular) {
|
|
|
|
makeSelectedRegular();
|
|
|
|
return true;
|
|
|
|
} else if (itemId == R.id.menu_bold) {
|
|
|
|
makeSelectedBold();
|
|
|
|
return true;
|
|
|
|
} else if (itemId == R.id.menu_italic) {
|
|
|
|
makeSelectedItalic();
|
|
|
|
return true;
|
|
|
|
} else if (itemId == R.id.menu_mono) {
|
|
|
|
makeSelectedMono();
|
|
|
|
return true;
|
|
|
|
} else if (itemId == R.id.menu_link) {
|
|
|
|
makeSelectedUrl();
|
|
|
|
return true;
|
2020-11-22 03:57:43 +01:00
|
|
|
} else if (itemId == R.id.menu_mention) {
|
|
|
|
makeSelectedMention();
|
|
|
|
return true;
|
2020-07-26 10:03:38 +02:00
|
|
|
} else if (itemId == R.id.menu_strike) {
|
|
|
|
makeSelectedStrike();
|
|
|
|
return true;
|
|
|
|
} else if (itemId == R.id.menu_underline) {
|
|
|
|
makeSelectedUnderline();
|
|
|
|
return true;
|
2021-12-30 11:52:40 +01:00
|
|
|
} else if (itemId == R.id.menu_spoiler) {
|
|
|
|
makeSelectedSpoiler();
|
|
|
|
return true;
|
2020-07-27 02:58:40 +02:00
|
|
|
} else if (itemId == R.id.menu_translate) {
|
2021-12-31 19:10:02 +01:00
|
|
|
// NekoX
|
2020-07-27 02:58:40 +02:00
|
|
|
makeSelectedTranslate();
|
|
|
|
return true;
|
2020-07-26 10:03:38 +02:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-03-31 01:58:05 +02:00
|
|
|
@Override
|
|
|
|
public ActionMode startActionMode(final ActionMode.Callback callback, int type) {
|
|
|
|
return super.startActionMode(overrideCallback(callback), type);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ActionMode startActionMode(final ActionMode.Callback callback) {
|
|
|
|
return super.startActionMode(overrideCallback(callback));
|
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressLint("DrawAllocation")
|
|
|
|
@Override
|
|
|
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
|
|
try {
|
2020-09-30 15:48:47 +02:00
|
|
|
isInitLineCount = getMeasuredWidth() == 0 && getMeasuredHeight() == 0;
|
2017-03-31 01:58:05 +02:00
|
|
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
2020-09-30 15:48:47 +02:00
|
|
|
if (isInitLineCount) {
|
|
|
|
lineCount = getLineCount();
|
|
|
|
}
|
|
|
|
isInitLineCount = false;
|
2017-03-31 01:58:05 +02:00
|
|
|
} catch (Exception e) {
|
|
|
|
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), AndroidUtilities.dp(51));
|
|
|
|
FileLog.e(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
captionLayout = null;
|
|
|
|
|
|
|
|
if (caption != null && caption.length() > 0) {
|
|
|
|
CharSequence text = getText();
|
|
|
|
if (text.length() > 1 && text.charAt(0) == '@') {
|
|
|
|
int index = TextUtils.indexOf(text, ' ');
|
|
|
|
if (index != -1) {
|
|
|
|
TextPaint paint = getPaint();
|
|
|
|
CharSequence str = text.subSequence(0, index + 1);
|
|
|
|
int size = (int) Math.ceil(paint.measureText(text, 0, index + 1));
|
|
|
|
int width = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
|
|
|
|
userNameLength = str.length();
|
|
|
|
CharSequence captionFinal = TextUtils.ellipsize(caption, paint, width - size, TextUtils.TruncateAt.END);
|
|
|
|
xOffset = size;
|
|
|
|
try {
|
|
|
|
captionLayout = new StaticLayout(captionFinal, getPaint(), width - size, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
|
|
|
|
if (captionLayout.getLineCount() > 0) {
|
|
|
|
xOffset += -captionLayout.getLineLeft(0);
|
|
|
|
}
|
|
|
|
yOffset = (getMeasuredHeight() - captionLayout.getLineBottom(0)) / 2 + AndroidUtilities.dp(0.5f);
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public String getCaption() {
|
|
|
|
return caption;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void setHintColor(int value) {
|
|
|
|
super.setHintColor(value);
|
|
|
|
hintColor = value;
|
|
|
|
invalidate();
|
|
|
|
}
|
|
|
|
|
2020-07-26 10:03:38 +02:00
|
|
|
public void setOffsetY(float offset) {
|
|
|
|
this.offsetY = offset;
|
|
|
|
invalidate();
|
|
|
|
}
|
|
|
|
|
|
|
|
public float getOffsetY() {
|
|
|
|
return offsetY;
|
|
|
|
}
|
|
|
|
|
2017-03-31 01:58:05 +02:00
|
|
|
@Override
|
|
|
|
protected void onDraw(Canvas canvas) {
|
2020-07-26 10:03:38 +02:00
|
|
|
canvas.save();
|
|
|
|
canvas.translate(0, offsetY);
|
2017-03-31 01:58:05 +02:00
|
|
|
super.onDraw(canvas);
|
|
|
|
try {
|
|
|
|
if (captionLayout != null && userNameLength == length()) {
|
|
|
|
Paint paint = getPaint();
|
|
|
|
int oldColor = getPaint().getColor();
|
|
|
|
paint.setColor(hintColor);
|
|
|
|
canvas.save();
|
|
|
|
canvas.translate(xOffset, yOffset);
|
|
|
|
captionLayout.draw(canvas);
|
|
|
|
canvas.restore();
|
|
|
|
paint.setColor(oldColor);
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e(e);
|
|
|
|
}
|
2020-07-26 10:03:38 +02:00
|
|
|
canvas.restore();
|
2017-03-31 01:58:05 +02:00
|
|
|
}
|
2019-05-14 14:08:05 +02:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
|
|
|
|
super.onInitializeAccessibilityNodeInfo(info);
|
2020-07-26 10:03:38 +02:00
|
|
|
final AccessibilityNodeInfoCompat infoCompat = AccessibilityNodeInfoCompat.wrap(info);
|
2019-05-14 14:08:05 +02:00
|
|
|
if (!TextUtils.isEmpty(caption)) {
|
2020-07-26 10:03:38 +02:00
|
|
|
infoCompat.setHintText(caption);
|
|
|
|
}
|
|
|
|
final List<AccessibilityNodeInfoCompat.AccessibilityActionCompat> actions = infoCompat.getActionList();
|
|
|
|
for (int i = 0, size = actions.size(); i < size; i++) {
|
|
|
|
final AccessibilityNodeInfoCompat.AccessibilityActionCompat action = actions.get(i);
|
|
|
|
if (action.getId() == ACCESSIBILITY_ACTION_SHARE) {
|
|
|
|
infoCompat.removeAction(action);
|
|
|
|
break;
|
2019-12-31 14:08:08 +01:00
|
|
|
}
|
2019-05-14 14:08:05 +02:00
|
|
|
}
|
2020-07-26 10:03:38 +02:00
|
|
|
if (hasSelection()) {
|
2021-12-30 11:52:40 +01:00
|
|
|
infoCompat.addAction(new AccessibilityNodeInfoCompat.AccessibilityActionCompat(R.id.menu_spoiler, LocaleController.getString("Spoiler", R.string.Spoiler)));
|
2020-07-26 10:03:38 +02:00
|
|
|
infoCompat.addAction(new AccessibilityNodeInfoCompat.AccessibilityActionCompat(R.id.menu_bold, LocaleController.getString("Bold", R.string.Bold)));
|
|
|
|
infoCompat.addAction(new AccessibilityNodeInfoCompat.AccessibilityActionCompat(R.id.menu_italic, LocaleController.getString("Italic", R.string.Italic)));
|
|
|
|
infoCompat.addAction(new AccessibilityNodeInfoCompat.AccessibilityActionCompat(R.id.menu_mono, LocaleController.getString("Mono", R.string.Mono)));
|
|
|
|
infoCompat.addAction(new AccessibilityNodeInfoCompat.AccessibilityActionCompat(R.id.menu_strike, LocaleController.getString("Strike", R.string.Strike)));
|
|
|
|
infoCompat.addAction(new AccessibilityNodeInfoCompat.AccessibilityActionCompat(R.id.menu_underline, LocaleController.getString("Underline", R.string.Underline)));
|
|
|
|
infoCompat.addAction(new AccessibilityNodeInfoCompat.AccessibilityActionCompat(R.id.menu_link, LocaleController.getString("CreateLink", R.string.CreateLink)));
|
|
|
|
infoCompat.addAction(new AccessibilityNodeInfoCompat.AccessibilityActionCompat(R.id.menu_regular, LocaleController.getString("Regular", R.string.Regular)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean performAccessibilityAction(int action, Bundle arguments) {
|
|
|
|
return performMenuAction(action) || super.performAccessibilityAction(action, arguments);
|
2019-05-14 14:08:05 +02:00
|
|
|
}
|
2021-09-20 00:10:42 +02:00
|
|
|
|
|
|
|
private int getThemedColor(String key) {
|
|
|
|
Integer color = resourcesProvider != null ? resourcesProvider.getColor(key) : null;
|
|
|
|
return color != null ? color : Theme.getColor(key);
|
|
|
|
}
|
2017-03-31 01:58:05 +02:00
|
|
|
}
|