@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.
- package/README.md +21 -5
- package/android/src/main/java/com/onekey/nativelist/NativeListAccessoryStack.kt +711 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListActionRenderer.kt +169 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListActivityRenderer.kt +243 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListAdapter.kt +20 -6
- package/android/src/main/java/com/onekey/nativelist/NativeListDataRowRenderer.kt +487 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListIdentityRenderer.kt +820 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListImageSlot.kt +147 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListLeadingVisual.kt +453 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListMarketRenderer.kt +997 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListMediaTileRenderer.kt +234 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListMessageRenderer.kt +232 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListMetricCardRenderer.kt +551 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListModels.kt +24 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListPrimitives.kt +475 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRailRenderer.kt +143 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRendererRegistry.kt +42 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRendererRowView.kt +415 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListResolvedText.kt +163 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRowHost.kt +70 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListSectionHeaderRenderer.kt +748 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListSystemRenderer.kt +464 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListTextView.kt +25 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListView.kt +174 -104
- package/android/src/main/java/com/onekey/nativelist/NativeListWalletGroupRenderer.kt +407 -0
- package/android/src/test/java/com/margelo/nitro/nativelist/NativeListSelectorBackgroundColorTest.kt +34 -0
- package/docs/DESIGN.md +518 -9
- package/docs/MIGRATION_BASELINE.md +117 -0
- package/docs/ROW_TEMPLATES.md +359 -0
- package/docs/SPEC.md +358 -0
- package/docs/STYLE_SPEC.md +978 -0
- package/docs/images/list-capabilities.svg +39 -0
- package/docs/images/row-action.svg +17 -0
- package/docs/images/row-activity.svg +24 -0
- package/docs/images/row-data.svg +24 -0
- package/docs/images/row-identity.svg +25 -0
- package/docs/images/row-market.svg +23 -0
- package/docs/images/row-media-tile.svg +26 -0
- package/docs/images/row-message.svg +20 -0
- package/docs/images/row-metric-card.svg +33 -0
- package/docs/images/row-rail.svg +18 -0
- package/docs/images/row-section-header.svg +19 -0
- package/docs/images/row-style-regions.svg +30 -0
- package/docs/images/row-system.svg +30 -0
- package/docs/images/row-wallet-group.svg +26 -0
- package/ios/NativeListAccessoryStack.swift +680 -0
- package/ios/NativeListActionRenderer.swift +108 -0
- package/ios/NativeListActivityRenderer.swift +179 -0
- package/ios/NativeListDataRowRenderer.swift +444 -0
- package/ios/NativeListIdentityRenderer.swift +685 -0
- package/ios/NativeListImageSlot.swift +140 -0
- package/ios/NativeListLeadingVisual.swift +372 -0
- package/ios/NativeListMarketRenderer.swift +698 -0
- package/ios/NativeListMediaTileRenderer.swift +184 -0
- package/ios/NativeListMessageRenderer.swift +168 -0
- package/ios/NativeListMetricCardRenderer.swift +420 -0
- package/ios/NativeListModels.swift +32 -0
- package/ios/NativeListRailRenderer.swift +152 -0
- package/ios/NativeListRendererCell.swift +311 -0
- package/ios/NativeListRendererRegistry.swift +50 -0
- package/ios/NativeListResolvedText.swift +122 -0
- package/ios/NativeListRowHost.swift +63 -0
- package/ios/NativeListSectionHeaderRenderer.swift +708 -0
- package/ios/NativeListSystemRenderer.swift +568 -0
- package/ios/NativeListTextLabel.swift +42 -0
- package/ios/NativeListTextStyles.swift +236 -0
- package/ios/NativeListWalletGroupRenderer.swift +255 -0
- package/ios/RNCNativeListView.swift +111 -180
- package/lib/module/models.js +54 -0
- package/lib/module/validation.js +324 -26
- package/lib/module/web/NativeListWebEngine.js +148 -936
- package/lib/module/web/templates/ActionRowRenderer.js +97 -0
- package/lib/module/web/templates/ActivityRowRenderer.js +95 -0
- package/lib/module/web/templates/DataRowRenderer.js +145 -0
- package/lib/module/web/templates/IdentityRowRenderer.js +289 -0
- package/lib/module/web/templates/MarketRowRenderer.js +310 -0
- package/lib/module/web/templates/MediaTileRowRenderer.js +132 -0
- package/lib/module/web/templates/MessageRowRenderer.js +165 -0
- package/lib/module/web/templates/MetricCardRowRenderer.js +172 -0
- package/lib/module/web/templates/RailRowRenderer.js +98 -0
- package/lib/module/web/templates/RowContainerStyle.js +100 -0
- package/lib/module/web/templates/RowElements.js +93 -0
- package/lib/module/web/templates/RowRendererRegistry.js +70 -0
- package/lib/module/web/templates/RowText.js +121 -0
- package/lib/module/web/templates/RowVisual.js +43 -0
- package/lib/module/web/templates/SectionHeaderRowRenderer.js +146 -0
- package/lib/module/web/templates/SystemRowRenderer.js +161 -0
- package/lib/module/web/templates/WalletGroupRowRenderer.js +96 -0
- package/lib/typescript/src/models.d.ts +166 -13
- package/lib/typescript/src/web/NativeListWebEngine.d.ts +18 -16
- package/lib/typescript/src/web/templates/ActionRowRenderer.d.ts +15 -0
- package/lib/typescript/src/web/templates/ActivityRowRenderer.d.ts +15 -0
- package/lib/typescript/src/web/templates/DataRowRenderer.d.ts +15 -0
- package/lib/typescript/src/web/templates/IdentityRowRenderer.d.ts +16 -0
- package/lib/typescript/src/web/templates/MarketRowRenderer.d.ts +30 -0
- package/lib/typescript/src/web/templates/MediaTileRowRenderer.d.ts +15 -0
- package/lib/typescript/src/web/templates/MessageRowRenderer.d.ts +44 -0
- package/lib/typescript/src/web/templates/MetricCardRowRenderer.d.ts +15 -0
- package/lib/typescript/src/web/templates/RailRowRenderer.d.ts +28 -0
- package/lib/typescript/src/web/templates/RowContainerStyle.d.ts +9 -0
- package/lib/typescript/src/web/templates/RowElements.d.ts +38 -0
- package/lib/typescript/src/web/templates/RowRendererRegistry.d.ts +83 -0
- package/lib/typescript/src/web/templates/RowText.d.ts +9 -0
- package/lib/typescript/src/web/templates/RowVisual.d.ts +20 -0
- package/lib/typescript/src/web/templates/SectionHeaderRowRenderer.d.ts +15 -0
- package/lib/typescript/src/web/templates/SystemRowRenderer.d.ts +16 -0
- package/lib/typescript/src/web/templates/WalletGroupRowRenderer.d.ts +20 -0
- package/package.json +3 -3
- package/src/models.ts +281 -19
- package/src/validation.ts +501 -46
- package/src/web/NativeListWebEngine.ts +361 -1932
- package/src/web/templates/ActionRowRenderer.ts +123 -0
- package/src/web/templates/ActivityRowRenderer.ts +159 -0
- package/src/web/templates/DataRowRenderer.ts +212 -0
- package/src/web/templates/IdentityRowRenderer.ts +527 -0
- package/src/web/templates/MarketRowRenderer.ts +467 -0
- package/src/web/templates/MediaTileRowRenderer.ts +182 -0
- package/src/web/templates/MessageRowRenderer.ts +306 -0
- package/src/web/templates/MetricCardRowRenderer.ts +337 -0
- package/src/web/templates/RailRowRenderer.ts +136 -0
- package/src/web/templates/RowContainerStyle.ts +131 -0
- package/src/web/templates/RowElements.ts +160 -0
- package/src/web/templates/RowRendererRegistry.ts +111 -0
- package/src/web/templates/RowText.ts +181 -0
- package/src/web/templates/RowVisual.ts +115 -0
- package/src/web/templates/SectionHeaderRowRenderer.ts +243 -0
- package/src/web/templates/SystemRowRenderer.ts +282 -0
- package/src/web/templates/WalletGroupRowRenderer.ts +131 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRowView.kt +0 -4538
- package/ios/NativeListCell.swift +0 -4300
|
@@ -226,12 +226,69 @@ class NativeListView(
|
|
|
226
226
|
mass = REORDER_SPRING_MASS,
|
|
227
227
|
durationSeconds = REORDER_SPRING_DURATION_MS / 1_000.0,
|
|
228
228
|
)
|
|
229
|
-
private
|
|
229
|
+
private var footerView: NativeListRowHost = NativeListRendererRegistry.create(reactContext, NativeListRendererKey.ACTION.ordinal)
|
|
230
|
+
private var footerRendererKey = NativeListRendererKey.ACTION
|
|
230
231
|
private val sectionIndexView = NativeListSectionIndexView(context)
|
|
231
232
|
private val sectionIndexPreview = TextView(context)
|
|
232
233
|
private var config: NativeListConfig? = null
|
|
233
234
|
private var usesSelectorSourceScale = false
|
|
234
|
-
private
|
|
235
|
+
private val stickyHeaderView = NativeListRendererRegistry.create(reactContext, NativeListRendererKey.SECTION_HEADER.ordinal)
|
|
236
|
+
private var stickyHeaderSignature: String? = null
|
|
237
|
+
private var stickyHeaderConfig: NativeListConfig? = null
|
|
238
|
+
private val stickyHeaderHost = object : FrameLayout(reactContext) {
|
|
239
|
+
private var down: MotionEvent? = null
|
|
240
|
+
private var forwarding = false
|
|
241
|
+
|
|
242
|
+
private fun forward(event: MotionEvent) {
|
|
243
|
+
val copy = MotionEvent.obtain(event)
|
|
244
|
+
copy.offsetLocation(x - refreshLayout.x - recyclerView.x, y - refreshLayout.y - recyclerView.y)
|
|
245
|
+
recyclerView.dispatchTouchEvent(copy)
|
|
246
|
+
copy.recycle()
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
|
|
250
|
+
when (event.actionMasked) {
|
|
251
|
+
MotionEvent.ACTION_DOWN -> { down?.recycle(); down = MotionEvent.obtain(event); forwarding = false }
|
|
252
|
+
MotionEvent.ACTION_MOVE -> {
|
|
253
|
+
val initial = down
|
|
254
|
+
if (initial != null && kotlin.math.abs(event.y - initial.y) > pagerGestureTouchSlop) {
|
|
255
|
+
startForwarding(initial, event)
|
|
256
|
+
return true
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { down?.recycle(); down = null }
|
|
260
|
+
}
|
|
261
|
+
return false
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// The intercepting MOVE is not redelivered to onTouchEvent, so forward it
|
|
265
|
+
// together with the initial DOWN to keep the list's drag continuous.
|
|
266
|
+
private fun startForwarding(initial: MotionEvent, event: MotionEvent) {
|
|
267
|
+
forward(initial)
|
|
268
|
+
forward(event)
|
|
269
|
+
forwarding = true
|
|
270
|
+
parent?.requestDisallowInterceptTouchEvent(true)
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
override fun onTouchEvent(event: MotionEvent): Boolean {
|
|
274
|
+
if (!forwarding) return super.onTouchEvent(event)
|
|
275
|
+
forward(event)
|
|
276
|
+
if (event.actionMasked == MotionEvent.ACTION_UP || event.actionMasked == MotionEvent.ACTION_CANCEL) {
|
|
277
|
+
forwarding = false
|
|
278
|
+
down?.recycle(); down = null
|
|
279
|
+
}
|
|
280
|
+
return true
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
override fun onDetachedFromWindow() { down?.recycle(); down = null; super.onDetachedFromWindow() }
|
|
284
|
+
}
|
|
285
|
+
private val stickyPreDraw = android.view.ViewTreeObserver.OnPreDrawListener {
|
|
286
|
+
updateStickyHeader()
|
|
287
|
+
true
|
|
288
|
+
}
|
|
289
|
+
// Registered only while attached, on the captured window observer, so detach
|
|
290
|
+
// removes the same instance the listener was merged into.
|
|
291
|
+
private var stickyObservedTree: ViewTreeObserver? = null
|
|
235
292
|
private var spacingDecoration: ItemSpacingDecoration? = null
|
|
236
293
|
private var itemTouchHelper: ItemTouchHelper? = null
|
|
237
294
|
private var reorderTouchListener: RecyclerView.OnItemTouchListener? = null
|
|
@@ -307,6 +364,9 @@ class NativeListView(
|
|
|
307
364
|
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
308
365
|
),
|
|
309
366
|
)
|
|
367
|
+
stickyHeaderHost.visibility = GONE
|
|
368
|
+
stickyHeaderHost.addView(stickyHeaderView, FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT))
|
|
369
|
+
contentContainer.addView(stickyHeaderHost, FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.TOP))
|
|
310
370
|
contentContainer.addView(
|
|
311
371
|
sectionIndexView,
|
|
312
372
|
FrameLayout.LayoutParams(
|
|
@@ -342,6 +402,9 @@ class NativeListView(
|
|
|
342
402
|
adapter.onAction = ::handleAction
|
|
343
403
|
adapter.onBindingInvalidated = ::handleBindingInvalidated
|
|
344
404
|
adapter.checkboxState = ::resolveCheckboxState
|
|
405
|
+
stickyHeaderView.onRowPress = ::handleRowPress
|
|
406
|
+
stickyHeaderView.onAction = ::handleAction
|
|
407
|
+
stickyHeaderView.onBindingInvalidated = ::handleBindingInvalidated
|
|
345
408
|
footerView.onRowPress = ::handleRowPress
|
|
346
409
|
footerView.onAction = ::handleAction
|
|
347
410
|
footerView.onBindingInvalidated = ::handleBindingInvalidated
|
|
@@ -459,6 +522,7 @@ class NativeListView(
|
|
|
459
522
|
|
|
460
523
|
override fun onAttachedToWindow() {
|
|
461
524
|
super.onAttachedToWindow()
|
|
525
|
+
startStickyHeaderTracking()
|
|
462
526
|
updateSectionIndexAttachment()
|
|
463
527
|
val first = config?.items?.firstOrNull()
|
|
464
528
|
if (recyclerView.isLayoutRequested && (first?.type == "market" || first?.json?.optString("presentation") == "market")) {
|
|
@@ -467,6 +531,7 @@ class NativeListView(
|
|
|
467
531
|
}
|
|
468
532
|
|
|
469
533
|
override fun onDetachedFromWindow() {
|
|
534
|
+
stopStickyHeaderTracking()
|
|
470
535
|
stopSectionIndexAttachmentTracking()
|
|
471
536
|
scheduleSectionIndexAttachmentToList()
|
|
472
537
|
updateRefreshIndicatorOffset(0)
|
|
@@ -500,9 +565,13 @@ class NativeListView(
|
|
|
500
565
|
usesSelectorSourceScale = next.items.any { it.usesSelectorSourceScale }
|
|
501
566
|
adapter.usesSelectorSourceScale = usesSelectorSourceScale
|
|
502
567
|
adapter.theme = next.theme
|
|
568
|
+
adapter.listStyle = next.listStyle
|
|
503
569
|
adapter.layout = next.layout
|
|
504
570
|
adapter.orientation = next.orientation
|
|
505
571
|
adapter.selectedKeys = next.selectedKeys
|
|
572
|
+
// Rows rebind through the adapter's listStyle invalidation; the fixed footer is bound
|
|
573
|
+
// outside the adapter, so a listStyle-only snapshot must rebind it here.
|
|
574
|
+
if (previous.listStyle?.toString() != next.listStyle?.toString()) bindFooter(next)
|
|
506
575
|
adapter.submitList(next.items) {
|
|
507
576
|
// OneKey patch: DiffUtil has dispatched its payloads; release the old serialized rows.
|
|
508
577
|
next.items.forEach { it.selectionUpdateFromContent = null }
|
|
@@ -535,6 +604,7 @@ class NativeListView(
|
|
|
535
604
|
if (previous?.generation != next.generation) endReachedGeneration = null
|
|
536
605
|
pendingReorder = null
|
|
537
606
|
adapter.theme = next.theme
|
|
607
|
+
adapter.listStyle = next.listStyle
|
|
538
608
|
adapter.layout = next.layout
|
|
539
609
|
adapter.orientation = next.orientation
|
|
540
610
|
adapter.selectedKeys = next.selectedKeys
|
|
@@ -1119,6 +1189,9 @@ class NativeListView(
|
|
|
1119
1189
|
itemTouchHelper = null
|
|
1120
1190
|
footerView.recycle()
|
|
1121
1191
|
footerView.dispose()
|
|
1192
|
+
stopStickyHeaderTracking()
|
|
1193
|
+
stickyHeaderView.dispose()
|
|
1194
|
+
stickyHeaderHost.visibility = GONE
|
|
1122
1195
|
recyclerView.swapAdapter(null, false)
|
|
1123
1196
|
adapter.dispose()
|
|
1124
1197
|
}
|
|
@@ -1151,10 +1224,63 @@ class NativeListView(
|
|
|
1151
1224
|
|
|
1152
1225
|
spacingDecoration?.let(recyclerView::removeItemDecoration)
|
|
1153
1226
|
spacingDecoration = ItemSpacingDecoration(dp(next.itemSpacing), next.itemSpacing, density).also(recyclerView::addItemDecoration)
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1227
|
+
stickyHeaderSignature = null
|
|
1228
|
+
if (!next.stickyHeaders || orientation != RecyclerView.VERTICAL) stickyHeaderHost.visibility = GONE
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
private fun updateStickyHeader() {
|
|
1232
|
+
val current = config
|
|
1233
|
+
if (current == null || !current.stickyHeaders || layoutManager.orientation != RecyclerView.VERTICAL || recyclerView.width <= 0) {
|
|
1234
|
+
stickyHeaderHost.visibility = GONE
|
|
1235
|
+
return
|
|
1236
|
+
}
|
|
1237
|
+
val first = layoutManager.findFirstVisibleItemPosition()
|
|
1238
|
+
var position = first
|
|
1239
|
+
while (position >= 0 && adapter.itemAt(position)?.let(::isStickySectionHeader) != true) position--
|
|
1240
|
+
val item = adapter.itemAt(position)
|
|
1241
|
+
if (item == null || first == RecyclerView.NO_POSITION || (layoutManager.findViewByPosition(position)?.top ?: -1) > 0) {
|
|
1242
|
+
stickyHeaderHost.visibility = GONE
|
|
1243
|
+
return
|
|
1244
|
+
}
|
|
1245
|
+
val width = recyclerView.width - recyclerView.paddingLeft - recyclerView.paddingRight
|
|
1246
|
+
if (width <= 0) {
|
|
1247
|
+
stickyHeaderHost.visibility = GONE
|
|
1248
|
+
return
|
|
1249
|
+
}
|
|
1250
|
+
val signature = "${item.content}:$width:${recyclerView.layoutDirection}:$usesSelectorSourceScale"
|
|
1251
|
+
if (stickyHeaderConfig !== current || stickyHeaderSignature != signature) {
|
|
1252
|
+
stickyHeaderConfig = current
|
|
1253
|
+
stickyHeaderSignature = signature
|
|
1254
|
+
stickyHeaderView.listStyle = current.listStyle
|
|
1255
|
+
stickyHeaderView.bind(item, current.theme, current.layout, current.orientation, position,
|
|
1256
|
+
item.json.optBoolean("selected", false) || current.selectedKeys.contains(item.key), ::resolveCheckboxState,
|
|
1257
|
+
useSourceScale = usesSelectorSourceScale)
|
|
1258
|
+
stickyHeaderView.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED))
|
|
1259
|
+
stickyHeaderHost.layoutParams = (stickyHeaderHost.layoutParams as FrameLayout.LayoutParams).apply {
|
|
1260
|
+
this.width = width
|
|
1261
|
+
height = stickyHeaderView.measuredHeight
|
|
1262
|
+
leftMargin = recyclerView.paddingLeft
|
|
1263
|
+
rightMargin = recyclerView.paddingRight
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
val height = stickyHeaderView.measuredHeight
|
|
1267
|
+
var nextTop = Int.MAX_VALUE
|
|
1268
|
+
for (index in 0 until recyclerView.childCount) {
|
|
1269
|
+
val child = recyclerView.getChildAt(index)
|
|
1270
|
+
val childPosition = recyclerView.getChildAdapterPosition(child)
|
|
1271
|
+
if (childPosition > position && adapter.itemAt(childPosition)?.let(::isStickySectionHeader) == true) nextTop = minOf(nextTop, child.top)
|
|
1272
|
+
}
|
|
1273
|
+
stickyHeaderHost.translationY = minOf(0, nextTop - height).toFloat()
|
|
1274
|
+
stickyHeaderHost.visibility = VISIBLE
|
|
1275
|
+
// React Native can retain the measured parent while this overlay becomes
|
|
1276
|
+
// visible in pre-draw. Lay out the container-owned header immediately.
|
|
1277
|
+
if (stickyHeaderHost.isLayoutRequested || stickyHeaderHost.width != width || stickyHeaderHost.height != height) {
|
|
1278
|
+
stickyHeaderHost.measure(
|
|
1279
|
+
View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
|
|
1280
|
+
View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY),
|
|
1281
|
+
)
|
|
1282
|
+
stickyHeaderHost.layout(recyclerView.paddingLeft, 0, recyclerView.paddingLeft + width, height)
|
|
1283
|
+
}
|
|
1158
1284
|
}
|
|
1159
1285
|
|
|
1160
1286
|
private fun configureSectionIndex(next: NativeListConfig) {
|
|
@@ -1264,6 +1390,20 @@ class NativeListView(
|
|
|
1264
1390
|
}
|
|
1265
1391
|
}
|
|
1266
1392
|
|
|
1393
|
+
private fun startStickyHeaderTracking() {
|
|
1394
|
+
if (resourcesDisposed) return
|
|
1395
|
+
val observer = viewTreeObserver
|
|
1396
|
+
if (stickyObservedTree === observer) return
|
|
1397
|
+
stopStickyHeaderTracking()
|
|
1398
|
+
observer.addOnPreDrawListener(stickyPreDraw)
|
|
1399
|
+
stickyObservedTree = observer
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
private fun stopStickyHeaderTracking() {
|
|
1403
|
+
stickyObservedTree?.takeIf(ViewTreeObserver::isAlive)?.removeOnPreDrawListener(stickyPreDraw)
|
|
1404
|
+
stickyObservedTree = null
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1267
1407
|
private fun startSectionIndexAttachmentTracking() {
|
|
1268
1408
|
val observer = viewTreeObserver
|
|
1269
1409
|
if (sectionIndexObservedTree === observer) return
|
|
@@ -1380,7 +1520,21 @@ class NativeListView(
|
|
|
1380
1520
|
footerView.visibility = GONE
|
|
1381
1521
|
footerView.recycle()
|
|
1382
1522
|
} else {
|
|
1523
|
+
if (footer.rendererKey != footerRendererKey) {
|
|
1524
|
+
val previous = footerView
|
|
1525
|
+
val position = indexOfChild(previous)
|
|
1526
|
+
previous.recycle()
|
|
1527
|
+
previous.dispose()
|
|
1528
|
+
footerView = NativeListRendererRegistry.create(reactContext, footer.rendererKey.ordinal)
|
|
1529
|
+
footerView.onRowPress = ::handleRowPress
|
|
1530
|
+
footerView.onAction = ::handleAction
|
|
1531
|
+
footerView.onBindingInvalidated = ::handleBindingInvalidated
|
|
1532
|
+
removeView(previous)
|
|
1533
|
+
addView(footerView, position, previous.layoutParams)
|
|
1534
|
+
footerRendererKey = footer.rendererKey
|
|
1535
|
+
}
|
|
1383
1536
|
footerView.visibility = VISIBLE
|
|
1537
|
+
footerView.listStyle = next.listStyle
|
|
1384
1538
|
footerView.bind(
|
|
1385
1539
|
footer,
|
|
1386
1540
|
next.theme,
|
|
@@ -1490,7 +1644,7 @@ class NativeListView(
|
|
|
1490
1644
|
return false
|
|
1491
1645
|
}
|
|
1492
1646
|
|
|
1493
|
-
private fun handleBindingInvalidated(row:
|
|
1647
|
+
private fun handleBindingInvalidated(row: NativeListRowHost, epoch: Long) {
|
|
1494
1648
|
val anchor = actionAnchor ?: return
|
|
1495
1649
|
if (anchor.ownerRowView.get() === row && anchor.bindingEpoch == epoch) {
|
|
1496
1650
|
invalidateActionAnchor("rebind")
|
|
@@ -2593,109 +2747,18 @@ private class ItemSpacingDecoration(
|
|
|
2593
2747
|
if (spacing <= 0) return
|
|
2594
2748
|
val horizontal = (parent.layoutManager as? LinearLayoutManager)?.orientation == RecyclerView.HORIZONTAL
|
|
2595
2749
|
val item = view.tag as? NativeListItem
|
|
2596
|
-
val sourceWallet = item?.type == "identity" && item.json.optString("presentation") == "walletSidebar" && item.
|
|
2750
|
+
val sourceWallet = item?.type == "identity" && item.json.optString("presentation") == "walletSidebar" && item.hasExplicitHeight
|
|
2597
2751
|
// OneKey patch: V1 measures the wallet and its bottom padding as one sortable row.
|
|
2598
2752
|
val itemSpacing = if (!horizontal && sourceWallet) {
|
|
2599
|
-
val sourceHeight = item!!.json.
|
|
2753
|
+
val sourceHeight = item!!.styledHeight ?: item.json.optDouble("height")
|
|
2600
2754
|
((sourceHeight + sourceSpacing) * density).roundToInt() - (sourceHeight * density).roundToInt()
|
|
2601
2755
|
} else spacing
|
|
2602
2756
|
if (horizontal) outRect.right = itemSpacing else outRect.bottom = itemSpacing
|
|
2603
2757
|
}
|
|
2604
2758
|
}
|
|
2605
2759
|
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
private val context: android.content.Context,
|
|
2609
|
-
theme: JSONObject?,
|
|
2610
|
-
private val density: Float,
|
|
2611
|
-
) : RecyclerView.ItemDecoration() {
|
|
2612
|
-
private val backgroundPaint = Paint().apply {
|
|
2613
|
-
color = parseColor(theme?.optString("rowBackground"), "#FFFFFF")
|
|
2614
|
-
}
|
|
2615
|
-
private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
|
2616
|
-
color = parseColor(theme?.optString("secondaryText"), "#0000009B")
|
|
2617
|
-
textSize = NativeListScale.font(context.resources, 14f) * density
|
|
2618
|
-
typeface = NativeListFonts.semibold(context)
|
|
2619
|
-
}
|
|
2620
|
-
|
|
2621
|
-
override fun onDrawOver(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {
|
|
2622
|
-
val manager = parent.layoutManager as? LinearLayoutManager ?: return
|
|
2623
|
-
val first = manager.findFirstVisibleItemPosition()
|
|
2624
|
-
if (first == RecyclerView.NO_POSITION) return
|
|
2625
|
-
var header: NativeListItem? = null
|
|
2626
|
-
for (index in first downTo 0) {
|
|
2627
|
-
val candidate = adapter.itemAt(index)
|
|
2628
|
-
if (candidate?.type == "sectionHeader") {
|
|
2629
|
-
if (candidate.json.optString("variant") == "summary" || !candidate.json.optBoolean("sticky", true)) continue
|
|
2630
|
-
header = candidate.takeIf(::isSimpleStickySectionHeader)
|
|
2631
|
-
break
|
|
2632
|
-
}
|
|
2633
|
-
}
|
|
2634
|
-
val item = header ?: return
|
|
2635
|
-
// OneKey patch: a pinned selector heading must use the same text rasterization as its row.
|
|
2636
|
-
textPaint.flags = if (item.usesSelectorSourceScale) Paint.ANTI_ALIAS_FLAG or Paint.SUBPIXEL_TEXT_FLAG or Paint.LINEAR_TEXT_FLAG else Paint.ANTI_ALIAS_FLAG
|
|
2637
|
-
val isHistory = item.json.optString("variant") == "history" ||
|
|
2638
|
-
item.sectionKey?.startsWith("history-") == true
|
|
2639
|
-
val sourceHeight = item.json.optInt("height", 36) * density
|
|
2640
|
-
val height = if (item.usesSelectorSourceScale) {
|
|
2641
|
-
if (item.json.optString("heightRounding") == "nearest") sourceHeight.roundToInt() else sourceHeight.toInt()
|
|
2642
|
-
} else NativeListScale.dp(context.resources, if (isHistory) 16 else 36)
|
|
2643
|
-
val textSize = if (item.usesSelectorSourceScale) 14f else NativeListScale.font(context.resources, if (isHistory) 12f else 14f)
|
|
2644
|
-
textPaint.textSize = if (item.usesSelectorSourceScale) kotlin.math.ceil((textSize * density).toDouble()).toFloat() else textSize * density
|
|
2645
|
-
val horizontalInset = if (item.usesSelectorSourceScale) ((20 * density).toInt() - parent.paddingLeft).toFloat() else NativeListScale.dp(context.resources, if (isHistory) 8 else 20).toFloat()
|
|
2646
|
-
val left = parent.paddingLeft.toFloat()
|
|
2647
|
-
val right = (parent.width - parent.paddingRight).toFloat()
|
|
2648
|
-
canvas.drawRect(left, 0f, right, height.toFloat(), backgroundPaint)
|
|
2649
|
-
val baseline = if (item.usesSelectorSourceScale) {
|
|
2650
|
-
val metrics = textPaint.fontMetricsInt
|
|
2651
|
-
val lineHeight = kotlin.math.ceil(20 * density.toDouble()).toInt()
|
|
2652
|
-
val leading = lineHeight - (metrics.descent - metrics.ascent)
|
|
2653
|
-
(height - lineHeight) / 2 - metrics.ascent + kotlin.math.ceil(leading / 2.0).toFloat()
|
|
2654
|
-
} else height / 2f - (textPaint.descent() + textPaint.ascent()) / 2f
|
|
2655
|
-
val value = item.json.optString("title").let { if (isHistory) it.uppercase() else it }
|
|
2656
|
-
val isRightToLeft = parent.layoutDirection == View.LAYOUT_DIRECTION_RTL
|
|
2657
|
-
val textWidth = if (isHistory) {
|
|
2658
|
-
spacedTextWidth(value, NativeListScale.dp(context.resources, 1).toFloat())
|
|
2659
|
-
} else {
|
|
2660
|
-
textPaint.measureText(value)
|
|
2661
|
-
}
|
|
2662
|
-
val x = if (isRightToLeft) right - horizontalInset - textWidth else left + horizontalInset
|
|
2663
|
-
if (isHistory) {
|
|
2664
|
-
drawSpacedText(canvas, value, x, baseline, NativeListScale.dp(context.resources, 1).toFloat())
|
|
2665
|
-
} else {
|
|
2666
|
-
canvas.drawText(value, x, baseline, textPaint)
|
|
2667
|
-
}
|
|
2668
|
-
}
|
|
2669
|
-
|
|
2670
|
-
private fun drawSpacedText(canvas: Canvas, value: String, x: Float, baseline: Float, spacing: Float) {
|
|
2671
|
-
var cursor = x
|
|
2672
|
-
value.forEachIndexed { index, character ->
|
|
2673
|
-
val glyph = character.toString()
|
|
2674
|
-
canvas.drawText(glyph, cursor, baseline, textPaint)
|
|
2675
|
-
cursor += textPaint.measureText(glyph)
|
|
2676
|
-
if (index < value.lastIndex) cursor += spacing * 0.8f
|
|
2677
|
-
}
|
|
2678
|
-
}
|
|
2679
|
-
|
|
2680
|
-
private fun spacedTextWidth(value: String, spacing: Float): Float =
|
|
2681
|
-
value.sumOf { textPaint.measureText(it.toString()).toDouble() }.toFloat() +
|
|
2682
|
-
max(0, value.length - 1) * spacing * 0.8f
|
|
2683
|
-
|
|
2684
|
-
companion object {
|
|
2685
|
-
private fun parseColor(value: String?, fallback: String): Int = try {
|
|
2686
|
-
parseNativeListColor(if (value.isNullOrEmpty()) fallback else value)
|
|
2687
|
-
} catch (_: IllegalArgumentException) {
|
|
2688
|
-
parseNativeListColor(fallback)
|
|
2689
|
-
}
|
|
2690
|
-
}
|
|
2691
|
-
}
|
|
2692
|
-
|
|
2693
|
-
internal fun isSimpleStickySectionHeader(item: NativeListItem): Boolean =
|
|
2694
|
-
item.type == "sectionHeader" &&
|
|
2695
|
-
item.json.optBoolean("sticky", true) &&
|
|
2696
|
-
item.json.optString("variant") != "summary" &&
|
|
2697
|
-
item.json.optString("value").isEmpty() &&
|
|
2698
|
-
item.json.optJSONObject("checkbox") == null
|
|
2760
|
+
internal fun isStickySectionHeader(item: NativeListItem): Boolean =
|
|
2761
|
+
item.type == "sectionHeader" && item.json.optBoolean("sticky", true) && item.json.optString("variant") != "summary"
|
|
2699
2762
|
|
|
2700
2763
|
// OneKey patch: paint only explicitly requested backgrounds into list side padding.
|
|
2701
2764
|
private class SelectorBackgroundDecoration(private val adapter: NativeListAdapter) : RecyclerView.ItemDecoration() {
|
|
@@ -2705,9 +2768,16 @@ private class SelectorBackgroundDecoration(private val adapter: NativeListAdapte
|
|
|
2705
2768
|
val child = parent.getChildAt(index)
|
|
2706
2769
|
val item = adapter.itemAt(parent.getChildAdapterPosition(child)) ?: continue
|
|
2707
2770
|
if (!item.json.optBoolean("backgroundFullWidth", false)) continue
|
|
2708
|
-
val color =
|
|
2709
|
-
|
|
2771
|
+
val color = resolveNativeListSelectorBackgroundColor(
|
|
2772
|
+
rowType = item.type,
|
|
2773
|
+
styleBackgroundColor = item.json.optJSONObject("style")
|
|
2774
|
+
?.optJSONObject("container")
|
|
2775
|
+
?.optString("backgroundColor"),
|
|
2776
|
+
rowBackgroundColor = item.json.optString("backgroundColor"),
|
|
2777
|
+
) ?: continue
|
|
2710
2778
|
paint.color = try { parseNativeListColor(color) } catch (_: IllegalArgumentException) { Color.TRANSPARENT }
|
|
2779
|
+
val opacity = item.json.optJSONObject("style")?.optJSONObject("container")?.optDouble("opacity", item.json.optDouble("opacity", 1.0)) ?: item.json.optDouble("opacity", 1.0)
|
|
2780
|
+
paint.alpha = (Color.alpha(paint.color) * opacity * (if (item.json.optBoolean("disabled", false)) 0.5 else 1.0)).toInt()
|
|
2711
2781
|
val top = child.y
|
|
2712
2782
|
canvas.drawRect(0f, top, parent.width.toFloat(), top + child.height, paint)
|
|
2713
2783
|
if (item.type == "system" && item.json.optString("variant") == "warning") {
|