Skip to content

Commit c0399f8

Browse files
authored
fix: mentions detection - android (#200)
Fixes: #199
1 parent 1ae5278 commit c0399f8

6 files changed

Lines changed: 27 additions & 9 deletions

File tree

android/src/main/java/com/swmansion/enriched/EnrichedTextInputView.kt

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ class EnrichedTextInputView : AppCompatEditText {
5151
val paragraphStyles: ParagraphStyles? = ParagraphStyles(this)
5252
val listStyles: ListStyles? = ListStyles(this)
5353
val parametrizedStyles: ParametrizedStyles? = ParametrizedStyles(this)
54-
var isSettingValue: Boolean = false
54+
// Sometimes setting up style triggers many changes in sequence
55+
// Eg. removing conflicting styles -> changing text -> applying spans
56+
// In such scenario we want to prevent from handling side effects (eg. onTextChanged)
57+
var isDuringTransaction: Boolean = false
5558
var isRemovingMany: Boolean = false
5659

5760
val mentionHandler: MentionHandler? = MentionHandler(this)
@@ -233,7 +236,7 @@ class EnrichedTextInputView : AppCompatEditText {
233236

234237
fun setValue(value: CharSequence?) {
235238
if (value == null) return
236-
isSettingValue = true
239+
isDuringTransaction = true
237240

238241
val newText = parseText(value)
239242
setText(newText)
@@ -244,7 +247,7 @@ class EnrichedTextInputView : AppCompatEditText {
244247
// Scroll to the last line of text
245248
setSelection(text?.length ?: 0)
246249

247-
isSettingValue = false
250+
isDuringTransaction = false
248251
}
249252

250253
fun setAutoFocus(autoFocus: Boolean) {
@@ -452,13 +455,13 @@ class EnrichedTextInputView : AppCompatEditText {
452455
val end = selection?.end ?: 0
453456
val lengthBefore = text?.length ?: 0
454457

455-
isSettingValue = true
458+
isDuringTransaction = true
456459
val targetRange = getTargetRange(name)
457460
val removed = removeStyle(style, targetRange.first, targetRange.second)
458461
if (removed) {
459462
spanState?.setStart(style, null)
460463
}
461-
isSettingValue = false
464+
isDuringTransaction = false
462465

463466
val lengthAfter = text?.length ?: 0
464467
val charactersRemoved = lengthBefore - lengthAfter

android/src/main/java/com/swmansion/enriched/events/MentionHandler.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ class MentionHandler(private val view: EnrichedTextInputView) {
88
private var previousText: String? = null
99
private var previousIndicator: String? = null
1010

11+
fun reset() {
12+
previousText = null
13+
previousIndicator = null
14+
}
15+
1116
fun endMention() {
1217
val indicator = previousIndicator
1318
if (indicator == null) return

android/src/main/java/com/swmansion/enriched/styles/ParametrizedStyles.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ class ParametrizedStyles(private val view: EnrichedTextInputView) {
201201
}
202202

203203
val start = mentionStart ?: return
204+
view.isDuringTransaction = true
204205
spannable.replace(start, selectionEnd, text)
205206

206207
val span = EnrichedMentionSpan(text, indicator, attributes, view.htmlStyle)
@@ -213,6 +214,8 @@ class ParametrizedStyles(private val view: EnrichedTextInputView) {
213214
spannable.insert(safeEnd, " ")
214215
}
215216

217+
view.isDuringTransaction = false
218+
view.mentionHandler?.reset()
216219
view.selection.validateStyles()
217220
}
218221

android/src/main/java/com/swmansion/enriched/utils/EnrichedSelection.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class EnrichedSelection(private val view: EnrichedTextInputView) {
3939
val finalStart = newStart.coerceAtMost(newEnd).coerceAtLeast(0).coerceAtMost(textLength)
4040
val finalEnd = newEnd.coerceAtLeast(newStart).coerceAtLeast(0).coerceAtMost(textLength)
4141

42-
if (isZeroWidthSelection(finalStart, finalEnd) && !view.isSettingValue) {
42+
if (isZeroWidthSelection(finalStart, finalEnd) && !view.isDuringTransaction) {
4343
view.setSelection(finalStart + 1)
4444
shouldValidateStyles = false
4545
}

android/src/main/java/com/swmansion/enriched/watchers/EnrichedTextWatcher.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ class EnrichedTextWatcher(private val view: EnrichedTextInputView) : TextWatcher
1818
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
1919
endCursorPosition = start + count
2020
view.layoutManager.measureSize(s ?: "")
21-
view.isRemovingMany = !view.isSettingValue && before > count + 1
21+
view.isRemovingMany = !view.isDuringTransaction && before > count + 1
2222
}
2323

2424
override fun afterTextChanged(s: Editable?) {
2525
if (s == null) return
2626
emitEvents(s)
2727

28-
if (view.isSettingValue) return
28+
if (view.isDuringTransaction) return
2929
applyStyles(s)
3030
}
3131

example/src/App.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,14 @@ export default function App() {
149149
};
150150

151151
const handleStartMention = (indicator: string) => {
152-
indicator === '@' ? openUserMentionPopup() : openChannelMentionPopup();
152+
if (indicator === '@') {
153+
userMention.onMentionChange('');
154+
openUserMentionPopup();
155+
return;
156+
}
157+
158+
channelMention.onMentionChange('');
159+
openChannelMentionPopup();
153160
};
154161

155162
const handleEndMention = (indicator: string) => {

0 commit comments

Comments
 (0)