react-native-enriched 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/README.md +15 -12
  2. package/android/build.gradle +77 -72
  3. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerDelegate.java +18 -0
  4. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerInterface.java +6 -0
  5. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/EventEmitters.cpp +146 -0
  6. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/EventEmitters.h +140 -0
  7. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/Props.cpp +10 -0
  8. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/Props.h +194 -0
  9. package/android/lint.gradle +70 -0
  10. package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputConnectionWrapper.kt +140 -0
  11. package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputView.kt +245 -116
  12. package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewLayoutManager.kt +3 -1
  13. package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt +162 -53
  14. package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewPackage.kt +1 -3
  15. package/android/src/main/java/com/swmansion/enriched/MeasurementStore.kt +70 -21
  16. package/android/src/main/java/com/swmansion/enriched/events/MentionHandler.kt +20 -10
  17. package/android/src/main/java/com/swmansion/enriched/events/OnChangeHtmlEvent.kt +8 -9
  18. package/android/src/main/java/com/swmansion/enriched/events/OnChangeSelectionEvent.kt +10 -9
  19. package/android/src/main/java/com/swmansion/enriched/events/OnChangeStateDeprecatedEvent.kt +21 -0
  20. package/android/src/main/java/com/swmansion/enriched/events/OnChangeStateEvent.kt +9 -12
  21. package/android/src/main/java/com/swmansion/enriched/events/OnChangeTextEvent.kt +10 -10
  22. package/android/src/main/java/com/swmansion/enriched/events/OnInputBlurEvent.kt +7 -9
  23. package/android/src/main/java/com/swmansion/enriched/events/OnInputFocusEvent.kt +7 -9
  24. package/android/src/main/java/com/swmansion/enriched/events/OnInputKeyPressEvent.kt +27 -0
  25. package/android/src/main/java/com/swmansion/enriched/events/OnLinkDetectedEvent.kt +13 -11
  26. package/android/src/main/java/com/swmansion/enriched/events/OnMentionDetectedEvent.kt +10 -9
  27. package/android/src/main/java/com/swmansion/enriched/events/OnMentionEvent.kt +9 -8
  28. package/android/src/main/java/com/swmansion/enriched/events/OnRequestHtmlResultEvent.kt +1 -2
  29. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedBlockQuoteSpan.kt +21 -8
  30. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedBoldSpan.kt +5 -4
  31. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedCodeBlockSpan.kt +7 -5
  32. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH1Span.kt +5 -4
  33. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH2Span.kt +5 -4
  34. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH3Span.kt +5 -4
  35. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH4Span.kt +24 -0
  36. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH5Span.kt +24 -0
  37. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH6Span.kt +24 -0
  38. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedImageSpan.kt +29 -17
  39. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedInlineCodeSpan.kt +5 -4
  40. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedItalicSpan.kt +5 -4
  41. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedLinkSpan.kt +7 -7
  42. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedMentionSpan.kt +11 -14
  43. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedOrderedListSpan.kt +15 -14
  44. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedSpans.kt +167 -71
  45. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedStrikeThroughSpan.kt +5 -4
  46. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedUnderlineSpan.kt +5 -4
  47. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedUnorderedListSpan.kt +8 -8
  48. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedBlockSpan.kt +3 -2
  49. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedHeadingSpan.kt +1 -2
  50. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedInlineSpan.kt +1 -2
  51. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedParagraphSpan.kt +3 -2
  52. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedSpan.kt +1 -0
  53. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedZeroWidthSpaceSpan.kt +1 -2
  54. package/android/src/main/java/com/swmansion/enriched/spans/utils/ForceRedrawSpan.kt +2 -1
  55. package/android/src/main/java/com/swmansion/enriched/styles/HtmlStyle.kt +78 -21
  56. package/android/src/main/java/com/swmansion/enriched/styles/InlineStyles.kt +25 -8
  57. package/android/src/main/java/com/swmansion/enriched/styles/ListStyles.kt +60 -20
  58. package/android/src/main/java/com/swmansion/enriched/styles/ParagraphStyles.kt +86 -26
  59. package/android/src/main/java/com/swmansion/enriched/styles/ParametrizedStyles.kt +128 -52
  60. package/android/src/main/java/com/swmansion/enriched/utils/AsyncDrawable.kt +10 -7
  61. package/android/src/main/java/com/swmansion/enriched/utils/EnrichedConstants.kt +11 -0
  62. package/android/src/main/java/com/swmansion/enriched/utils/EnrichedEditableFactory.kt +17 -0
  63. package/android/src/main/java/com/swmansion/enriched/utils/EnrichedParser.java +128 -87
  64. package/android/src/main/java/com/swmansion/enriched/utils/EnrichedSelection.kt +71 -42
  65. package/android/src/main/java/com/swmansion/enriched/utils/EnrichedSpanState.kt +183 -48
  66. package/android/src/main/java/com/swmansion/enriched/utils/EnrichedSpannable.kt +82 -0
  67. package/android/src/main/java/com/swmansion/enriched/utils/EnrichedSpannableStringBuilder.kt +15 -0
  68. package/android/src/main/java/com/swmansion/enriched/utils/Utils.kt +0 -70
  69. package/android/src/main/java/com/swmansion/enriched/watchers/EnrichedSpanWatcher.kt +46 -14
  70. package/android/src/main/java/com/swmansion/enriched/watchers/EnrichedTextWatcher.kt +34 -11
  71. package/android/src/main/new_arch/CMakeLists.txt +6 -0
  72. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/conversions.h +21 -1
  73. package/ios/EnrichedTextInputView.h +1 -1
  74. package/ios/EnrichedTextInputView.mm +381 -49
  75. package/ios/config/InputConfig.h +18 -0
  76. package/ios/config/InputConfig.mm +118 -8
  77. package/ios/generated/RNEnrichedTextInputViewSpec/EventEmitters.cpp +146 -0
  78. package/ios/generated/RNEnrichedTextInputViewSpec/EventEmitters.h +140 -0
  79. package/ios/generated/RNEnrichedTextInputViewSpec/Props.cpp +10 -0
  80. package/ios/generated/RNEnrichedTextInputViewSpec/Props.h +194 -0
  81. package/ios/generated/RNEnrichedTextInputViewSpec/RCTComponentViewHelpers.h +74 -0
  82. package/ios/inputParser/InputParser.mm +83 -10
  83. package/ios/{attachments → interfaces}/ImageAttachment.mm +3 -1
  84. package/ios/interfaces/LinkRegexConfig.h +19 -0
  85. package/ios/interfaces/LinkRegexConfig.mm +37 -0
  86. package/ios/{utils → interfaces}/MentionStyleProps.mm +2 -2
  87. package/ios/{utils → interfaces}/StyleHeaders.h +10 -0
  88. package/ios/{utils → interfaces}/StyleTypeEnum.h +3 -0
  89. package/ios/styles/BlockQuoteStyle.mm +5 -5
  90. package/ios/styles/BoldStyle.mm +21 -6
  91. package/ios/styles/CodeBlockStyle.mm +5 -5
  92. package/ios/styles/H4Style.mm +17 -0
  93. package/ios/styles/H5Style.mm +17 -0
  94. package/ios/styles/H6Style.mm +17 -0
  95. package/ios/styles/HeadingStyleBase.mm +27 -10
  96. package/ios/styles/ImageStyle.mm +5 -5
  97. package/ios/styles/InlineCodeStyle.mm +30 -19
  98. package/ios/styles/ItalicStyle.mm +5 -5
  99. package/ios/styles/LinkStyle.mm +98 -40
  100. package/ios/styles/MentionStyle.mm +4 -4
  101. package/ios/styles/OrderedListStyle.mm +5 -5
  102. package/ios/styles/StrikethroughStyle.mm +5 -5
  103. package/ios/styles/UnderlineStyle.mm +5 -5
  104. package/ios/styles/UnorderedListStyle.mm +5 -5
  105. package/ios/utils/ParagraphAttributesUtils.h +4 -0
  106. package/ios/utils/ParagraphAttributesUtils.mm +67 -0
  107. package/ios/utils/ParagraphsUtils.mm +4 -4
  108. package/lib/module/EnrichedTextInput.js +22 -1
  109. package/lib/module/EnrichedTextInput.js.map +1 -1
  110. package/lib/module/EnrichedTextInputNativeComponent.ts +138 -12
  111. package/lib/module/{normalizeHtmlStyle.js → utils/normalizeHtmlStyle.js} +12 -0
  112. package/lib/module/utils/normalizeHtmlStyle.js.map +1 -0
  113. package/lib/module/utils/regexParser.js +46 -0
  114. package/lib/module/utils/regexParser.js.map +1 -0
  115. package/lib/typescript/src/EnrichedTextInput.d.ts +23 -14
  116. package/lib/typescript/src/EnrichedTextInput.d.ts.map +1 -1
  117. package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts +123 -12
  118. package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts.map +1 -1
  119. package/lib/typescript/src/index.d.ts +1 -1
  120. package/lib/typescript/src/index.d.ts.map +1 -1
  121. package/lib/typescript/src/utils/normalizeHtmlStyle.d.ts +4 -0
  122. package/lib/typescript/src/utils/normalizeHtmlStyle.d.ts.map +1 -0
  123. package/lib/typescript/src/utils/regexParser.d.ts +3 -0
  124. package/lib/typescript/src/utils/regexParser.d.ts.map +1 -0
  125. package/package.json +10 -6
  126. package/src/EnrichedTextInput.tsx +51 -13
  127. package/src/EnrichedTextInputNativeComponent.ts +138 -12
  128. package/src/index.tsx +2 -0
  129. package/src/{normalizeHtmlStyle.ts → utils/normalizeHtmlStyle.ts} +14 -2
  130. package/src/utils/regexParser.ts +56 -0
  131. package/lib/module/normalizeHtmlStyle.js.map +0 -1
  132. package/lib/typescript/src/normalizeHtmlStyle.d.ts +0 -4
  133. package/lib/typescript/src/normalizeHtmlStyle.d.ts.map +0 -1
  134. /package/ios/{utils → extensions}/ColorExtension.h +0 -0
  135. /package/ios/{utils → extensions}/ColorExtension.mm +0 -0
  136. /package/ios/{utils → extensions}/FontExtension.h +0 -0
  137. /package/ios/{utils → extensions}/FontExtension.mm +0 -0
  138. /package/ios/{utils → extensions}/LayoutManagerExtension.h +0 -0
  139. /package/ios/{utils → extensions}/LayoutManagerExtension.mm +0 -0
  140. /package/ios/{utils → extensions}/StringExtension.h +0 -0
  141. /package/ios/{utils → extensions}/StringExtension.mm +0 -0
  142. /package/ios/{utils → interfaces}/BaseStyleProtocol.h +0 -0
  143. /package/ios/{attachments → interfaces}/ImageAttachment.h +0 -0
  144. /package/ios/{utils → interfaces}/ImageData.h +0 -0
  145. /package/ios/{utils → interfaces}/ImageData.mm +0 -0
  146. /package/ios/{utils → interfaces}/LinkData.h +0 -0
  147. /package/ios/{utils → interfaces}/LinkData.mm +0 -0
  148. /package/ios/{attachments → interfaces}/MediaAttachment.h +0 -0
  149. /package/ios/{attachments → interfaces}/MediaAttachment.mm +0 -0
  150. /package/ios/{utils → interfaces}/MentionParams.h +0 -0
  151. /package/ios/{utils → interfaces}/MentionParams.mm +0 -0
  152. /package/ios/{utils → interfaces}/MentionStyleProps.h +0 -0
  153. /package/ios/{utils → interfaces}/StylePair.h +0 -0
  154. /package/ios/{utils → interfaces}/StylePair.mm +0 -0
  155. /package/ios/{utils → interfaces}/TextDecorationLineEnum.h +0 -0
  156. /package/ios/{utils → interfaces}/TextDecorationLineEnum.mm +0 -0
@@ -9,20 +9,29 @@ import com.swmansion.enriched.spans.EnrichedImageSpan
9
9
  import com.swmansion.enriched.spans.EnrichedLinkSpan
10
10
  import com.swmansion.enriched.spans.EnrichedMentionSpan
11
11
  import com.swmansion.enriched.spans.EnrichedSpans
12
+ import com.swmansion.enriched.utils.EnrichedConstants
12
13
  import com.swmansion.enriched.utils.getSafeSpanBoundaries
14
+ import com.swmansion.enriched.utils.removeZWS
13
15
 
14
- class ParametrizedStyles(private val view: EnrichedTextInputView) {
16
+ class ParametrizedStyles(
17
+ private val view: EnrichedTextInputView,
18
+ ) {
15
19
  private var mentionStart: Int? = null
16
20
  private var isSettingLinkSpan = false
17
21
 
18
22
  var mentionIndicators: Array<String> = emptyArray<String>()
19
23
 
20
- fun <T>removeSpansForRange(spannable: Spannable, start: Int, end: Int, clazz: Class<T>): Boolean {
24
+ fun <T> removeSpansForRange(
25
+ spannable: Spannable,
26
+ start: Int,
27
+ end: Int,
28
+ clazz: Class<T>,
29
+ ): Boolean {
21
30
  val ssb = spannable as SpannableStringBuilder
22
31
  val spans = ssb.getSpans(start, end, clazz)
23
32
  if (spans.isEmpty()) return false
24
33
 
25
- ssb.replace(start, end, ssb.substring(start, end).replace("\u200B", ""))
34
+ ssb.removeZWS(start, end)
26
35
 
27
36
  for (span in spans) {
28
37
  ssb.removeSpan(span)
@@ -31,7 +40,12 @@ class ParametrizedStyles(private val view: EnrichedTextInputView) {
31
40
  return true
32
41
  }
33
42
 
34
- fun setLinkSpan(start: Int, end: Int, text: String, url: String) {
43
+ fun setLinkSpan(
44
+ start: Int,
45
+ end: Int,
46
+ text: String,
47
+ url: String,
48
+ ) {
35
49
  isSettingLinkSpan = true
36
50
 
37
51
  val spannable = view.text as SpannableStringBuilder
@@ -55,36 +69,66 @@ class ParametrizedStyles(private val view: EnrichedTextInputView) {
55
69
  isSettingLinkSpan = false
56
70
  }
57
71
 
58
- fun afterTextChanged(s: Editable, endCursorPosition: Int) {
59
- val result = getWordAtIndex(s, endCursorPosition) ?: return
60
-
61
- afterTextChangedLinks(result)
62
- afterTextChangedMentions(result)
72
+ fun afterTextChanged(
73
+ s: Editable,
74
+ startCursorPosition: Int,
75
+ endCursorPosition: Int,
76
+ ) {
77
+ afterTextChangedLinks(startCursorPosition, endCursorPosition)
78
+ afterTextChangedMentions(s, startCursorPosition)
63
79
  }
64
80
 
65
- fun detectAllLinks() {
66
- val spannable = view.text as Spannable
67
-
68
- // TODO: Consider using more reliable regex, this one matches almost anything
69
- val urlPattern = android.util.Patterns.WEB_URL.matcher(spannable)
81
+ fun detectLinksInRange(
82
+ spannable: Spannable,
83
+ start: Int,
84
+ end: Int,
85
+ ) {
86
+ val regex = view.linkRegex ?: return
87
+ val contextText = spannable.subSequence(start, end).toString()
70
88
 
71
- val spans = spannable.getSpans(0, spannable.length, EnrichedLinkSpan::class.java)
89
+ val spans = spannable.getSpans(start, end, EnrichedLinkSpan::class.java)
72
90
  for (span in spans) {
73
91
  spannable.removeSpan(span)
74
92
  }
75
93
 
76
- while (urlPattern.find()) {
77
- val word = urlPattern.group()
78
- val start = urlPattern.start()
79
- val end = urlPattern.end()
80
- val span = EnrichedLinkSpan(word, view.htmlStyle)
81
- val (safeStart, safeEnd) = spannable.getSafeSpanBoundaries(start, end)
82
- spannable.setSpan(span, safeStart, safeEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
94
+ val wordsRegex = Regex("\\S+")
95
+ for (wordMatch in wordsRegex.findAll(contextText)) {
96
+ var word = wordMatch.value
97
+ var wordStart = wordMatch.range.first
98
+
99
+ // Do not include zero-width space in link detection
100
+ if (word.startsWith("\u200B")) {
101
+ word = word.substring(1)
102
+ wordStart += 1
103
+ }
104
+
105
+ // Loop over words and detect links
106
+ val matcher = regex.matcher(word)
107
+ while (matcher.find()) {
108
+ val linkStart = matcher.start()
109
+ val linkEnd = matcher.end()
110
+
111
+ val spanStart = start + wordStart + linkStart
112
+ val spanEnd = start + wordStart + linkEnd
113
+
114
+ val span = EnrichedLinkSpan(matcher.group(), view.htmlStyle)
115
+ val (safeStart, safeEnd) = spannable.getSafeSpanBoundaries(spanStart, spanEnd)
116
+
117
+ spannable.setSpan(
118
+ span,
119
+ safeStart,
120
+ safeEnd,
121
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE,
122
+ )
123
+ }
83
124
  }
84
125
  }
85
126
 
86
- private fun getWordAtIndex(s: CharSequence, index: Int): TextRange? {
87
- if (index < 0 ) return null
127
+ private fun getWordAtIndex(
128
+ s: CharSequence,
129
+ index: Int,
130
+ ): TextRange? {
131
+ if (index < 0) return null
88
132
 
89
133
  var start = index
90
134
  var end = index
@@ -102,8 +146,31 @@ class ParametrizedStyles(private val view: EnrichedTextInputView) {
102
146
  return TextRange(result, start, end)
103
147
  }
104
148
 
149
+ // After editing text we want to automatically detect links in the affected range
150
+ // Affected range is range + previous word + next word
151
+ private fun getLinksAffectedRange(
152
+ s: CharSequence,
153
+ start: Int,
154
+ end: Int,
155
+ ): IntRange {
156
+ var actualStart = start
157
+ var actualEnd = end
158
+
159
+ // Expand backward to find the start of the first affected word
160
+ while (actualStart > 0 && !Character.isWhitespace(s[actualStart - 1])) {
161
+ actualStart--
162
+ }
163
+
164
+ // Expand forward to find the end of the last affected word
165
+ while (actualEnd < s.length && !Character.isWhitespace(s[actualEnd])) {
166
+ actualEnd++
167
+ }
168
+
169
+ return actualStart..actualEnd
170
+ }
171
+
105
172
  private fun canLinkBeApplied(): Boolean {
106
- val mergingConfig = EnrichedSpans.getMergingConfigForStyle(EnrichedSpans.LINK, view.htmlStyle)?: return true
173
+ val mergingConfig = EnrichedSpans.getMergingConfigForStyle(EnrichedSpans.LINK, view.htmlStyle) ?: return true
107
174
  val conflictingStyles = mergingConfig.conflictingStyles
108
175
  val blockingStyles = mergingConfig.blockingStyles
109
176
 
@@ -118,34 +185,29 @@ class ParametrizedStyles(private val view: EnrichedTextInputView) {
118
185
  return true
119
186
  }
120
187
 
121
- private fun afterTextChangedLinks(result: TextRange) {
188
+ private fun afterTextChangedLinks(
189
+ editStart: Int,
190
+ editEnd: Int,
191
+ ) {
122
192
  // Do not detect link if it's applied manually
123
193
  if (isSettingLinkSpan || !canLinkBeApplied()) return
124
194
 
125
- val spannable = view.text as Spannable
126
- val (word, start, end) = result
127
-
128
- // TODO: Consider using more reliable regex, this one matches almost anything
129
- val urlPattern = android.util.Patterns.WEB_URL.matcher(word)
130
- val spans = spannable.getSpans(start, end, EnrichedLinkSpan::class.java)
131
- for (span in spans) {
132
- spannable.removeSpan(span)
133
- }
134
-
135
- if (urlPattern.matches()) {
136
- val span = EnrichedLinkSpan(word, view.htmlStyle)
137
- val (safeStart, safeEnd) = spannable.getSafeSpanBoundaries(start, end)
138
- spannable.setSpan(span, safeStart, safeEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
139
- }
195
+ val spannable = view.text as? Spannable ?: return
196
+ val affectedRange = getLinksAffectedRange(spannable, editStart, editEnd)
197
+ detectLinksInRange(spannable, affectedRange.first, affectedRange.last)
140
198
  }
141
199
 
142
- private fun afterTextChangedMentions(currentWord: TextRange) {
200
+ private fun afterTextChangedMentions(
201
+ s: CharSequence,
202
+ endCursorPosition: Int,
203
+ ) {
143
204
  val mentionHandler = view.mentionHandler ?: return
205
+ val currentWord = getWordAtIndex(s, endCursorPosition) ?: return
144
206
  val spannable = view.text as Spannable
145
207
 
146
208
  val indicatorsPattern = mentionIndicators.joinToString("|") { Regex.escape(it) }
147
209
  val mentionIndicatorRegex = Regex("^($indicatorsPattern)")
148
- val mentionRegex= Regex("^($indicatorsPattern)\\w*")
210
+ val mentionRegex = Regex("^($indicatorsPattern)\\w*")
149
211
 
150
212
  val spans = spannable.getSpans(currentWord.start, currentWord.end, EnrichedMentionSpan::class.java)
151
213
  for (span in spans) {
@@ -192,20 +254,24 @@ class ParametrizedStyles(private val view: EnrichedTextInputView) {
192
254
  mentionHandler.onMention(indicator, text)
193
255
  }
194
256
 
195
- fun setImageSpan(src: String, width: Float, height: Float) {
257
+ fun setImageSpan(
258
+ src: String,
259
+ width: Float,
260
+ height: Float,
261
+ ) {
196
262
  if (view.selection == null) return
197
263
  val spannable = view.text as SpannableStringBuilder
198
264
  val (start, originalEnd) = view.selection.getInlineSelection()
199
265
 
200
266
  if (start == originalEnd) {
201
- spannable.insert(start, "\uFFFC")
267
+ spannable.insert(start, EnrichedConstants.ORC_STRING)
202
268
  } else {
203
269
  val spans = spannable.getSpans(start, originalEnd, EnrichedImageSpan::class.java)
204
270
  for (s in spans) {
205
271
  spannable.removeSpan(s)
206
272
  }
207
273
 
208
- spannable.replace(start, originalEnd, "\uFFFC")
274
+ spannable.replace(start, originalEnd, EnrichedConstants.ORC_STRING)
209
275
  }
210
276
 
211
277
  val (imageStart, imageEnd) = spannable.getSafeSpanBoundaries(start, start + 1)
@@ -228,7 +294,11 @@ class ParametrizedStyles(private val view: EnrichedTextInputView) {
228
294
  }
229
295
  }
230
296
 
231
- fun setMentionSpan(indicator: String, text: String, attributes: Map<String, String>) {
297
+ fun setMentionSpan(
298
+ indicator: String,
299
+ text: String,
300
+ attributes: Map<String, String>,
301
+ ) {
232
302
  val selection = view.selection ?: return
233
303
 
234
304
  val spannable = view.text as SpannableStringBuilder
@@ -259,17 +329,23 @@ class ParametrizedStyles(private val view: EnrichedTextInputView) {
259
329
  view.selection.validateStyles()
260
330
  }
261
331
 
262
- fun getStyleRange(): Pair<Int, Int> {
263
- return view.selection?.getInlineSelection() ?: Pair(0, 0)
264
- }
332
+ fun getStyleRange(): Pair<Int, Int> = view.selection?.getInlineSelection() ?: Pair(0, 0)
265
333
 
266
- fun removeStyle(name: String, start: Int, end: Int): Boolean {
334
+ fun removeStyle(
335
+ name: String,
336
+ start: Int,
337
+ end: Int,
338
+ ): Boolean {
267
339
  val config = EnrichedSpans.parametrizedStyles[name] ?: return false
268
340
  val spannable = view.text as Spannable
269
341
  return removeSpansForRange(spannable, start, end, config.clazz)
270
342
  }
271
343
 
272
344
  companion object {
273
- data class TextRange(val text: String, val start: Int, val end: Int)
345
+ data class TextRange(
346
+ val text: String,
347
+ val start: Int,
348
+ val end: Int,
349
+ )
274
350
  }
275
351
  }
@@ -13,12 +13,12 @@ import android.os.Looper
13
13
  import android.util.Log
14
14
  import androidx.core.content.res.ResourcesCompat
15
15
  import androidx.core.graphics.drawable.DrawableCompat
16
- import java.net.URL
17
- import java.util.concurrent.Executors
18
16
  import androidx.core.graphics.drawable.toDrawable
19
17
  import com.swmansion.enriched.R
18
+ import java.net.URL
19
+ import java.util.concurrent.Executors
20
20
 
21
- class AsyncDrawable (
21
+ class AsyncDrawable(
22
22
  private val url: String,
23
23
  ) : Drawable() {
24
24
  private var internalDrawable: Drawable = Color.TRANSPARENT.toDrawable()
@@ -78,11 +78,14 @@ class AsyncDrawable (
78
78
  }
79
79
 
80
80
  @Deprecated("Deprecated in Java")
81
- override fun getOpacity(): Int {
82
- return PixelFormat.TRANSLUCENT
83
- }
81
+ override fun getOpacity(): Int = PixelFormat.TRANSLUCENT
84
82
 
85
- override fun setBounds(left: Int, top: Int, right: Int, bottom: Int) {
83
+ override fun setBounds(
84
+ left: Int,
85
+ top: Int,
86
+ right: Int,
87
+ bottom: Int,
88
+ ) {
86
89
  super.setBounds(left, top, right, bottom)
87
90
  internalDrawable.setBounds(left, top, right, bottom)
88
91
  }
@@ -0,0 +1,11 @@
1
+ package com.swmansion.enriched.utils
2
+
3
+ object EnrichedConstants {
4
+ // Zero Width Space
5
+ const val ZWS = '\u200B'
6
+ const val ZWS_STRING = "\u200B"
7
+
8
+ // Object Replacement Character
9
+ const val ORC = '\uFFFC'
10
+ const val ORC_STRING = "\uFFFC"
11
+ }
@@ -0,0 +1,17 @@
1
+ package com.swmansion.enriched.utils
2
+
3
+ import android.text.Editable
4
+ import android.text.Spannable
5
+ import android.text.SpannableStringBuilder
6
+ import com.swmansion.enriched.watchers.EnrichedSpanWatcher
7
+
8
+ class EnrichedEditableFactory(
9
+ private val watcher: EnrichedSpanWatcher,
10
+ ) : Editable.Factory() {
11
+ override fun newEditable(source: CharSequence): Editable {
12
+ val s = source as? SpannableStringBuilder ?: SpannableStringBuilder(source)
13
+ s.removeSpan(watcher)
14
+ s.setSpan(watcher, 0, s.length, Spannable.SPAN_INCLUSIVE_INCLUSIVE)
15
+ return s
16
+ }
17
+ }