That fuck shit the fascists are using
1package org.tm.archive.components
2
3import android.text.Annotation
4import android.text.Editable
5import android.text.Spannable
6import android.text.Spanned
7import android.text.TextUtils
8import android.text.TextWatcher
9import org.signal.core.util.StringUtil
10import org.tm.archive.conversation.MessageStyler
11import org.tm.archive.conversation.MessageStyler.isSupportedStyle
12
13/**
14 * Formatting should only grow when appending until a white space character is entered/pasted.
15 *
16 * This watcher observes changes to the text and will shrink supported style ranges as necessary
17 * to provide the desired behavior.
18 */
19class ComposeTextStyleWatcher : TextWatcher {
20 private val markerAnnotation = Annotation("text-formatting", "marker")
21 private var textSnapshotPriorToChange: CharSequence? = null
22
23 override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
24 if (s is Spannable) {
25 s.removeSpan(markerAnnotation)
26 }
27
28 textSnapshotPriorToChange = s.subSequence(start, start + count)
29 }
30
31 override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
32 if (s is Spannable) {
33 s.removeSpan(markerAnnotation)
34
35 if (count > 0) {
36 s.setSpan(markerAnnotation, start, start + count, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
37 }
38 }
39 }
40
41 override fun afterTextChanged(s: Editable) {
42 val editStart = s.getSpanStart(markerAnnotation)
43 val editEnd = s.getSpanEnd(markerAnnotation)
44
45 s.removeSpan(markerAnnotation)
46
47 try {
48 if (editStart < 0 || editEnd < 0 || editStart >= editEnd || (editStart == 0 && editEnd == s.length)) {
49 textSnapshotPriorToChange = null
50 return
51 }
52
53 val change = s.subSequence(editStart, editEnd)
54 if (change.isEmpty() ||
55 textSnapshotPriorToChange == null ||
56 (editEnd - editStart == 1 && !StringUtil.isVisuallyEmpty(change[0])) ||
57 TextUtils.equals(textSnapshotPriorToChange, change) ||
58 editEnd - editStart > 1
59 ) {
60 textSnapshotPriorToChange = null
61 return
62 }
63 textSnapshotPriorToChange = null
64
65 var newEnd = editStart
66 for (i in change.indices) {
67 if (StringUtil.isVisuallyEmpty(change[i])) {
68 newEnd = editStart + i
69 break
70 }
71 }
72
73 s.getSpans(editStart, editEnd, Object::class.java)
74 .filter { it.isSupportedStyle() }
75 .forEach { style ->
76 val styleStart = s.getSpanStart(style)
77 val styleEnd = s.getSpanEnd(style)
78
79 if (styleEnd == editEnd && styleStart < styleEnd) {
80 s.removeSpan(style)
81 s.setSpan(style, styleStart, newEnd, MessageStyler.SPAN_FLAGS)
82 } else if (styleStart >= styleEnd) {
83 s.removeSpan(style)
84 }
85 }
86 } finally {
87 s.getSpans(editStart, editEnd, Object::class.java)
88 .filter { it.isSupportedStyle() }
89 .forEach { style ->
90 val styleStart = s.getSpanStart(style)
91 val styleEnd = s.getSpanEnd(style)
92 if (styleEnd == styleStart || styleStart > styleEnd) {
93 s.removeSpan(style)
94 }
95 }
96 }
97 }
98}