Skip to content

Commit 1aa55a5

Browse files
committed
refactor(android): enforce non-nullable RichTextStyle and improve error handling
1 parent df3f7f1 commit 1aa55a5

5 files changed

Lines changed: 31 additions & 28 deletions

File tree

android/src/main/java/com/richtext/RichTextView.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,10 @@ class RichTextView : AppCompatTextView {
6262
try {
6363
val document = parser.parseMarkdown(currentMarkdown)
6464
if (document != null) {
65-
renderer.setStyle(richTextStyle)
65+
val currentStyle = requireNotNull(richTextStyle) {
66+
"richTextStyle should always be provided from JS side with defaults."
67+
}
68+
renderer.setStyle(currentStyle)
6669
val styledText = renderer.renderDocument(document, onLinkPressCallback)
6770
text = styledText
6871
movementMethod = LinkMovementMethod.getInstance()
@@ -77,7 +80,8 @@ class RichTextView : AppCompatTextView {
7780
}
7881

7982
fun setRichTextStyle(style: ReadableMap?) {
80-
richTextStyle = RichTextStyle(style)
83+
// JS always provides defaults via normalizeRichTextStyle, so style should always be present
84+
richTextStyle = style?.let { RichTextStyle(it) }
8185
}
8286

8387

android/src/main/java/com/richtext/renderer/NodeRenderer.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ interface NodeRenderer {
1919
}
2020

2121
data class RendererConfig(
22-
val style: RichTextStyle?
22+
val style: RichTextStyle
2323
)
2424

2525
class DocumentRenderer(
@@ -88,11 +88,11 @@ class HeadingRenderer(
8888
}
8989

9090
val contentLength = builder.length - start
91-
if (contentLength > 0) {
91+
if (contentLength > 0 && config != null) {
9292
builder.setSpan(
9393
RichTextHeadingSpan(
9494
heading.level,
95-
config?.style
95+
config.style
9696
),
9797
start,
9898
start + contentLength,

android/src/main/java/com/richtext/renderer/Renderer.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@ import org.commonmark.node.*
88
class Renderer {
99
private var style: RichTextStyle? = null
1010

11-
fun setStyle(style: RichTextStyle?) {
11+
fun setStyle(style: RichTextStyle) {
1212
this.style = style
1313
}
1414

1515
fun renderDocument(document: Document, onLinkPress: ((String) -> Unit)? = null): SpannableString {
1616
val builder = SpannableStringBuilder()
17-
val config = RendererConfig(style)
17+
val currentStyle = requireNotNull(style) {
18+
"richTextStyle should always be provided from JS side with defaults."
19+
}
20+
val config = RendererConfig(currentStyle)
1821

1922
renderNode(document, builder, onLinkPress, config)
2023

android/src/main/java/com/richtext/spans/RichTextHeadingSpan.kt

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ import com.richtext.styles.RichTextStyle
77

88
class RichTextHeadingSpan(
99
private val level: Int,
10-
private val style: RichTextStyle?
11-
) : AbsoluteSizeSpan(getFontSize(level, style)) {
10+
private val style: RichTextStyle
11+
) : AbsoluteSizeSpan(style.getHeadingFontSize(level).toInt()) {
1212

1313
private val cachedTypeface: Typeface? by lazy {
14-
style?.getHeadingFontFamily(level)?.let { fontFamily ->
14+
style.getHeadingFontFamily(level)?.let { fontFamily ->
1515
Typeface.create(fontFamily, Typeface.NORMAL)
1616
}
1717
}
@@ -25,9 +25,4 @@ class RichTextHeadingSpan(
2525
super.updateMeasureState(tp)
2626
cachedTypeface?.let { tp.typeface = it }
2727
}
28-
29-
companion object {
30-
private fun getFontSize(level: Int, style: RichTextStyle?): Int =
31-
style?.getHeadingFontSize(level)?.toInt() ?: 32
32-
}
3328
}

android/src/main/java/com/richtext/styles/RichTextStyle.kt

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,16 @@ data class HeadingStyle(
88
val fontFamily: String?
99
)
1010

11-
class RichTextStyle(style: ReadableMap?) {
12-
private val headingStyles = mutableMapOf<Int, HeadingStyle>()
11+
class RichTextStyle(style: ReadableMap) {
12+
private val headingStyles = arrayOfNulls<HeadingStyle>(7)
1313

1414
init {
15-
style?.let { parseStyles(it) }
15+
parseStyles(style)
1616
}
1717

1818
fun getHeadingFontSize(level: Int): Float {
19-
return headingStyles[level]?.fontSize ?: 32f
19+
return headingStyles[level]?.fontSize
20+
?: error("Heading style for level $level not found. JS should always provide defaults.")
2021
}
2122

2223
fun getHeadingFontFamily(level: Int): String? {
@@ -27,16 +28,16 @@ class RichTextStyle(style: ReadableMap?) {
2728
(1..6).forEach { level ->
2829
val levelKey = "h$level"
2930
val levelStyle = style.getMap(levelKey)
30-
levelStyle?.let { map ->
31-
val fontSize = if (map.hasKey("fontSize") && !map.isNull("fontSize")) {
32-
PixelUtil.toPixelFromSP(map.getDouble("fontSize").toFloat())
33-
} else {
34-
32f
35-
}
36-
val fontFamily = map.getString("fontFamily")
37-
38-
headingStyles[level] = HeadingStyle(fontSize, fontFamily)
31+
requireNotNull(levelStyle) { "Style for $levelKey not found. JS should always provide defaults." }
32+
33+
require(levelStyle.hasKey("fontSize") && !levelStyle.isNull("fontSize")) {
34+
"fontSize not found for $levelKey. JS should always provide defaults."
3935
}
36+
37+
val fontSize = PixelUtil.toPixelFromSP(levelStyle.getDouble("fontSize").toFloat())
38+
val fontFamily = levelStyle.getString("fontFamily")
39+
40+
headingStyles[level] = HeadingStyle(fontSize, fontFamily)
4041
}
4142
}
4243
}

0 commit comments

Comments
 (0)