diff --git a/editor/src/main/java/com/canopas/editor/ui/data/QuillTextManager.kt b/editor/src/main/java/com/canopas/editor/ui/data/QuillTextManager.kt index dd09aae..d1e0b32 100644 --- a/editor/src/main/java/com/canopas/editor/ui/data/QuillTextManager.kt +++ b/editor/src/main/java/com/canopas/editor/ui/data/QuillTextManager.kt @@ -29,50 +29,25 @@ class QuillTextManager(quillSpan: QuillSpan) { val fromIndex = editableText.indexOf(span.insert ?: "", startIndex = startIndex) val endIndex = fromIndex + (span.insert?.length ?: 0) - 1 - attributes?.let { - val textSpanStyles = mutableListOf() - - if (it.header != null) { - when (it.header) { - 1 -> TextSpanStyle.H1Style - 2 -> TextSpanStyle.H2Style - 3 -> TextSpanStyle.H3Style - 4 -> TextSpanStyle.H4Style - 5 -> TextSpanStyle.H5Style - 6 -> TextSpanStyle.H6Style - else -> null - }?.let { headerStyle -> textSpanStyles.add(headerStyle) } - } - - if (it.bold == true) { - textSpanStyles.add(TextSpanStyle.BoldStyle) - } - - if (it.italic == true) { - textSpanStyles.add(TextSpanStyle.ItalicStyle) - } - - if (it.underline == true) { - textSpanStyles.add(TextSpanStyle.UnderlineStyle) - } - - if (it.list == ListType.bullet) { - textSpanStyles.add(TextSpanStyle.BulletStyle) + val textSpanStyles = attributes?.let { attrs -> + mutableListOf().apply { + attrs.header?.let { header -> + TextSpanStyle.HeaderMap.headerMap["$header"]?.let { add(it) } + } + if (attrs.bold == true) add(TextSpanStyle.BoldStyle) + if (attrs.italic == true) add(TextSpanStyle.ItalicStyle) + if (attrs.underline == true) add(TextSpanStyle.UnderlineStyle) + if (attrs.list == ListType.bullet) add(TextSpanStyle.BulletStyle) } + } ?: mutableListOf(TextSpanStyle.Default) - quillTextSpans.add( - QuillTextSpan(from = fromIndex, to = endIndex, style = textSpanStyles) + quillTextSpans.add( + QuillTextSpan( + from = fromIndex, + to = endIndex, + style = textSpanStyles ) - } - ?: run { - quillTextSpans.add( - QuillTextSpan( - from = fromIndex, - to = endIndex, - style = listOf(TextSpanStyle.Default) - ) - ) - } + ) } } @@ -95,37 +70,39 @@ class QuillTextManager(quillSpan: QuillSpan) { editable.removeSpans() editable.removeSpans() - quillTextSpans.forEach { - it.style.forEach { style -> - editable.setSpan( - style.style, - it.from, - it.to + 1, - Spannable.SPAN_INCLUSIVE_EXCLUSIVE - ) + try { + quillTextSpans.forEach { + it.style.forEach { style -> + editable.setSpan( + style.style, + it.from, + it.to + 1, + Spannable.SPAN_INCLUSIVE_EXCLUSIVE + ) + } } + } catch (e: Exception) { + e.printStackTrace() } updateCurrentSpanStyle() } private fun updateCurrentSpanStyle() { - if (this.selection.collapsed && this.selection.min == 0) return - this.currentStyles.clear() + if (selection.collapsed && selection.min == 0) return + currentStyles.clear() - val currentStyles = - if (selection.collapsed) { - getRichSpanByTextIndex(textIndex = selection.min - 1) - } else { - getRichSpanListByTextRange(selection).distinct() - } + val currentStyles = if (selection.collapsed) { + getRichSpanByTextIndex(textIndex = selection.min - 1) + } else { + getRichSpanListByTextRange(selection).distinct() + } - val currentSpan = - quillTextSpans.findLast { - it.from <= selection.min - 2 && - it.to >= selection.min - 2 && - it.style.contains(TextSpanStyle.BulletStyle) - } + val currentSpan = quillTextSpans.findLast { + it.from <= selection.min - 2 && it.to >= selection.min - 2 && it.style.contains( + TextSpanStyle.BulletStyle + ) + } if (currentSpan != null && this.selection.collapsed) { if (editable[selection.min - 1] == '\n' && editable[selection.min - 2] == '\n') { @@ -176,116 +153,83 @@ class QuillTextManager(quillSpan: QuillSpan) { val fromIndex = selection.min val toIndex = selection.max - 1 - val selectedSpan = quillTextSpans.find { it.from <= fromIndex && it.to >= toIndex } - selectedSpan?.let { - val index = quillTextSpans.indexOf(it) - val updatedStyle = it.style.filterNot { it == style } + quillTextSpans.firstOrNull { it.from <= fromIndex && it.to >= toIndex } + ?.let { selectedSpan -> + val index = quillTextSpans.indexOf(selectedSpan) + val updatedStyle = selectedSpan.style.filterNot { it == style } + val newSpans = mutableListOf() - val newSpans = mutableListOf() - - when { - fromIndex == it.from && toIndex == it.to -> { - quillTextSpans[index] = it.copy(style = updatedStyle) - } + when { + fromIndex == selectedSpan.from && toIndex == selectedSpan.to -> { + quillTextSpans[index] = selectedSpan.copy(style = updatedStyle) + } - fromIndex == it.from && toIndex < it.to -> { - newSpans.add( - QuillTextSpan( - from = fromIndex, - to = toIndex, - style = updatedStyle - ) - ) - newSpans.add( - QuillTextSpan( - from = toIndex + 1, - to = it.to, - style = it.style + fromIndex == selectedSpan.from && toIndex < selectedSpan.to -> { + newSpans.add(QuillTextSpan(fromIndex, toIndex, updatedStyle)) + newSpans.add( + QuillTextSpan( + toIndex + 1, + selectedSpan.to, + selectedSpan.style + ) ) - ) - quillTextSpans.removeAt(index) - quillTextSpans.addAll(index, newSpans) - } + quillTextSpans.removeAt(index) + quillTextSpans.addAll(index, newSpans) + } - fromIndex > it.from -> { - newSpans.add( - QuillTextSpan( - from = it.from, - to = fromIndex - 1, - style = it.style - ) - ) - newSpans.add( - QuillTextSpan( - from = fromIndex, - to = toIndex, - style = updatedStyle + fromIndex > selectedSpan.from -> { + newSpans.add( + QuillTextSpan( + selectedSpan.from, + fromIndex - 1, + selectedSpan.style + ) ) - ) - newSpans.add( - QuillTextSpan( - from = toIndex + 1, - to = it.to, - style = it.style + newSpans.add(QuillTextSpan(fromIndex, toIndex, updatedStyle)) + newSpans.add( + QuillTextSpan( + toIndex + 1, + selectedSpan.to, + selectedSpan.style + ) ) - ) - quillTextSpans.removeAt(index) - quillTextSpans.addAll(index, newSpans) - } + quillTextSpans.removeAt(index) + quillTextSpans.addAll(index, newSpans) + } - else -> {} + else -> {} + } } - } updateText() } } private fun addStyle(style: TextSpanStyle) { - if (selection.min > 0) { - when { - !currentStyles.contains(style) -> { - when (style) { - TextSpanStyle.BulletStyle -> { - when { - editable[selection.min - 1] == '\n' && selection.collapsed -> currentStyles.add( - style - ) - - editable[selection.min - 1] == '\n' && !selection.collapsed -> currentStyles.add( - style - ) - } - } - - else -> currentStyles.add(style) - } - - when { - style == TextSpanStyle.BulletStyle && selection.collapsed && editable[selection.min - 1] == '\n' -> editable.insert( - selection.min, - "\u200B" - ) + when { + selection.min > 0 -> { + if (style != TextSpanStyle.BulletStyle || editable[selection.min - 1] == '\n') { + currentStyles.add(style) + if (style == TextSpanStyle.BulletStyle && selection.collapsed) { + editable.insert(selection.min, "\u200B") } } } - } else { - if (!currentStyles.contains(style)) { + + selection.min == 0 && style == TextSpanStyle.BulletStyle && selection.collapsed -> { currentStyles.add(style) + editable.insert(selection.min, "\u200B") } + + !currentStyles.contains(style) -> currentStyles.add(style) } - when { - (style.isHeaderStyle() || style.isDefault()) && selection.collapsed -> handleAddHeaderStyle( - style - ) + if ((style.isHeaderStyle() || style.isDefault()) && selection.collapsed) { + handleAddHeaderStyle(style) } - if (!selection.collapsed && selection.min > 0) { - when { - editable[selection.min - 1] != '\n' && style == TextSpanStyle.BulletStyle -> return - else -> applyStylesToSelectedText(style) - } - } else { + if (!selection.collapsed || selection.min <= 0 || + (style != TextSpanStyle.BulletStyle || editable[selection.min - 1] == '\n') + ) { applyStylesToSelectedText(style) } } @@ -312,21 +256,16 @@ class QuillTextManager(quillSpan: QuillSpan) { val startIndex: Int = max(0, text.lastIndexOf("\n", fromIndex - 1)) var endIndex: Int = text.indexOf("\n", toIndex) - if (endIndex == -1) endIndex = text.length - 1 val nextNewlineIndex = text.lastIndexOf("\n", startIndex) - val parts = - quillTextSpans.filter { part -> part.from < nextNewlineIndex && part.to >= startIndex } - if (parts.isEmpty() && fromIndex - 1 == nextNewlineIndex) return + if (quillTextSpans.none { it.from < nextNewlineIndex && it.to >= startIndex && it.style.any { it.isHeaderStyle() } }) return - val selectedParts = - quillTextSpans.filter { part -> part.from < endIndex && part.to >= startIndex } - - quillTextSpans.removeAll( - selectedParts.filter { it.style.size == 1 && it.style.first().isHeaderStyle() } - ) + quillTextSpans.removeAll { + it.from < endIndex && it.to >= startIndex && it.style.size == 1 && it.style.first() + .isHeaderStyle() + } } private fun applyStylesToSelectedText(style: TextSpanStyle) { @@ -336,77 +275,70 @@ class QuillTextManager(quillSpan: QuillSpan) { val toIndex = selection.max val selectedSpan = quillTextSpans.find { it.from <= fromIndex && (it.to + 1) >= toIndex } - if (selectedSpan != null) { - if (fromIndex == selectedSpan.from && toIndex < selectedSpan.to) { - val index = quillTextSpans.indexOf(selectedSpan) - quillTextSpans.removeAt(index) - quillTextSpans.add( - index, - QuillTextSpan( + val index = quillTextSpans.indexOf(selectedSpan) + + when { + selectedSpan != null -> { + if (fromIndex == selectedSpan.from && toIndex < selectedSpan.to) { + val newSpan = QuillTextSpan( from = fromIndex, to = toIndex - 1, style = selectedSpan.style + listOf(style) ) - ) - quillTextSpans.add( - index + 1, - QuillTextSpan(from = toIndex, to = selectedSpan.to, style = selectedSpan.style) - ) - } else if (fromIndex > selectedSpan.from && toIndex < selectedSpan.to) { - val index = quillTextSpans.indexOf(selectedSpan) - quillTextSpans.removeAt(index) - quillTextSpans.add( - index, - QuillTextSpan( + val nextSpan = QuillTextSpan( + from = toIndex, + to = selectedSpan.to, + style = selectedSpan.style + ) + quillTextSpans[index] = newSpan + quillTextSpans.add(index + 1, nextSpan) + } else if (fromIndex > selectedSpan.from && toIndex < selectedSpan.to) { + val previousSpan = QuillTextSpan( from = selectedSpan.from, to = fromIndex - 1, style = selectedSpan.style ) - ) - quillTextSpans.add( - index + 1, - QuillTextSpan( + val newSpan = QuillTextSpan( from = fromIndex, to = toIndex - 1, style = selectedSpan.style + listOf(style) ) - ) - quillTextSpans.add( - index + 2, - QuillTextSpan(from = toIndex, to = selectedSpan.to, style = selectedSpan.style) - ) - } else if ( - fromIndex > selectedSpan.from && - (toIndex == selectedSpan.to || toIndex == (selectedSpan.to + 1)) - ) { - val index = quillTextSpans.indexOf(selectedSpan) - quillTextSpans.removeAt(index) - quillTextSpans.add( - index, - QuillTextSpan( + val nextSpan = QuillTextSpan( + from = toIndex, + to = selectedSpan.to, + style = selectedSpan.style + ) + quillTextSpans[index] = previousSpan + quillTextSpans.add(index + 1, newSpan) + quillTextSpans.add(index + 2, nextSpan) + } else if (fromIndex > selectedSpan.from && (toIndex == selectedSpan.to || toIndex == (selectedSpan.to + 1))) { + val previousSpan = QuillTextSpan( from = selectedSpan.from, to = fromIndex - 1, style = selectedSpan.style ) - ) - quillTextSpans.add( - index + 1, - QuillTextSpan( + val newSpan = QuillTextSpan( from = fromIndex, to = toIndex - 1, style = selectedSpan.style + listOf(style) ) - ) - } else { - val index = quillTextSpans.indexOf(selectedSpan) - quillTextSpans[index] = - selectedSpan.copy(style = selectedSpan.style + listOf(style)) + quillTextSpans[index] = previousSpan + quillTextSpans.add(index + 1, newSpan) + } else { + quillTextSpans[index] = + selectedSpan.copy(style = selectedSpan.style + listOf(style)) + } } - } else { - quillTextSpans.add( - QuillTextSpan(from = fromIndex, to = toIndex - 1, style = listOf(style)) + + else -> quillTextSpans.add( + QuillTextSpan( + from = fromIndex, + to = toIndex - 1, + style = listOf(style) + ) ) } + updateText() } @@ -436,14 +368,11 @@ class QuillTextManager(quillSpan: QuillSpan) { val typedCharsCount = newValue.length - rawText.length val startTypeIndex = selection.min - typedCharsCount - if ( - newValue.getOrNull(startTypeIndex) == '\n' && currentStyles.any { it.isHeaderStyle() } - ) { + if (newValue.getOrNull(startTypeIndex) == '\n' && currentStyles.any { it.isHeaderStyle() }) { currentStyles.clear() } val selectedStyles = currentStyles.distinct() - moveSpans(startTypeIndex, typedCharsCount) val currentSpan = @@ -458,11 +387,11 @@ class QuillTextManager(quillSpan: QuillSpan) { when { span.style == selectedStyles -> { - if (isBulletStyle && newValue[startTypeIndex] == '\n') { - if (newValue[startTypeIndex - 1] != '\n') { + if (isBulletStyle && newValue.getOrNull(startTypeIndex) == '\n') { + if (newValue.getOrNull(startTypeIndex - 1) != '\n') { quillTextSpans.add( index + 1, - QuillTextSpan( + span.copy( from = startTypeIndex, to = startTypeIndex + typedCharsCount - 1, style = selectedStyles @@ -470,73 +399,45 @@ class QuillTextManager(quillSpan: QuillSpan) { ) quillTextSpans.add( index + 2, - QuillTextSpan( + span.copy( from = startTypeIndex + typedCharsCount, - to = startTypeIndex + typedCharsCount, + to = to + typedCharsCount, style = selectedStyles ) ) } else { - quillTextSpans[index - 1] = - span.copy( - to = to + typedCharsCount, - style = - selectedStyles.filterNot { it == TextSpanStyle.BulletStyle } - ) - quillTextSpans[index] = - span.copy( - to = to + typedCharsCount, - style = - selectedStyles.filterNot { it == TextSpanStyle.BulletStyle } - ) + val updatedSpan = span.copy(to = to + typedCharsCount, + style = selectedStyles.filterNot { it == TextSpanStyle.BulletStyle } + ) + quillTextSpans[index - 1] = updatedSpan + quillTextSpans[index] = updatedSpan } } else { - val updatedSpan = span.copy(to = to + typedCharsCount, style = styles) - quillTextSpans[index] = updatedSpan + quillTextSpans[index] = span.copy(to = to + typedCharsCount, style = styles) } } span.style != selectedStyles -> { quillTextSpans.removeAt(index) - if (startTypeIndex == from) { - quillTextSpans.add( - index, - span.copy( - from = startTypeIndex, - to = startTypeIndex + typedCharsCount - 1, - style = styles - ) - ) - quillTextSpans.add( - index + 1, - span.copy( - from = startTypeIndex + typedCharsCount, - to = to + typedCharsCount, - style = styles - ) - ) - } else { - quillTextSpans.add( - index, - span.copy(to = startTypeIndex - 1, style = span.style) - ) - quillTextSpans.add( - index + 1, - span.copy( - from = startTypeIndex, - to = startTypeIndex + typedCharsCount, - style = selectedStyles - ) + val newSpans = mutableListOf() + if (startTypeIndex != from) { + newSpans.add(span.copy(to = startTypeIndex - 1)) + } + newSpans.add( + span.copy( + from = startTypeIndex, + to = startTypeIndex + typedCharsCount - 1, + style = selectedStyles ) - quillTextSpans.add( - index + 2, - span.copy( - from = startTypeIndex + typedCharsCount + 1, - to = to + typedCharsCount, - style = span.style - ) + ) + newSpans.add( + span.copy( + from = startTypeIndex + typedCharsCount, + to = to + typedCharsCount, + style = styles ) - } + ) + quillTextSpans.addAll(index, newSpans) } startTypeIndex == from && to == startTypeIndex -> { @@ -562,53 +463,35 @@ class QuillTextManager(quillSpan: QuillSpan) { } startTypeIndex in (from + 1) until to -> { - quillTextSpans.removeAt(index) - quillTextSpans.add(index, span.copy(to = startTypeIndex - 1, style = styles)) - quillTextSpans.add( - index + 1, + val newSpans = mutableListOf() + newSpans.add(span.copy(to = startTypeIndex - 1, style = styles)) + newSpans.add( span.copy( from = startTypeIndex, to = startTypeIndex + typedCharsCount - 1, style = selectedStyles ) ) - quillTextSpans.add( - index + 2, + newSpans.add( span.copy( from = startTypeIndex + typedCharsCount, to = to + typedCharsCount, style = styles ) ) + quillTextSpans.removeAt(index) + quillTextSpans.addAll(index, newSpans) } + + else -> {} } - } - if (currentSpan == null) { - val lastSpan = quillTextSpans.lastOrNull() - if (lastSpan != null) { - val lastStyles = lastSpan.style - if (lastStyles == selectedStyles) { - quillTextSpans[quillTextSpans.lastIndex] = - lastSpan.copy(to = lastSpan.to + typedCharsCount) - } else { - quillTextSpans.add( - QuillTextSpan( - from = startTypeIndex, - to = startTypeIndex + typedCharsCount - 1, - style = selectedStyles - ) - ) - } - } else { - quillTextSpans.add( - QuillTextSpan( - from = startTypeIndex, - to = startTypeIndex + typedCharsCount - 1, - style = selectedStyles - ) - ) - } - } + } ?: quillTextSpans.add( + QuillTextSpan( + from = startTypeIndex, + to = startTypeIndex + typedCharsCount - 1, + style = selectedStyles + ) + ) } private fun moveSpans(startTypeIndex: Int, by: Int) { diff --git a/editor/src/main/java/com/canopas/editor/ui/utils/ElementsSpanStyle.kt b/editor/src/main/java/com/canopas/editor/ui/utils/ElementsSpanStyle.kt index 3517f31..de89ea8 100644 --- a/editor/src/main/java/com/canopas/editor/ui/utils/ElementsSpanStyle.kt +++ b/editor/src/main/java/com/canopas/editor/ui/utils/ElementsSpanStyle.kt @@ -161,4 +161,15 @@ sealed interface TextSpanStyle { return key == other.key } } + + object HeaderMap { + internal val headerMap = mapOf( + "1" to H1Style, + "2" to H2Style, + "3" to H3Style, + "4" to H4Style, + "5" to H5Style, + "6" to H6Style + ) + } } \ No newline at end of file