From 3bc5dd8b187afdd0422640e9c9e409ee50c8923e Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Wed, 6 Sep 2023 16:41:58 -0500 Subject: [PATCH] Allow backspacing into custom emoji When the platform wants to backspace into an imagespan, remove the span. Some platforms remove the whole span when you backspace, some don't, this at least makes it not weird on those that do not. --- .../conversations/ui/widget/EditMessage.java | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/ui/widget/EditMessage.java b/src/main/java/eu/siacs/conversations/ui/widget/EditMessage.java index bcacb3341..daa6ec4d7 100644 --- a/src/main/java/eu/siacs/conversations/ui/widget/EditMessage.java +++ b/src/main/java/eu/siacs/conversations/ui/widget/EditMessage.java @@ -9,7 +9,11 @@ import android.preference.PreferenceManager; import android.text.Editable; import android.text.InputFilter; import android.text.InputType; +import android.text.Spannable; import android.text.Spanned; +import android.text.SpannableStringBuilder; +import android.text.TextWatcher; +import android.text.style.ImageSpan; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.inputmethod.EditorInfo; @@ -20,6 +24,8 @@ import androidx.core.view.inputmethod.EditorInfoCompat; import androidx.core.view.inputmethod.InputConnectionCompat; import androidx.core.view.inputmethod.InputContentInfoCompat; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -49,10 +55,12 @@ public class EditMessage extends AppCompatEditText { public EditMessage(Context context, AttributeSet attrs) { super(context, attrs); + addTextChangedListener(new Watcher()); } public EditMessage(Context context) { super(context); + addTextChangedListener(new Watcher()); } @Override @@ -79,7 +87,6 @@ public class EditMessage extends AppCompatEditText { return AUTOFILL_TYPE_NONE; } - @Override public void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { super.onTextChanged(text, start, lengthBefore, lengthAfter); @@ -206,4 +213,47 @@ public class EditMessage extends AppCompatEditText { boolean onTabPressed(boolean repeated); } + + public static class Watcher implements TextWatcher { + protected List spansToRemove = new ArrayList<>(); + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (s instanceof SpannableStringBuilder && ((SpannableStringBuilder) s).getTextWatcherDepth() > 1) return; + } + + if (!(s instanceof Spannable)) return; + Spannable text = (Spannable) s; + + if (count > 0 && text != null) { // something deleted + int end = start + count; + ImageSpan[] spans = text.getSpans(start, end, ImageSpan.class); + synchronized(spansToRemove) { + for (ImageSpan span : spans) { + if (text.getSpanStart(span) < end && start < text.getSpanEnd(span)) { + spansToRemove.add(span); + } + } + } + } + } + + @Override + public void afterTextChanged(Editable s) { + List toRemove; + synchronized(spansToRemove) { + toRemove = new ArrayList<>(spansToRemove); + spansToRemove.clear(); + } + for (ImageSpan span : toRemove) { + if (s.getSpanStart(span) > -1 && s.getSpanEnd(span) > -1) { + s.removeSpan(span); + } + } + } + + @Override + public void onTextChanged(CharSequence s, int start, int count, int after) { } + } } -- 2.45.2