Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ class EnrichedTextInputView : AppCompatEditText {
get() = transactionManager.isDuringTransaction

var isRemovingMany: Boolean = false
var textVersion = 0
set(value) {
field =
if (value >= 255) {
0
} else {
value
}
}
Comment thread
IvanIhnatsiuk marked this conversation as resolved.

val blockTextEventEmitting: Boolean
get() = transactionManager.blockTextEventEmitting
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class ParagraphStyles(
for (range in paragraphRanges) {
val paragraphStart = range.first
val paragraphEnd = range.last
spannableStringBuilder.removeZWS(paragraphStart, paragraphEnd + 1)
spannableStringBuilder.removeZWS(paragraphStart, paragraphEnd)
val spans = spannableStringBuilder.getSpans(paragraphStart, paragraphEnd, clazz)
if (spans.isEmpty()) continue

Expand Down Expand Up @@ -191,10 +191,14 @@ class ParagraphStyles(
val span = createSpan(name) ?: return

if (!hasRealText) {
// Insert ZWS with paragraph style
val zeroWidthSpace = buildZWSWithSpan(span)
val zwsIndex = (pStart until pEnd).firstOrNull { ssb[it] == Strings.ZERO_WIDTH_SPACE_CHAR }

ssb.replace(pStart, pEnd, zeroWidthSpace)
if (zwsIndex != null) {
applyParagraphSpan(ssb, span, zwsIndex, zwsIndex + 1)
} else {
val zeroWidthSpace = buildZWSWithSpan(span)
ssb.insert(pStart, zeroWidthSpace)
}

view.setSelection(pStart + 1)
view.selection.validateStyles()
Expand Down Expand Up @@ -366,7 +370,6 @@ class ParagraphStyles(
private fun insertEscapingParagraph(span: EnrichedSpan?) {
val editable = view.editableText
val index = view.selection.end

val text = editable.toString()

val hasNewlineBefore = index > 0 && text[index - 1] == Strings.NEWLINE
Expand All @@ -376,32 +379,32 @@ class ParagraphStyles(
(index == 0 || hasNewlineBefore) &&
(index == text.length || hasNewlineAfter)

var insertIndex = index
val prefix = if (!isParagraphEmpty && !hasNewlineBefore) Strings.NEWLINE_STRING else ""
val suffix = if (!hasNewlineAfter) Strings.NEWLINE_STRING else ""

if (!isParagraphEmpty && !hasNewlineBefore) {
editable.insert(insertIndex, Strings.NEWLINE_STRING)
insertIndex += 1
}
val builder = SpannableStringBuilder()
builder.append(prefix)

val builder =
SpannableStringBuilder(Strings.OBJECT_REPLACEMENT_STRING).apply {
if (span != null) {
setSpan(span, 0, length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
}
val objectStartInBuilder = builder.length
builder.append(Strings.OBJECT_REPLACEMENT_STRING)

val objectStart = insertIndex
editable.insert(insertIndex, builder)
insertIndex += builder.length

if (!hasNewlineAfter) {
editable.insert(insertIndex, Strings.NEWLINE_STRING)
insertIndex += 1
if (span != null) {
builder.setSpan(
span,
objectStartInBuilder,
objectStartInBuilder + Strings.OBJECT_REPLACEMENT_STRING.length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE,
)
}

builder.append(suffix)

editable.insert(index, builder)

val objectStart = index + objectStartInBuilder
isolateNonEditableParagraph(editable, objectStart, span)

view.setSelection(insertIndex)
view.setSelection(index + builder.length)
}

private fun isolateNonEditableParagraph(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class EnrichedSelection(
) {
var start: Int = 0
var end: Int = 0
var prevText: String? = null
var prevTextVersion: Int? = null

val inlineStylesList =
EnrichedSpans.inlineSpans.map { (type, config) -> type to config } +
Expand All @@ -50,10 +50,9 @@ class EnrichedSelection(
shouldValidateStyles = true
}

val stringText = view.text.toString()

if (prevText != stringText) {
if (prevTextVersion != view.textVersion) {
shouldValidateStyles = true
prevTextVersion = view.textVersion
}

val textLength = view.text?.length ?: 0
Expand All @@ -69,7 +68,6 @@ class EnrichedSelection(

start = finalStart
end = finalEnd
prevText = stringText
validateStyles()
val (paragraphStart, paragraphEnd) = getParagraphSelection()
emitSelectionChangeEvent(view.text, finalStart, finalEnd, paragraphStart, paragraphEnd)
Expand Down Expand Up @@ -108,10 +106,12 @@ class EnrichedSelection(
view.isRemovingMany = false
}

handleParagraphStyleState()
val paragraphSelection = getParagraphSelection()

handleParagraphStyleState(paragraphSelection)

for ((style, config) in EnrichedSpans.listSpans) {
state.setStart(style, getListStyleStart(config.clazz))
state.setStart(style, getListStyleStart(config.clazz, paragraphSelection))
}

state.emitStateChangeEvent()
Expand Down Expand Up @@ -189,15 +189,14 @@ class EnrichedSelection(
return spannable.getParagraphBounds(currentStart, currentEnd)
}

private fun handleParagraphStyleState() {
private fun handleParagraphStyleState(paragraphSelection: Pair<Int, Int>) {
val spanState = view.spanState
val (start, end) = getParagraphSelection()
val (start, end) = paragraphSelection
val spannable = view.text as? Spannable ?: return

val spans =
spannable
.getSpans(start, end, EnrichedParagraphSpan::class.java)
.toList()

if (spans.isEmpty()) {
EnrichedSpans.paragraphSpans.keys.forEach {
Expand Down Expand Up @@ -226,8 +225,11 @@ class EnrichedSelection(
}
}

private fun <T> getListStyleStart(type: Class<T>): Int? {
val (start, end) = getParagraphSelection()
private fun <T> getListStyleStart(
type: Class<T>,
paragraphSelection: Pair<Int, Int>,
): Int? {
val (start, end) = paragraphSelection
val spannable = view.text as Spannable
var styleStart: Int? = null

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class EnrichedTextWatcher(
private var startCursorPosition: Int = 0
private var prevText: String? = view.text?.toString() ?: ""
private var nonEditableParagraphToRemove: EnrichedNonEditableParagraphSpan? = null
private var isApplyingInternalTextChange = false

private val inlineSpanPreserver = InlineSpanPreserver()

Expand All @@ -28,6 +29,8 @@ class EnrichedTextWatcher(
count: Int,
after: Int,
) {
if (isApplyingInternalTextChange) return

previousTextLength = s?.length ?: 0
startCursorPosition = start
nonEditableParagraphToRemove = getNonEditableParagraphBeforeDeletedRange(s, start, count, after)
Expand All @@ -49,6 +52,8 @@ class EnrichedTextWatcher(
before: Int,
count: Int,
) {
if (isApplyingInternalTextChange) return

endCursorPosition = start + count
view.isRemovingMany = !view.isDuringTransaction && before > count + 1
inlineSpanPreserver.onTextChanged(
Expand All @@ -58,18 +63,28 @@ class EnrichedTextWatcher(
}

override fun afterTextChanged(s: Editable?) {
emitEvents(s)
if (s == null) return
view.textVersion += 1

if (isApplyingInternalTextChange) return

if (s == null) {
emitEvents(null)
return
}

view.transactionManager.runWithBlockedTextEvents {
view.transactionManager.runWithIgnoredSpanWatcher {
inlineSpanPreserver.afterTextChanged()
if (!view.isDuringTransaction) {
removePendingNonEditableParagraph(s)
applyStyles(s)
runWithInternalTextChange {
removePendingNonEditableParagraph(s)
applyStyles(s)
}
}
}
}

emitEvents(s)
view.correctScrollPositionIfNeeded()
}

Expand All @@ -83,6 +98,15 @@ class EnrichedTextWatcher(
ZWSNormalizer.normalizeNonEmptyParagraphs(s)
}

private fun runWithInternalTextChange(block: () -> Unit) {
isApplyingInternalTextChange = true
try {
block()
} finally {
isApplyingInternalTextChange = false
}
}

private fun getNonEditableParagraphBeforeDeletedRange(
text: CharSequence?,
start: Int,
Expand Down Expand Up @@ -129,6 +153,11 @@ class EnrichedTextWatcher(
}

private fun emitEvents(s: Editable?) {
if (!view.shouldEmitOnChangeText) {
view.emitOnAnyContentChangeEvent()
return
}

val nextText = s?.toString() ?: ""
if (prevText != nextText) {
prevText = nextText
Expand Down