@onekeyfe/react-native-native-list 3.0.157-alpha.248 → 3.0.157-alpha.250

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 (130) hide show
  1. package/README.md +21 -5
  2. package/android/src/main/java/com/onekey/nativelist/NativeListAccessoryStack.kt +711 -0
  3. package/android/src/main/java/com/onekey/nativelist/NativeListActionRenderer.kt +169 -0
  4. package/android/src/main/java/com/onekey/nativelist/NativeListActivityRenderer.kt +243 -0
  5. package/android/src/main/java/com/onekey/nativelist/NativeListAdapter.kt +20 -6
  6. package/android/src/main/java/com/onekey/nativelist/NativeListDataRowRenderer.kt +487 -0
  7. package/android/src/main/java/com/onekey/nativelist/NativeListIdentityRenderer.kt +820 -0
  8. package/android/src/main/java/com/onekey/nativelist/NativeListImageSlot.kt +147 -0
  9. package/android/src/main/java/com/onekey/nativelist/NativeListLeadingVisual.kt +453 -0
  10. package/android/src/main/java/com/onekey/nativelist/NativeListMarketRenderer.kt +997 -0
  11. package/android/src/main/java/com/onekey/nativelist/NativeListMediaTileRenderer.kt +234 -0
  12. package/android/src/main/java/com/onekey/nativelist/NativeListMessageRenderer.kt +232 -0
  13. package/android/src/main/java/com/onekey/nativelist/NativeListMetricCardRenderer.kt +551 -0
  14. package/android/src/main/java/com/onekey/nativelist/NativeListModels.kt +24 -0
  15. package/android/src/main/java/com/onekey/nativelist/NativeListPrimitives.kt +475 -0
  16. package/android/src/main/java/com/onekey/nativelist/NativeListRailRenderer.kt +143 -0
  17. package/android/src/main/java/com/onekey/nativelist/NativeListRendererRegistry.kt +42 -0
  18. package/android/src/main/java/com/onekey/nativelist/NativeListRendererRowView.kt +415 -0
  19. package/android/src/main/java/com/onekey/nativelist/NativeListResolvedText.kt +163 -0
  20. package/android/src/main/java/com/onekey/nativelist/NativeListRowHost.kt +70 -0
  21. package/android/src/main/java/com/onekey/nativelist/NativeListSectionHeaderRenderer.kt +748 -0
  22. package/android/src/main/java/com/onekey/nativelist/NativeListSystemRenderer.kt +464 -0
  23. package/android/src/main/java/com/onekey/nativelist/NativeListTextView.kt +25 -0
  24. package/android/src/main/java/com/onekey/nativelist/NativeListView.kt +174 -104
  25. package/android/src/main/java/com/onekey/nativelist/NativeListWalletGroupRenderer.kt +407 -0
  26. package/android/src/test/java/com/margelo/nitro/nativelist/NativeListSelectorBackgroundColorTest.kt +34 -0
  27. package/docs/DESIGN.md +518 -9
  28. package/docs/MIGRATION_BASELINE.md +117 -0
  29. package/docs/ROW_TEMPLATES.md +359 -0
  30. package/docs/SPEC.md +358 -0
  31. package/docs/STYLE_SPEC.md +978 -0
  32. package/docs/images/list-capabilities.svg +39 -0
  33. package/docs/images/row-action.svg +17 -0
  34. package/docs/images/row-activity.svg +24 -0
  35. package/docs/images/row-data.svg +24 -0
  36. package/docs/images/row-identity.svg +25 -0
  37. package/docs/images/row-market.svg +23 -0
  38. package/docs/images/row-media-tile.svg +26 -0
  39. package/docs/images/row-message.svg +20 -0
  40. package/docs/images/row-metric-card.svg +33 -0
  41. package/docs/images/row-rail.svg +18 -0
  42. package/docs/images/row-section-header.svg +19 -0
  43. package/docs/images/row-style-regions.svg +30 -0
  44. package/docs/images/row-system.svg +30 -0
  45. package/docs/images/row-wallet-group.svg +26 -0
  46. package/ios/NativeListAccessoryStack.swift +680 -0
  47. package/ios/NativeListActionRenderer.swift +108 -0
  48. package/ios/NativeListActivityRenderer.swift +179 -0
  49. package/ios/NativeListDataRowRenderer.swift +444 -0
  50. package/ios/NativeListIdentityRenderer.swift +685 -0
  51. package/ios/NativeListImageSlot.swift +140 -0
  52. package/ios/NativeListLeadingVisual.swift +372 -0
  53. package/ios/NativeListMarketRenderer.swift +698 -0
  54. package/ios/NativeListMediaTileRenderer.swift +184 -0
  55. package/ios/NativeListMessageRenderer.swift +168 -0
  56. package/ios/NativeListMetricCardRenderer.swift +420 -0
  57. package/ios/NativeListModels.swift +32 -0
  58. package/ios/NativeListRailRenderer.swift +152 -0
  59. package/ios/NativeListRendererCell.swift +311 -0
  60. package/ios/NativeListRendererRegistry.swift +50 -0
  61. package/ios/NativeListResolvedText.swift +122 -0
  62. package/ios/NativeListRowHost.swift +63 -0
  63. package/ios/NativeListSectionHeaderRenderer.swift +708 -0
  64. package/ios/NativeListSystemRenderer.swift +568 -0
  65. package/ios/NativeListTextLabel.swift +42 -0
  66. package/ios/NativeListTextStyles.swift +236 -0
  67. package/ios/NativeListWalletGroupRenderer.swift +255 -0
  68. package/ios/RNCNativeListView.swift +111 -180
  69. package/lib/module/models.js +54 -0
  70. package/lib/module/validation.js +324 -26
  71. package/lib/module/web/NativeListWebEngine.js +148 -936
  72. package/lib/module/web/templates/ActionRowRenderer.js +97 -0
  73. package/lib/module/web/templates/ActivityRowRenderer.js +95 -0
  74. package/lib/module/web/templates/DataRowRenderer.js +145 -0
  75. package/lib/module/web/templates/IdentityRowRenderer.js +289 -0
  76. package/lib/module/web/templates/MarketRowRenderer.js +310 -0
  77. package/lib/module/web/templates/MediaTileRowRenderer.js +132 -0
  78. package/lib/module/web/templates/MessageRowRenderer.js +165 -0
  79. package/lib/module/web/templates/MetricCardRowRenderer.js +172 -0
  80. package/lib/module/web/templates/RailRowRenderer.js +98 -0
  81. package/lib/module/web/templates/RowContainerStyle.js +100 -0
  82. package/lib/module/web/templates/RowElements.js +93 -0
  83. package/lib/module/web/templates/RowRendererRegistry.js +70 -0
  84. package/lib/module/web/templates/RowText.js +121 -0
  85. package/lib/module/web/templates/RowVisual.js +43 -0
  86. package/lib/module/web/templates/SectionHeaderRowRenderer.js +146 -0
  87. package/lib/module/web/templates/SystemRowRenderer.js +161 -0
  88. package/lib/module/web/templates/WalletGroupRowRenderer.js +96 -0
  89. package/lib/typescript/src/models.d.ts +166 -13
  90. package/lib/typescript/src/web/NativeListWebEngine.d.ts +18 -16
  91. package/lib/typescript/src/web/templates/ActionRowRenderer.d.ts +15 -0
  92. package/lib/typescript/src/web/templates/ActivityRowRenderer.d.ts +15 -0
  93. package/lib/typescript/src/web/templates/DataRowRenderer.d.ts +15 -0
  94. package/lib/typescript/src/web/templates/IdentityRowRenderer.d.ts +16 -0
  95. package/lib/typescript/src/web/templates/MarketRowRenderer.d.ts +30 -0
  96. package/lib/typescript/src/web/templates/MediaTileRowRenderer.d.ts +15 -0
  97. package/lib/typescript/src/web/templates/MessageRowRenderer.d.ts +44 -0
  98. package/lib/typescript/src/web/templates/MetricCardRowRenderer.d.ts +15 -0
  99. package/lib/typescript/src/web/templates/RailRowRenderer.d.ts +28 -0
  100. package/lib/typescript/src/web/templates/RowContainerStyle.d.ts +9 -0
  101. package/lib/typescript/src/web/templates/RowElements.d.ts +38 -0
  102. package/lib/typescript/src/web/templates/RowRendererRegistry.d.ts +83 -0
  103. package/lib/typescript/src/web/templates/RowText.d.ts +9 -0
  104. package/lib/typescript/src/web/templates/RowVisual.d.ts +20 -0
  105. package/lib/typescript/src/web/templates/SectionHeaderRowRenderer.d.ts +15 -0
  106. package/lib/typescript/src/web/templates/SystemRowRenderer.d.ts +16 -0
  107. package/lib/typescript/src/web/templates/WalletGroupRowRenderer.d.ts +20 -0
  108. package/package.json +3 -3
  109. package/src/models.ts +281 -19
  110. package/src/validation.ts +501 -46
  111. package/src/web/NativeListWebEngine.ts +361 -1932
  112. package/src/web/templates/ActionRowRenderer.ts +123 -0
  113. package/src/web/templates/ActivityRowRenderer.ts +159 -0
  114. package/src/web/templates/DataRowRenderer.ts +212 -0
  115. package/src/web/templates/IdentityRowRenderer.ts +527 -0
  116. package/src/web/templates/MarketRowRenderer.ts +467 -0
  117. package/src/web/templates/MediaTileRowRenderer.ts +182 -0
  118. package/src/web/templates/MessageRowRenderer.ts +306 -0
  119. package/src/web/templates/MetricCardRowRenderer.ts +337 -0
  120. package/src/web/templates/RailRowRenderer.ts +136 -0
  121. package/src/web/templates/RowContainerStyle.ts +131 -0
  122. package/src/web/templates/RowElements.ts +160 -0
  123. package/src/web/templates/RowRendererRegistry.ts +111 -0
  124. package/src/web/templates/RowText.ts +181 -0
  125. package/src/web/templates/RowVisual.ts +115 -0
  126. package/src/web/templates/SectionHeaderRowRenderer.ts +243 -0
  127. package/src/web/templates/SystemRowRenderer.ts +282 -0
  128. package/src/web/templates/WalletGroupRowRenderer.ts +131 -0
  129. package/android/src/main/java/com/onekey/nativelist/NativeListRowView.kt +0 -4538
  130. package/ios/NativeListCell.swift +0 -4300
@@ -0,0 +1,475 @@
1
+ package com.margelo.nitro.nativelist
2
+
3
+ import android.graphics.Canvas
4
+ import android.graphics.Color
5
+ import android.graphics.Paint
6
+ import android.graphics.Path
7
+ import android.graphics.Typeface
8
+ import android.view.View
9
+ import android.widget.LinearLayout
10
+ import android.widget.TextView
11
+ import androidx.core.graphics.PathParser
12
+ import kotlin.math.roundToInt
13
+
14
+ /** React Native color strings use CSS #RRGGBBAA ordering; Android expects #AARRGGBB. */
15
+ internal fun parseNativeListColor(value: String): Int {
16
+ val normalized = value.trim()
17
+ val androidValue =
18
+ if (
19
+ normalized.length == 9 &&
20
+ normalized[0] == '#' &&
21
+ normalized.drop(1).all { it.isDigit() || it.lowercaseChar() in 'a'..'f' }
22
+ ) {
23
+ "#${normalized.takeLast(2)}${normalized.substring(1, 7)}"
24
+ } else {
25
+ normalized
26
+ }
27
+ return Color.parseColor(androidValue)
28
+ }
29
+
30
+ internal object NativeListScale {
31
+ private const val STANDARD_DP_WIDTH_THRESHOLD = 400
32
+
33
+ fun factor(resources: android.content.res.Resources): Float {
34
+ val widthDp = resources.configuration.screenWidthDp
35
+ return if (widthDp in 1 until STANDARD_DP_WIDTH_THRESHOLD) 0.9f else 1f
36
+ }
37
+
38
+ fun dp(resources: android.content.res.Resources, value: Int): Int =
39
+ (value * factor(resources) * resources.displayMetrics.density).roundToInt()
40
+
41
+ fun dp(resources: android.content.res.Resources, value: Float): Float =
42
+ (value * factor(resources) * resources.displayMetrics.density).roundToInt().toFloat()
43
+
44
+ fun font(resources: android.content.res.Resources, value: Float): Float =
45
+ if (factor(resources) == 1f) value else (value * factor(resources)).roundToInt().toFloat()
46
+ }
47
+
48
+ internal object NativeListFonts {
49
+ private val cache = mutableMapOf<String, Typeface>()
50
+
51
+ private fun load(context: android.content.Context, weight: String, fallback: String): Typeface =
52
+ cache.getOrPut(weight) {
53
+ try {
54
+ Typeface.createFromAsset(context.assets, "fonts/Roobert-$weight.ttf")
55
+ } catch (_: RuntimeException) {
56
+ Typeface.create(fallback, Typeface.NORMAL)
57
+ }
58
+ }
59
+
60
+ fun regular(context: android.content.Context) = load(context, "Regular", "sans-serif")
61
+
62
+ fun medium(context: android.content.Context) = load(context, "Medium", "sans-serif-medium")
63
+
64
+ fun semibold(context: android.content.Context) = load(context, "SemiBold", "sans-serif-medium")
65
+
66
+ fun bold(context: android.content.Context) = load(context, "Bold", "sans-serif")
67
+ }
68
+
69
+ internal class DottedUnderlineTextView(context: android.content.Context) :
70
+ NativeListTextView(context) {
71
+ var useSourceScale = false
72
+
73
+ private fun scaledDp(value: Float) =
74
+ if (useSourceScale) value * resources.displayMetrics.density
75
+ else NativeListScale.dp(resources, value)
76
+
77
+ var showsDottedUnderline = false
78
+ var dottedUnderlineColor = Color.TRANSPARENT
79
+ private val dottedPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { style = Paint.Style.FILL }
80
+
81
+ override fun onDraw(canvas: Canvas) {
82
+ super.onDraw(canvas)
83
+ if (!showsDottedUnderline || text.isEmpty()) return
84
+ dottedPaint.color = dottedUnderlineColor
85
+ val radius = scaledDp(0.75f)
86
+ val spacing = scaledDp(4f)
87
+ val lineWidth = paint.measureText(text.toString()).coerceAtMost(width.toFloat())
88
+ val y = height - radius
89
+ var x = scaledDp(1f)
90
+ while (x <= lineWidth - radius) {
91
+ canvas.drawCircle(x, y, radius, dottedPaint)
92
+ x += spacing
93
+ }
94
+ }
95
+ }
96
+
97
+ internal class PackedTitleLineLayout(context: android.content.Context) : LinearLayout(context) {
98
+ var packsChildrenAtStart = false
99
+ // OneKey patch: optional cap for the Market subtitle's localized name.
100
+ var leadingTextMaxWidth = Int.MAX_VALUE
101
+
102
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
103
+ if (!packsChildrenAtStart || childCount < 2) {
104
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec)
105
+ return
106
+ }
107
+
108
+ val title = getChildAt(0)
109
+ val widthMode = MeasureSpec.getMode(widthMeasureSpec)
110
+ val widthSize = MeasureSpec.getSize(widthMeasureSpec)
111
+ var accessoryWidth = 0
112
+ for (index in 1 until childCount) {
113
+ val child = getChildAt(index)
114
+ if (child.visibility == GONE) continue
115
+ measureChildWithMargins(
116
+ child,
117
+ widthMeasureSpec,
118
+ paddingLeft + paddingRight + accessoryWidth,
119
+ heightMeasureSpec,
120
+ paddingTop + paddingBottom,
121
+ )
122
+ val margins = child.layoutParams as MarginLayoutParams
123
+ accessoryWidth += child.measuredWidth + margins.leftMargin + margins.rightMargin
124
+ }
125
+ val titleMargins = title.layoutParams as MarginLayoutParams
126
+ if (widthMode != MeasureSpec.UNSPECIFIED) {
127
+ (title as TextView).maxWidth =
128
+ (widthSize -
129
+ paddingLeft -
130
+ paddingRight -
131
+ accessoryWidth -
132
+ titleMargins.leftMargin -
133
+ titleMargins.rightMargin)
134
+ .coerceAtLeast(0)
135
+ .coerceAtMost(leadingTextMaxWidth)
136
+ }
137
+ (title.layoutParams as LayoutParams).apply {
138
+ width = LayoutParams.WRAP_CONTENT
139
+ weight = 0f
140
+ }
141
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec)
142
+ if (widthMode != MeasureSpec.UNSPECIFIED) {
143
+ setMeasuredDimension(widthSize, measuredHeight)
144
+ }
145
+ }
146
+ }
147
+
148
+ // OneKey patch: fit subtitle segments at intrinsic width, shrinking text only when necessary.
149
+ internal class SelectorSubtitleLayout(context: android.content.Context) : LinearLayout(context) {
150
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
151
+ val available = MeasureSpec.getSize(widthMeasureSpec)
152
+ val labels = mutableListOf<Pair<TextView, Int>>()
153
+ var fixedWidth = 0
154
+ for (index in 0 until childCount) {
155
+ val child = getChildAt(index)
156
+ val params = child.layoutParams as LayoutParams
157
+ if (child is TextView) {
158
+ child.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), heightMeasureSpec)
159
+ labels.add(child to child.measuredWidth)
160
+ } else fixedWidth += params.width + params.leftMargin + params.rightMargin
161
+ }
162
+ val desired = labels.sumOf { it.second }
163
+ val textWidth = (available - fixedWidth).coerceAtLeast(0)
164
+ labels.forEach { (label, width) ->
165
+ (label.layoutParams as LayoutParams).width =
166
+ if (desired <= textWidth) width
167
+ else (width.toLong() * textWidth / desired.coerceAtLeast(1)).toInt()
168
+ }
169
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec)
170
+ }
171
+ }
172
+
173
+ internal class OneKeyIconView(context: android.content.Context) : View(context) {
174
+ var useSourceScale = false
175
+ var iconName: String = ""
176
+ set(value) {
177
+ field = value
178
+ invalidate()
179
+ }
180
+
181
+ var tintColor: Int = Color.rgb(100, 100, 100)
182
+ set(value) {
183
+ field = value
184
+ invalidate()
185
+ }
186
+
187
+ var glyphSizeDp: Int? = null
188
+ set(value) {
189
+ field = value
190
+ invalidate()
191
+ }
192
+
193
+ private val fill = Paint(Paint.ANTI_ALIAS_FLAG).apply { style = Paint.Style.FILL }
194
+
195
+ override fun onDraw(canvas: Canvas) {
196
+ super.onDraw(canvas)
197
+ val pathData = iconPaths[iconName] ?: return
198
+ val drawSize =
199
+ minOf(
200
+ minOf(width, height).toFloat(),
201
+ glyphSizeDp?.let {
202
+ if (useSourceScale) (it * resources.displayMetrics.density).roundToInt().toFloat()
203
+ else NativeListScale.dp(resources, it).toFloat()
204
+ } ?: Float.MAX_VALUE,
205
+ )
206
+ // OneKey patch: custom account-error artwork uses an 18-point viewBox.
207
+ // val scale = drawSize / 24f
208
+ val scale = drawSize / (selectorIconViewBoxes[iconName] ?: 24f)
209
+ fill.color = tintColor
210
+ canvas.save()
211
+ canvas.translate((width - drawSize) / 2f, (height - drawSize) / 2f)
212
+ canvas.scale(scale, scale)
213
+ val sourceFillTypes = actionIconFillTypes[iconName]
214
+ pathData.forEachIndexed { index, data ->
215
+ PathParser.createPathFromPathData(data)?.let { path ->
216
+ path.fillType = sourceFillTypes?.getOrNull(index) ?: Path.FillType.EVEN_ODD
217
+ // OneKey patch: provider illustration colors are part of their source asset.
218
+ fill.color = selectorIconColors[iconName]?.getOrNull(index) ?: tintColor
219
+ canvas.drawPath(path, fill)
220
+ }
221
+ }
222
+ canvas.restore()
223
+ }
224
+
225
+ companion object {
226
+ // OneKey patch: preserve provider colors and non-24 viewBoxes.
227
+ private val selectorIconColors: Map<String, List<Int?>> =
228
+ mapOf(
229
+ "GlobusOutline" to listOf(null),
230
+ "LockSolid" to listOf(null),
231
+ "GoogleIllus" to
232
+ listOf(
233
+ parseNativeListColor("#4285F4"),
234
+ parseNativeListColor("#34A853"),
235
+ parseNativeListColor("#FBBC05"),
236
+ parseNativeListColor("#EA4335"),
237
+ ),
238
+ "AppleBrand" to listOf(null),
239
+ "BotIllus" to
240
+ listOf(
241
+ parseNativeListColor("#8897A5"),
242
+ parseNativeListColor("#3FA9F5"),
243
+ parseNativeListColor("#8897A5"),
244
+ parseNativeListColor("#8897A5"),
245
+ parseNativeListColor("#10243E"),
246
+ parseNativeListColor("#10243E"),
247
+ parseNativeListColor("#10243E"),
248
+ ),
249
+ "AllNetworksSolid" to listOf(null, null),
250
+ "CrossedSmallSolid" to listOf(null),
251
+ "AccountErrorCustom" to listOf(Color.argb(0x72, 0, 0, 0), Color.argb(0x72, 0, 0, 0)),
252
+ "Circle" to listOf(null),
253
+ )
254
+ private val selectorIconViewBoxes =
255
+ mapOf(
256
+ "GlobusOutline" to 24f,
257
+ "LockSolid" to 24f,
258
+ "GoogleIllus" to 24f,
259
+ "AppleBrand" to 16f,
260
+ "BotIllus" to 24f,
261
+ "AllNetworksSolid" to 24f,
262
+ "CrossedSmallSolid" to 24f,
263
+ "AccountErrorCustom" to 18f,
264
+ "Circle" to 24f,
265
+ )
266
+ // Keep the SVG fill-rule used by each Action-row source path. React Native
267
+ // SVG defaults to nonzero (WINDING); only paths declaring fillRule="evenodd"
268
+ // use EVEN_ODD. Other existing icons retain their prior rendering behavior.
269
+ private val actionIconFillTypes =
270
+ mapOf(
271
+ "GlobusOutline" to listOf(Path.FillType.EVEN_ODD),
272
+ "LockSolid" to listOf(Path.FillType.EVEN_ODD),
273
+ "GoogleIllus" to
274
+ listOf(
275
+ Path.FillType.WINDING,
276
+ Path.FillType.WINDING,
277
+ Path.FillType.WINDING,
278
+ Path.FillType.WINDING,
279
+ ),
280
+ "AppleBrand" to listOf(Path.FillType.WINDING),
281
+ "BotIllus" to
282
+ listOf(
283
+ Path.FillType.WINDING,
284
+ Path.FillType.WINDING,
285
+ Path.FillType.WINDING,
286
+ Path.FillType.WINDING,
287
+ Path.FillType.WINDING,
288
+ Path.FillType.WINDING,
289
+ Path.FillType.WINDING,
290
+ ),
291
+ "AllNetworksSolid" to listOf(Path.FillType.WINDING, Path.FillType.EVEN_ODD),
292
+ "CrossedSmallSolid" to listOf(Path.FillType.WINDING),
293
+ "AccountErrorCustom" to listOf(Path.FillType.WINDING, Path.FillType.EVEN_ODD),
294
+ "Circle" to listOf(Path.FillType.WINDING),
295
+ "BadgeVerifiedSolid" to listOf(Path.FillType.EVEN_ODD),
296
+ "ChevronRightSmallOutline" to listOf(Path.FillType.WINDING),
297
+ "MinusCircleOutline" to listOf(Path.FillType.WINDING, Path.FillType.EVEN_ODD),
298
+ "PlusCircleOutline" to listOf(Path.FillType.WINDING, Path.FillType.EVEN_ODD),
299
+ "PlusSmallOutline" to listOf(Path.FillType.WINDING),
300
+ "DotHorOutline" to listOf(Path.FillType.WINDING),
301
+ "MinusCircleSolid" to listOf(Path.FillType.EVEN_ODD),
302
+ "PencilOutline" to listOf(Path.FillType.EVEN_ODD),
303
+ "DragOutline" to listOf(Path.FillType.WINDING),
304
+ "StarSolid" to listOf(Path.FillType.WINDING),
305
+ "ChevronGrabberVerOutline" to listOf(Path.FillType.WINDING),
306
+ "ChevronBottomOutline" to listOf(Path.FillType.WINDING),
307
+ "ChevronTopOutline" to listOf(Path.FillType.WINDING),
308
+ "ImageSquareWavesOutline" to listOf(Path.FillType.WINDING, Path.FillType.EVEN_ODD),
309
+ )
310
+
311
+ // Exact 24x24 paths from app-monorepo packages/components Icon sources.
312
+ private val iconPaths =
313
+ mapOf(
314
+ // OneKey patch: official selector SVG path geometry.
315
+ "GlobusOutline" to
316
+ listOf(
317
+ "M12 2c5.185 0 9.448 3.947 9.95 9H22v2h-.05c-.502 5.053-4.765 9-9.95 9s-9.448-3.947-9.95-9H2v-2h.05C2.552 5.947 6.815 2 12 2M9.523 13c.09 1.982.438 3.726.934 5.002.29.746.612 1.282.917 1.614.304.331.517.384.626.384s.322-.053.626-.384c.305-.332.627-.868.917-1.614.496-1.276.845-3.02.934-5.002zm-5.459 0a8 8 0 0 0 4.8 6.36 10 10 0 0 1-.271-.633C7.994 17.187 7.61 15.189 7.52 13zm12.416 0c-.09 2.189-.474 4.187-1.073 5.727a10 10 0 0 1-.271.633 8 8 0 0 0 4.8-6.36zM8.863 4.639A8 8 0 0 0 4.064 11h3.457c.09-2.189.473-4.187 1.072-5.727q.127-.327.27-.634M12 4c-.109 0-.322.053-.626.384-.305.332-.627.868-.917 1.614-.496 1.276-.844 3.02-.934 5.002h4.954c-.09-1.982-.438-3.726-.934-5.002-.29-.746-.612-1.282-.917-1.614C12.322 4.053 12.109 4 12 4m3.136.639q.144.307.271.634c.599 1.54.982 3.538 1.073 5.727h3.456a8 8 0 0 0-4.8-6.361"
318
+ ),
319
+ "LockSolid" to
320
+ listOf(
321
+ "M12 2a5 5 0 0 1 5 5v2h3v13H4V9h3V7a5 5 0 0 1 5-5m-1 11v5h2v-5zm1-9a3 3 0 0 0-3 3v2h6V7a3 3 0 0 0-3-3"
322
+ ),
323
+ "GoogleIllus" to
324
+ listOf(
325
+ "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09",
326
+ "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23",
327
+ "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22z",
328
+ "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53",
329
+ ),
330
+ "AppleBrand" to
331
+ listOf(
332
+ "M11.67.834c.117 1.074-.315 2.153-.955 2.928-.64.773-1.692 1.378-2.718 1.298-.14-1.054.38-2.151.971-2.836C9.63 1.45 10.746.872 11.67.834M14.994 7.093c-.176.108-1.992 1.224-1.972 3.482.025 2.769 2.428 3.693 2.46 3.705l-.004.015a10.1 10.1 0 0 1-1.264 2.593c-.764 1.116-1.556 2.229-2.806 2.254-.598.011-1-.162-1.416-.343-.437-.19-.891-.386-1.609-.386-.751 0-1.226.203-1.683.398-.397.169-.78.333-1.32.354-1.208.047-2.124-1.207-2.895-2.32C.909 14.57-.294 10.414 1.322 7.612c.803-1.395 2.237-2.275 3.794-2.298.671-.014 1.32.244 1.89.47.434.172.821.326 1.135.326.282 0 .659-.149 1.099-.323.692-.273 1.539-.607 2.41-.518.599.026 2.276.24 3.354 1.818z"
333
+ ),
334
+ "BotIllus" to
335
+ listOf(
336
+ "M11 2a1 1 0 1 1 2 0v1.8l1.6 1.6a1 1 0 1 1-1.4 1.4L12 5.6l-1.2 1.2a1 1 0 0 1-1.4-1.4L11 3.8z",
337
+ "M8.0 6.0h8.0a5.0 5.0 0 0 1 5.0 5.0v4.0a5.0 5.0 0 0 1 -5.0 5.0h-8.0a5.0 5.0 0 0 1 -5.0 -5.0v-4.0a5.0 5.0 0 0 1 5.0 -5.0z",
338
+ "M3.0 10.0h0.0a1.5 1.5 0 0 1 1.5 1.5v3.0a1.5 1.5 0 0 1 -1.5 1.5h0.0a1.5 1.5 0 0 1 -1.5 -1.5v-3.0a1.5 1.5 0 0 1 1.5 -1.5z",
339
+ "M21.0 10.0h0.0a1.5 1.5 0 0 1 1.5 1.5v3.0a1.5 1.5 0 0 1 -1.5 1.5h0.0a1.5 1.5 0 0 1 -1.5 -1.5v-3.0a1.5 1.5 0 0 1 1.5 -1.5z",
340
+ "M7.5 12.0a1.5 1.5 0 1 0 3.0 0a1.5 1.5 0 1 0 -3.0 0",
341
+ "M13.5 12.0a1.5 1.5 0 1 0 3.0 0a1.5 1.5 0 1 0 -3.0 0",
342
+ "M8.5 15.4c.9.8 2.08 1.2 3.5 1.2s2.6-.4 3.5-1.2c.24-.2.6-.18.8.06.2.23.17.6-.06.8-1.14.98-2.58 1.46-4.24 1.46s-3.1-.48-4.24-1.46a.58.58 0 0 1-.06-.8c.2-.24.56-.26.8-.06",
343
+ ),
344
+ "AllNetworksSolid" to
345
+ listOf(
346
+ "M15.333 13.998a1.335 1.335 0 1 1 0 2.67 1.335 1.335 0 0 1 0-2.67",
347
+ "M12 0c6.627 0 12 5.373 12 12s-5.373 12-12 12S0 18.627 0 12 5.373 0 12 0M8 12.668A2 2 0 0 0 6 14.666V16c0 1.103.895 1.997 1.998 1.998h1.334A2 2 0 0 0 11.33 16v-1.334a2 2 0 0 0-1.998-1.998zm7.333 0a2.665 2.665 0 1 0 0 5.33 2.665 2.665 0 0 0 0-5.33M7.999 6.001A2 2 0 0 0 6.001 8v1.334c0 1.103.895 1.998 1.998 1.998h1.334a2 2 0 0 0 1.998-1.998V7.999a2 2 0 0 0-1.998-1.998zm6.667 0A2 2 0 0 0 12.668 8v1.334c0 1.103.895 1.998 1.998 1.998H16a2 2 0 0 0 1.998-1.998V7.999A2 2 0 0 0 16 6.001z",
348
+ ),
349
+ "CrossedSmallSolid" to
350
+ listOf(
351
+ "M17.87 8.25 14.12 12l3.75 3.75-2.12 2.121-3.75-3.75-3.75 3.75-2.121-2.121L9.879 12l-3.75-3.75 2.12-2.121L12 9.879l3.75-3.75 2.122 2.121Z"
352
+ ),
353
+ "AccountErrorCustom" to
354
+ listOf(
355
+ "M12.5 12.75a1.25 1.25 0 1 0 0-2.5 1.25 1.25 0 0 0 0 2.5",
356
+ "M0 3.5A3.5 3.5 0 0 1 3.5 0h8.088A2.41 2.41 0 0 1 14 2.412V5h1a3 3 0 0 1 3 3v7a3 3 0 0 1-3 3H4a4 4 0 0 1-4-4zm2 3.163V14a2 2 0 0 0 2 2h11a1 1 0 0 0 1-1V8a1 1 0 0 0-1-1H3.5c-.537 0-1.045-.12-1.5-.337M2 3.5A1.5 1.5 0 0 0 3.5 5H12V2.412A.41.41 0 0 0 11.588 2H3.5A1.5 1.5 0 0 0 2 3.5",
357
+ ),
358
+ "Circle" to listOf("M0 12a12 12 0 1 0 24 0a12 12 0 1 0 -24 0"),
359
+ "BadgeVerifiedSolid" to
360
+ listOf(
361
+ "M9.483 11.458v3.5h-1v-3.5z M10.467 2.698a2.03 2.03 0 0 1 3.065 0l1.358 1.564a.03.03 0 0 0 .028.01l2.046-.325a2.03 2.03 0 0 1 2.347 1.971l.037 2.07q0 .016.014.026l1.776 1.066a2.03 2.03 0 0 1 .532 3.019l-1.304 1.609a.03.03 0 0 0-.005.03l.675 1.956a2.03 2.03 0 0 1-1.533 2.656l-2.033.394a.03.03 0 0 0-.023.019l-.741 1.933a2.03 2.03 0 0 1-2.88 1.05l-1.811-1.006a.03.03 0 0 0-.03 0l-1.811 1.005a2.03 2.03 0 0 1-2.88-1.049l-.742-1.933a.03.03 0 0 0-.023-.019l-2.033-.394a2.03 2.03 0 0 1-1.532-2.656l.675-1.957a.03.03 0 0 0-.005-.029l-1.304-1.61a2.03 2.03 0 0 1 .532-3.018l1.776-1.066a.03.03 0 0 0 .014-.026l.035-2.07a2.03 2.03 0 0 1 2.349-1.97l2.045.324a.03.03 0 0 0 .028-.01zm1.516 3.76a.5.5 0 0 0-.447.276l-1.861 3.724H8.483a1 1 0 0 0-1 1v3.5a1 1 0 0 0 1 1h6.692a2 2 0 0 0 1.981-1.73l.341-2.5a2 2 0 0 0-1.982-2.27h-1.939l.197-1.269a1.5 1.5 0 0 0-1.481-1.731z"
362
+ ),
363
+ "ArrowBottomOutline" to
364
+ listOf("m13 17.586 5-5L19.414 14 12 21.414 4.586 14 6 12.586l5 5V3h2z"),
365
+ "ArrowTopOutline" to
366
+ listOf("M19.414 10 18 11.414l-5-5V21h-2V6.414l-5 5L4.586 10 12 2.586z"),
367
+ "ChartTrendingUpOutline" to
368
+ listOf("M22 13h-2V9.414l-7 7-4-4-6 6L1.586 17 9 9.586l4 4L18.586 8H15V6h7z"),
369
+ "SwapHorOutline" to
370
+ listOf(
371
+ "M21 16H6.914l2.293 2.293-1.414 1.414L2.086 14H21zm.914-6H3V8h14.086l-2.293-2.293 1.414-1.414z"
372
+ ),
373
+ "ShieldExclamationOutline" to
374
+ listOf(
375
+ "M12 12.25a1.25 1.25 0 1 1 0 2.5 1.25 1.25 0 0 1 0-2.5m0-4.75a1 1 0 0 1 1 1v2a1 1 0 0 1-2 0v-2a1 1 0 0 1 1-1",
376
+ "M11.352 2.223c.42-.145.876-.145 1.296 0l6.98 2.4a1.995 1.995 0 0 1 1.347 1.886v5.432c0 2.799-1.146 4.817-2.805 6.387-1.61 1.525-3.735 2.652-5.696 3.71a1 1 0 0 1-.947 0c-1.961-1.058-4.086-2.185-5.697-3.71-1.659-1.57-2.805-3.588-2.805-6.386V6.508c0-.852.542-1.61 1.347-1.887l6.98-2.4ZM5.02 6.509v5.432c0 2.16.848 3.676 2.18 4.938 1.272 1.204 2.957 2.149 4.799 3.145 1.842-.996 3.527-1.94 4.799-3.145 1.332-1.262 2.181-2.778 2.181-4.938V6.51L12 4.109z",
377
+ ),
378
+ "InfoCircleOutline" to
379
+ listOf(
380
+ "M13 17h-2v-5h-1v-2h3zm0-8h-2V7h2z",
381
+ "M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2m0 2a8 8 0 1 0 0 16 8 8 0 0 0 0-16",
382
+ ),
383
+ "SpeakerPromoteOutline" to
384
+ listOf(
385
+ "M21.996 11a4 4 0 0 1-3 3.874v5.495l-5.361-1.711A3.998 3.998 0 0 1 5.996 17v-.779l-4-1.276v-7.89l17-5.424v5.495c1.725.444 3 2.01 3 3.874m-2 0c0-.74-.402-1.385-1-1.731v3.46c.597-.345 1-.989 1-1.729M7.998 7.24v7.521l8.998 2.871V4.368l-8.998 2.87ZM3.996 8.516v4.967l2.002.638V7.877zm4 8.484a2 2 0 0 0 3.706 1.041L7.996 16.86z"
386
+ ),
387
+ "PlusCircleOutline" to
388
+ listOf(
389
+ "M13 11h4v2h-4v4h-2v-4l-4 .001v-2L11 11V7h2z",
390
+ "M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2m0 2a8 8 0 1 0 0 16 8 8 0 0 0 0-16",
391
+ ),
392
+ "PlusSmallOutline" to listOf("M13 11h5v2h-5v5h-2v-5H6v-2h5V6h2z"),
393
+ "DotHorOutline" to listOf("M6 14H2v-4h4zm8 0h-4v-4h4zm8 0h-4v-4h4z"),
394
+ "MinusCircleOutline" to
395
+ listOf(
396
+ "M17 13H7v-2h10z",
397
+ "M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2m0 2a8 8 0 1 0 0 16 8 8 0 0 0 0-16",
398
+ ),
399
+ "MinusCircleSolid" to
400
+ listOf(
401
+ "M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2M7 13h10v-2H7z"
402
+ ),
403
+ "ErrorSolid" to listOf("M23.256 20H.742L12 1.041zM11 15v2h2v-2zm0-6v5h2V9z"),
404
+ "QuestionmarkSolid" to
405
+ listOf(
406
+ "M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2m-1 15h2v-2h-2zM9 7v3h2V9h2v1l-2 1.5V14h2v-1.5l2-1.5V7z"
407
+ ),
408
+ "PencilOutline" to
409
+ listOf(
410
+ "M22.414 7.5 7.914 22H2v-5.914l14.5-14.5zM4 16.914V20h3.086l9.5-9.5L13.5 7.414zM14.914 6 18 9.086 19.586 7.5 16.5 4.414z"
411
+ ),
412
+ "ChevronRightSmallOutline" to listOf("M15.414 12 10 17.414 8.586 16l4-4-4-4L10 6.586z"),
413
+ "DragOutline" to
414
+ listOf("M11 21H7v-4h4zm6 0h-4v-4h4zm-6-7H7v-4h4zm6 0h-4v-4h4zm-6-7H7V3h4zm6 0h-4V3h4z"),
415
+ "StarOutline" to
416
+ listOf(
417
+ "m15.455 7.243 7.729 1.123-5.592 5.45 1.32 7.698L12 17.879l-6.911 3.635 1.32-7.698-5.592-5.45 7.728-1.123L12 .24zM9.872 9.071l-4.759.69 3.444 3.358-.814 4.738L12 15.62l.465.245 3.791 1.993-.813-4.739 3.443-3.357-4.758-.69L12 4.758z"
418
+ ),
419
+ "StarSolid" to
420
+ listOf(
421
+ "m15.405 7.313 7.84 1.034-5.735 5.443 1.44 7.774L12 17.793l-6.948 3.771 1.44-7.774L.756 8.347l7.839-1.034L12 .178z"
422
+ ),
423
+ "ChevronGrabberVerOutline" to
424
+ listOf(
425
+ "M17.414 15 12 20.414 6.586 15 8 13.586l4 4 4-4zm0-6L16 10.414l-4-4-4 4L6.586 9 12 3.586z"
426
+ ),
427
+ "ChevronBottomOutline" to
428
+ listOf("M20.707 9.707 12 18.414 3.293 9.707l1.414-1.414L12 15.586l7.293-7.293z"),
429
+ "ChevronTopOutline" to
430
+ listOf("m20.707 14.293-1.414 1.414L12 8.414l-7.293 7.293-1.414-1.414L12 5.586z"),
431
+ "ImageSquareWavesOutline" to
432
+ listOf(
433
+ "M14.25 7a2 2 0 1 1 0 4 2 2 0 0 1 0-4",
434
+ "M21 21H3V3h18zM5 16.414V19h12.586L14 15.414l-2 2-4-4zm0-2.828 3-3 4 4 2-2 5 5V5H5z",
435
+ ),
436
+ )
437
+ }
438
+ }
439
+
440
+ internal class OneKeyCheckboxView(context: android.content.Context) : View(context) {
441
+ var usesSelectorGeometry = false
442
+ private val glyphPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { style = Paint.Style.FILL }
443
+ private var state = "unchecked"
444
+
445
+ fun setState(value: String, color: Int) {
446
+ state = value
447
+ glyphPaint.color = color
448
+ invalidate()
449
+ }
450
+
451
+ override fun onDraw(canvas: Canvas) {
452
+ super.onDraw(canvas)
453
+ val pathData =
454
+ when (state) {
455
+ "checked" ->
456
+ "M12.204 5.043a1 1 0 0 1 0 1.414l-4.5 4.5a1 1 0 0 1-1.414 0l-2-2a1 1 0 1 1 1.414-1.414l1.293 1.293 3.793-3.793a1 1 0 0 1 1.414 0"
457
+ "indeterminate" -> "M4 8a1 1 0 0 1 1-1h6a1 1 0 0 1 0 2H5a1 1 0 0 1-1-1"
458
+ else -> return
459
+ }
460
+ // OneKey patch: the source icon is a 16dp child after the 2dp border, not 80% of a rounded
461
+ // frame.
462
+ val drawSize =
463
+ if (usesSelectorGeometry) (16 * resources.displayMetrics.density).roundToInt().toFloat()
464
+ else minOf(width, height) * 0.8f
465
+ val borderOffset = (2 * resources.displayMetrics.density).roundToInt().toFloat()
466
+ canvas.save()
467
+ canvas.translate(
468
+ if (usesSelectorGeometry) borderOffset else (width - drawSize) / 2f,
469
+ if (usesSelectorGeometry) borderOffset else (height - drawSize) / 2f,
470
+ )
471
+ canvas.scale(drawSize / 16f, drawSize / 16f)
472
+ PathParser.createPathFromPathData(pathData)?.let { canvas.drawPath(it, glyphPaint) }
473
+ canvas.restore()
474
+ }
475
+ }
@@ -0,0 +1,143 @@
1
+ package com.margelo.nitro.nativelist
2
+
3
+ import android.view.Gravity
4
+ import android.widget.LinearLayout
5
+ import com.facebook.react.uimanager.ThemedReactContext
6
+ import kotlin.math.roundToInt
7
+ import org.json.JSONObject
8
+
9
+ internal class NativeListRailRowView(context: ThemedReactContext) :
10
+ NativeListRendererRowView(context) {
11
+ private val textLine =
12
+ LinearLayout(context).apply {
13
+ orientation = HORIZONTAL
14
+ gravity = Gravity.CENTER_VERTICAL
15
+ }
16
+ private val title = NativeListTextView(context)
17
+ private val badge = NativeListTextView(context)
18
+ private val status = NativeListTextView(context)
19
+ private var visual: NativeListLeadingVisual? = null
20
+ private var leadingWidth = 0
21
+ private var leadingGap = 0
22
+ private var badgeGap = 0
23
+ private var trailingGap = 0
24
+ override val defaultCornerRadius = 8
25
+ override val pressedColorName = "strongBackground"
26
+ override val pressedColorFallback = "#0000000F"
27
+ override val assetFields = listOf("visual")
28
+ override val showsSelection = false
29
+
30
+ override fun defaultHeight(item: NativeListItem, layout: String) = 28
31
+
32
+ init {
33
+ listOf(title, badge, status).forEach {
34
+ textLine.addView(it, LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT))
35
+ }
36
+ addView(textLine, LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT))
37
+ }
38
+
39
+ override fun bindContent(
40
+ item: NativeListItem,
41
+ theme: JSONObject?,
42
+ layout: String,
43
+ checkboxState: (NativeListItem, NativeSelectionTarget?, String) -> String,
44
+ ) {
45
+ val style = item.json.optJSONObject("style") ?: JSONObject()
46
+ fun dimension(name: String, fallback: Int) =
47
+ if (style.has(name)) stylePx(style.optDouble(name)) else dp(fallback)
48
+ fun color(name: String, fallback: String) =
49
+ parseNativeListColor(theme?.optString(name, fallback) ?: fallback)
50
+ fun text(
51
+ view: NativeListTextView,
52
+ field: String,
53
+ value: String,
54
+ weight: String,
55
+ tint: Int,
56
+ lineHeight: Int,
57
+ ) {
58
+ NativeListResolvedText.resolve(
59
+ reactContext,
60
+ value,
61
+ style.optJSONObject(field),
62
+ 12f,
63
+ weight,
64
+ tint,
65
+ lineHeight,
66
+ 1,
67
+ sourceScale,
68
+ )
69
+ .bind(view)
70
+ }
71
+ text(
72
+ title,
73
+ "title",
74
+ item.json.optString("title"),
75
+ "medium",
76
+ color("primaryText", "#000000DF"),
77
+ 16,
78
+ )
79
+ val badgeData = item.json.optJSONObject("badge")
80
+ val tone = badgeData?.optString("tone")
81
+ val badgeColor =
82
+ when (tone) {
83
+ "success" -> color("positive", "#00713FDE")
84
+ "danger" -> color("negative", "#C40006D3")
85
+ else -> color("secondaryText", "#0000009B")
86
+ }
87
+ text(badge, "badge", badgeData?.optString("text") ?: "", "medium", badgeColor, 16)
88
+ val statusValue = item.json.optString("status").takeUnless { it == "none" } ?: ""
89
+ text(status, "status", statusValue, "regular", color("secondaryText", "#0000009B"), 0)
90
+ val horizontal = dimension("horizontalPadding", 4)
91
+ val vertical = dimension("verticalPadding", 4)
92
+ setPadding(horizontal, vertical, horizontal, vertical)
93
+ gravity =
94
+ when (style.optJSONObject("container")?.optString("contentVerticalAlignment")) {
95
+ "top" -> Gravity.TOP
96
+ "bottom" -> Gravity.BOTTOM
97
+ else -> Gravity.CENTER_VERTICAL
98
+ }
99
+ leadingGap = dimension("leadingGap", 6)
100
+ badgeGap = dimension("titleBadgeGap", 6)
101
+ trailingGap = dimension("trailingGap", 0)
102
+ badge.layoutParams =
103
+ LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT).apply {
104
+ marginStart = badgeGap
105
+ }
106
+ status.layoutParams =
107
+ LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT).apply {
108
+ marginStart = trailingGap
109
+ }
110
+ val image = style.optJSONObject("image") ?: JSONObject()
111
+ leadingWidth = if (image.has("width")) stylePx(image.optDouble("width")) else dp(20)
112
+ val imageHeight = if (image.has("height")) stylePx(image.optDouble("height")) else dp(20)
113
+ // Legacy: a rail without a visual still reserves its empty 20dp slot and gap.
114
+ val source =
115
+ item.json.optJSONObject("visual") ?: JSONObject().put("backgroundColor", "#00000000")
116
+ val view = visual ?: NativeListLeadingVisual(reactContext).also { visual = it }
117
+ view.bind(source, image, item.key, theme, false, sourceScale)
118
+ val params = LayoutParams(leadingWidth, imageHeight).apply { marginEnd = leadingGap }
119
+ if (view.parent == null) addView(view, 0, params) else view.layoutParams = params
120
+ }
121
+
122
+ // Retain the legacy 6-unit trailing allowance when a status is present.
123
+ override fun horizontalWidth(item: NativeListItem): Int =
124
+ (paddingLeft +
125
+ paddingRight +
126
+ leadingWidth +
127
+ leadingGap +
128
+ title.paint.measureText(title.text.toString()) +
129
+ (if (badge.visibility == VISIBLE) badgeGap + badge.paint.measureText(badge.text.toString())
130
+ else 0f) +
131
+ (if (status.visibility == VISIBLE)
132
+ trailingGap + dp(6) + status.paint.measureText(status.text.toString())
133
+ else 0f))
134
+ .roundToInt()
135
+
136
+ override fun recycleContent() {
137
+ visual?.recycle()
138
+ }
139
+
140
+ override fun disposeContent() {
141
+ visual?.dispose()
142
+ }
143
+ }
@@ -0,0 +1,42 @@
1
+ package com.margelo.nitro.nativelist
2
+
3
+ import com.facebook.react.uimanager.ThemedReactContext
4
+
5
+ internal object NativeListRendererRegistry {
6
+ private val factories: Map<NativeListRendererKey, (ThemedReactContext) -> NativeListRowHost> =
7
+ mapOf(
8
+ NativeListRendererKey.SECTION_HEADER to ::NativeListSectionHeaderRowView,
9
+ NativeListRendererKey.WALLET_GROUP to ::NativeListWalletGroupRowView,
10
+ NativeListRendererKey.IDENTITY to ::NativeListIdentityRowView,
11
+ NativeListRendererKey.MARKET to ::NativeListMarketRowView,
12
+ NativeListRendererKey.MESSAGE to ::NativeListMessageRowView,
13
+ NativeListRendererKey.RAIL to ::NativeListRailRowView,
14
+ NativeListRendererKey.MEDIA_TILE to ::NativeListMediaTileRowView,
15
+ NativeListRendererKey.METRIC_CARD to ::NativeListMetricCardRowView,
16
+ NativeListRendererKey.DATA_ROW to ::NativeListDataRowView,
17
+ NativeListRendererKey.ACTIVITY to ::NativeListActivityRowView,
18
+ NativeListRendererKey.SYSTEM to ::NativeListSystemRowView,
19
+ NativeListRendererKey.ACTION to ::NativeListActionRowView,
20
+ )
21
+
22
+ private val keys =
23
+ mapOf(
24
+ "sectionHeader" to NativeListRendererKey.SECTION_HEADER,
25
+ "walletGroup" to NativeListRendererKey.WALLET_GROUP,
26
+ "identity" to NativeListRendererKey.IDENTITY,
27
+ "market" to NativeListRendererKey.MARKET,
28
+ "message" to NativeListRendererKey.MESSAGE,
29
+ "rail" to NativeListRendererKey.RAIL,
30
+ "mediaTile" to NativeListRendererKey.MEDIA_TILE,
31
+ "metricCard" to NativeListRendererKey.METRIC_CARD,
32
+ "dataRow" to NativeListRendererKey.DATA_ROW,
33
+ "activity" to NativeListRendererKey.ACTIVITY,
34
+ "system" to NativeListRendererKey.SYSTEM,
35
+ "action" to NativeListRendererKey.ACTION,
36
+ )
37
+
38
+ fun key(type: String) = keys.getValue(type)
39
+
40
+ fun create(context: ThemedReactContext, viewType: Int): NativeListRowHost =
41
+ factories.getValue(NativeListRendererKey.entries[viewType])(context)
42
+ }