@@ -7,21 +7,28 @@ import android.text.SpannableStringBuilder
77import android.text.TextUtils
88import android.text.style.AbsoluteSizeSpan
99import android.text.style.BackgroundColorSpan
10+ import android.text.style.ClickableSpan
1011import android.text.style.ForegroundColorSpan
1112import android.text.style.StrikethroughSpan
1213import android.text.style.StyleSpan
1314import android.text.style.TypefaceSpan
1415import android.text.style.UnderlineSpan
1516import android.view.Gravity
17+ import android.text.method.ArrowKeyMovementMethod
18+ import android.text.method.LinkMovementMethod
1619import androidx.appcompat.widget.AppCompatTextView
1720import com.facebook.react.uimanager.PixelUtil
1821import com.margelo.nitro.nitrotext.*
1922import androidx.core.graphics.toColorInt
23+ import com.nitrotext.renderers.NitroHtmlRenderer
24+ import com.nitrotext.spans.NitroLineHeightSpan
2025
2126class NitroTextImpl (private val view : AppCompatTextView ) {
2227 // Stored props
2328 private var fragments: Array <Fragment >? = null
2429 private var text: String? = null
30+ private var renderer: NitroRenderer = NitroRenderer .PLAINTEXT
31+ private var richTextStyleRules: Array <RichTextStyleRule >? = null
2532
2633 private var selectable: Boolean? = null
2734 private var selectionColor: String? = null
@@ -56,7 +63,11 @@ class NitroTextImpl(private val view: AppCompatTextView) {
5663 applyAlignment()
5764
5865 val frags = fragments
59- if (! frags.isNullOrEmpty()) {
66+ val content = text
67+
68+ if (renderer == NitroRenderer .HTML && ! content.isNullOrEmpty()) {
69+ applyHtml(content)
70+ } else if (! frags.isNullOrEmpty()) {
6071 applyFragments(frags)
6172 } else {
6273 applySimpleText()
@@ -68,6 +79,8 @@ class NitroTextImpl(private val view: AppCompatTextView) {
6879 // Setters
6980 fun setFragments (value : Array <Fragment >? ) { fragments = value }
7081 fun setText (value : String? ) { text = value }
82+ fun setRenderer (value : NitroRenderer ? ) { renderer = value ? : NitroRenderer .PLAINTEXT }
83+ fun setRichTextStyleRules (value : Array <RichTextStyleRule >? ) { richTextStyleRules = value }
7184
7285 fun setSelectable (value : Boolean? ) { selectable = value }
7386 fun setSelectionColor (value : String? ) { selectionColor = value }
@@ -212,7 +225,7 @@ class NitroTextImpl(private val view: AppCompatTextView) {
212225 }
213226 containerLineHeightPx?.let { applyLineHeightSpan(builder, 0 , builder.length, it) }
214227 view.text = builder
215-
228+
216229 // Apply default text color for runs without explicit color
217230 view.setTextColor(resolvedFontColor())
218231 }
@@ -265,6 +278,59 @@ class NitroTextImpl(private val view: AppCompatTextView) {
265278 return parsed ? : Color .BLACK
266279 }
267280
281+ private fun baseRichTextStyle (): RichTextStyle {
282+ return RichTextStyle (
283+ fontColor = fontColor,
284+ fragmentBackgroundColor = fragmentBackgroundColor,
285+ fontSize = fontSize,
286+ fontWeight = fontWeight,
287+ fontStyle = fontStyle,
288+ fontFamily = fontFamily,
289+ lineHeight = lineHeight,
290+ letterSpacing = letterSpacing,
291+ textAlign = textAlign,
292+ textTransform = textTransform,
293+ textDecorationLine = textDecorationLine,
294+ textDecorationColor = textDecorationColor,
295+ textDecorationStyle = textDecorationStyle,
296+ marginTop = null ,
297+ marginBottom = null ,
298+ marginLeft = null ,
299+ marginRight = null ,
300+ )
301+ }
302+
303+ private fun applyHtml (html : String ) {
304+ val renderer = NitroHtmlRenderer (
305+ context = view.context,
306+ defaultTextSizePx = view.textSize,
307+ allowFontScaling = allowFontScaling,
308+ maxFontSizeMultiplier = maxFontSizeMultiplier,
309+ )
310+ val spannable = renderer.render(html, baseRichTextStyle(), richTextStyleRules)
311+ trimTrailingNewlines(spannable)
312+ view.text = spannable
313+ val hasLinks = spannable.getSpans(0 , spannable.length, ClickableSpan ::class .java).isNotEmpty()
314+ view.linksClickable = hasLinks
315+ val isSelectable = selectable == true
316+ view.movementMethod = when {
317+ hasLinks && isSelectable -> LinkMovementMethod .getInstance()
318+ hasLinks -> HtmlLinkMovementMethod
319+ isSelectable -> ArrowKeyMovementMethod .getInstance()
320+ else -> null
321+ }
322+ view.setTextIsSelectable(isSelectable)
323+ view.setTextColor(resolvedFontColor())
324+ }
325+
326+ private fun trimTrailingNewlines (builder : SpannableStringBuilder ) {
327+ var length = builder.length
328+ while (length > 0 && builder[length - 1 ] == ' \n ' ) {
329+ builder.delete(length - 1 , length)
330+ length = builder.length
331+ }
332+ }
333+
268334 private fun resolveLineHeight (value : Double? ): Float? {
269335 val raw = value ? : return null
270336 val px = if (allowFontScaling) {
@@ -294,8 +360,4 @@ class NitroTextImpl(private val view: AppCompatTextView) {
294360 }
295361 builder.setSpan(NitroLineHeightSpan (lineHeightPx), start, end, flags)
296362 }
297-
298- companion object {
299- private const val TAG = " NitroTextImpl"
300- }
301363}
0 commit comments