@@ -13,6 +13,7 @@ import android.text.Spannable
1313import android.util.AttributeSet
1414import android.util.Log
1515import android.util.TypedValue
16+ import android.view.Gravity
1617import android.view.MotionEvent
1718import android.view.inputmethod.InputMethodManager
1819import androidx.appcompat.widget.AppCompatEditText
@@ -92,8 +93,8 @@ class ReactNativeRichTextEditorView : AppCompatEditText {
9293 isSingleLine = false
9394 isHorizontalScrollBarEnabled = false
9495 isVerticalScrollBarEnabled = true
95- gravity = android.view. Gravity .TOP or android.view. Gravity .START
96- inputType = android.text. InputType .TYPE_CLASS_TEXT or android.text. InputType .TYPE_TEXT_FLAG_MULTI_LINE
96+ gravity = Gravity .TOP or Gravity .START
97+ inputType = InputType .TYPE_CLASS_TEXT or InputType .TYPE_TEXT_FLAG_MULTI_LINE
9798
9899 setPadding(0 , 0 , 0 , 0 )
99100 setBackgroundColor(Color .TRANSPARENT )
@@ -364,10 +365,56 @@ class ReactNativeRichTextEditorView : AppCompatEditText {
364365 layoutManager.invalidateLayout(text)
365366 }
366367
368+ private fun removeStyle (name : String , start : Int , end : Int ) {
369+ when (name) {
370+ EditorSpans .BOLD -> inlineStyles?.removeStyle(EditorSpans .BOLD , start, end)
371+ EditorSpans .ITALIC -> inlineStyles?.removeStyle(EditorSpans .ITALIC , start, end)
372+ EditorSpans .UNDERLINE -> inlineStyles?.removeStyle(EditorSpans .UNDERLINE , start, end)
373+ EditorSpans .STRIKETHROUGH -> inlineStyles?.removeStyle(EditorSpans .STRIKETHROUGH , start, end)
374+ EditorSpans .INLINE_CODE -> inlineStyles?.removeStyle(EditorSpans .INLINE_CODE , start, end)
375+ EditorSpans .H1 -> paragraphStyles?.removeStyle(EditorSpans .H1 , start, end)
376+ EditorSpans .H2 -> paragraphStyles?.removeStyle(EditorSpans .H2 , start, end)
377+ EditorSpans .H3 -> paragraphStyles?.removeStyle(EditorSpans .H3 , start, end)
378+ EditorSpans .CODE_BLOCK -> paragraphStyles?.removeStyle(EditorSpans .CODE_BLOCK , start, end)
379+ EditorSpans .BLOCK_QUOTE -> paragraphStyles?.removeStyle(EditorSpans .BLOCK_QUOTE , start, end)
380+ EditorSpans .ORDERED_LIST -> listStyles?.removeStyle(EditorSpans .ORDERED_LIST , start, end)
381+ EditorSpans .UNORDERED_LIST -> listStyles?.removeStyle(EditorSpans .UNORDERED_LIST , start, end)
382+ EditorSpans .LINK -> parametrizedStyles?.removeStyle(EditorSpans .LINK , start, end)
383+ EditorSpans .IMAGE -> parametrizedStyles?.removeStyle(EditorSpans .IMAGE , start, end)
384+ EditorSpans .MENTION -> parametrizedStyles?.removeStyle(EditorSpans .MENTION , start, end)
385+ else -> Log .w(" ReactNativeRichTextEditorView" , " Unknown style: $name " )
386+ }
387+ }
388+
389+ private fun getTargetRange (name : String ): Pair <Int , Int > {
390+ val result = when (name) {
391+ EditorSpans .BOLD -> inlineStyles?.getStyleRange()
392+ EditorSpans .ITALIC -> inlineStyles?.getStyleRange()
393+ EditorSpans .UNDERLINE -> inlineStyles?.getStyleRange()
394+ EditorSpans .STRIKETHROUGH -> inlineStyles?.getStyleRange()
395+ EditorSpans .INLINE_CODE -> inlineStyles?.getStyleRange()
396+ EditorSpans .H1 -> paragraphStyles?.getStyleRange()
397+ EditorSpans .H2 -> paragraphStyles?.getStyleRange()
398+ EditorSpans .H3 -> paragraphStyles?.getStyleRange()
399+ EditorSpans .CODE_BLOCK -> paragraphStyles?.getStyleRange()
400+ EditorSpans .BLOCK_QUOTE -> paragraphStyles?.getStyleRange()
401+ EditorSpans .ORDERED_LIST -> listStyles?.getStyleRange()
402+ EditorSpans .UNORDERED_LIST -> listStyles?.getStyleRange()
403+ EditorSpans .LINK -> parametrizedStyles?.getStyleRange()
404+ EditorSpans .IMAGE -> parametrizedStyles?.getStyleRange()
405+ EditorSpans .MENTION -> parametrizedStyles?.getStyleRange()
406+ else -> Pair (0 , 0 )
407+ }
408+
409+ return result ? : Pair (0 , 0 )
410+ }
411+
367412 private fun verifyStyle (name : String ): Boolean {
368413 val mergingConfig = EditorSpans .mergingConfig[name] ? : return true
369414 val conflictingStyles = mergingConfig.conflictingStyles
370415 val blockingStyles = mergingConfig.blockingStyles
416+ val isEnabling = spanState?.getStart(name) == null
417+ if (! isEnabling) return true
371418
372419 for (style in blockingStyles) {
373420 if (spanState?.getStart(style) != null ) {
@@ -377,23 +424,22 @@ class ReactNativeRichTextEditorView : AppCompatEditText {
377424 }
378425
379426 for (style in conflictingStyles) {
380- if (spanState?.getStart(style) != null ) {
381- val start = selection?.start ? : 0
382- val end = selection?.end ? : 0
383- val lengthBefore = text?.length ? : 0
384-
385- toggleStyle(style)
386-
387- val lengthAfter = text?.length ? : 0
388- val charactersRemoved = lengthBefore - lengthAfter
389- val finalEnd = if (charactersRemoved > 0 && end > start) {
390- end - charactersRemoved
391- } else {
392- end
393- }
427+ val start = selection?.start ? : 0
428+ val end = selection?.end ? : 0
429+ val lengthBefore = text?.length ? : 0
394430
395- selection?.onSelection(start, finalEnd)
431+ val targetRange = getTargetRange(name)
432+ removeStyle(style, targetRange.first, targetRange.second)
433+
434+ val lengthAfter = text?.length ? : 0
435+ val charactersRemoved = lengthBefore - lengthAfter
436+ val finalEnd = if (charactersRemoved > 0 && end > start) {
437+ end - charactersRemoved
438+ } else {
439+ end
396440 }
441+
442+ selection?.onSelection(start, finalEnd)
397443 }
398444
399445 return true
0 commit comments