@onekeyfe/react-native-native-list 3.0.105
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 +342 -0
- package/android/CMakeLists.txt +20 -0
- package/android/build.gradle +105 -0
- package/android/gradle.properties +4 -0
- package/android/src/main/AndroidManifest.xml +1 -0
- package/android/src/main/cpp/cpp-adapter.cpp +6 -0
- package/android/src/main/java/com/onekey/nativelist/HybridNativeList.kt +125 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListAdapter.kt +165 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListModels.kt +147 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListPackage.kt +25 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRowView.kt +2939 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListView.kt +1794 -0
- package/common/fonts/Roobert-Bold.ttf +0 -0
- package/common/fonts/Roobert-Medium.ttf +0 -0
- package/common/fonts/Roobert-Regular.ttf +0 -0
- package/common/fonts/Roobert-SemiBold.ttf +0 -0
- package/docs/DESIGN.md +129 -0
- package/ios/HybridNativeList.swift +131 -0
- package/ios/NativeListCell.swift +2858 -0
- package/ios/NativeListDesignAssets.swift +110 -0
- package/ios/NativeListModels.swift +215 -0
- package/ios/RNCNativeListView.swift +1737 -0
- package/ios/Resources/NativeListIcons.xcassets/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_arrow_bottom.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_arrow_bottom.imageset/icon.svg +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_arrow_top.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_arrow_top.imageset/icon.svg +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_chart_trending_up.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_chart_trending_up.imageset/icon.svg +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_checkbox_checked.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_checkbox_checked.imageset/icon.svg +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_checkbox_indeterminate.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_checkbox_indeterminate.imageset/icon.svg +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_chevron_bottom.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_chevron_bottom.imageset/icon.svg +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_chevron_grabber_ver.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_chevron_grabber_ver.imageset/icon.svg +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_chevron_right_small.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_chevron_right_small.imageset/icon.svg +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_chevron_top.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_chevron_top.imageset/icon.svg +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_dot_hor.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_dot_hor.imageset/icon.svg +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_drag.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_drag.imageset/icon.svg +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_error_solid.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_error_solid.imageset/icon.svg +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_image_square_waves.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_image_square_waves.imageset/icon.svg +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_info_circle.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_info_circle.imageset/icon.svg +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_minus_circle.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_minus_circle.imageset/icon.svg +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_minus_circle_solid.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_minus_circle_solid.imageset/icon.svg +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_pencil.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_pencil.imageset/icon.svg +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_plus_circle.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_plus_circle.imageset/icon.svg +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_plus_small.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_plus_small.imageset/icon.svg +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_questionmark_solid.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_questionmark_solid.imageset/icon.svg +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_shield_exclamation.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_shield_exclamation.imageset/icon.svg +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_speaker_promote.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_speaker_promote.imageset/icon.svg +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_star.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_star.imageset/icon.svg +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_star_solid.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_star_solid.imageset/icon.svg +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_swap_hor.imageset/Contents.json +1 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_swap_hor.imageset/icon.svg +1 -0
- package/lib/module/NativeList.js +183 -0
- package/lib/module/NativeList.nitro.js +4 -0
- package/lib/module/NativeList.types.js +4 -0
- package/lib/module/NativeList.web.js +167 -0
- package/lib/module/index.js +6 -0
- package/lib/module/models.js +2 -0
- package/lib/module/package.json +1 -0
- package/lib/module/scrolling.js +121 -0
- package/lib/module/selection.js +85 -0
- package/lib/module/validation.js +562 -0
- package/lib/module/web/NativeListWebEngine.js +2238 -0
- package/lib/nitrogen/generated/.gitattributes +1 -0
- package/lib/nitrogen/generated/android/c++/JFunc_void_std__string.hpp +76 -0
- package/lib/nitrogen/generated/android/c++/JHybridNativeListSpec.cpp +201 -0
- package/lib/nitrogen/generated/android/c++/JHybridNativeListSpec.hpp +84 -0
- package/lib/nitrogen/generated/android/c++/JNativeListScrollAlignment.hpp +64 -0
- package/lib/nitrogen/generated/android/c++/views/JHybridNativeListStateUpdater.cpp +104 -0
- package/lib/nitrogen/generated/android/c++/views/JHybridNativeListStateUpdater.hpp +54 -0
- package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/Func_void_std__string.kt +78 -0
- package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/HybridNativeListSpec.kt +177 -0
- package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/NativeListScrollAlignment.kt +25 -0
- package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/nativelistOnLoad.kt +35 -0
- package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/views/HybridNativeListManager.kt +96 -0
- package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/views/HybridNativeListStateUpdater.kt +23 -0
- package/lib/nitrogen/generated/android/nativelist+autolinking.cmake +83 -0
- package/lib/nitrogen/generated/android/nativelist+autolinking.gradle +27 -0
- package/lib/nitrogen/generated/android/nativelistOnLoad.cpp +58 -0
- package/lib/nitrogen/generated/android/nativelistOnLoad.hpp +34 -0
- package/lib/nitrogen/generated/ios/NativeListModule+autolinking.rb +62 -0
- package/lib/nitrogen/generated/ios/NativeListModule-Swift-Cxx-Bridge.cpp +41 -0
- package/lib/nitrogen/generated/ios/NativeListModule-Swift-Cxx-Bridge.hpp +91 -0
- package/lib/nitrogen/generated/ios/NativeListModule-Swift-Cxx-Umbrella.hpp +49 -0
- package/lib/nitrogen/generated/ios/NativeListModuleAutolinking.mm +33 -0
- package/lib/nitrogen/generated/ios/NativeListModuleAutolinking.swift +26 -0
- package/lib/nitrogen/generated/ios/c++/HybridNativeListSpecSwift.cpp +11 -0
- package/lib/nitrogen/generated/ios/c++/HybridNativeListSpecSwift.hpp +180 -0
- package/lib/nitrogen/generated/ios/c++/views/HybridNativeListComponent.mm +180 -0
- package/lib/nitrogen/generated/ios/swift/Func_void_std__string.swift +46 -0
- package/lib/nitrogen/generated/ios/swift/HybridNativeListSpec.swift +69 -0
- package/lib/nitrogen/generated/ios/swift/HybridNativeListSpec_cxx.swift +447 -0
- package/lib/nitrogen/generated/ios/swift/NativeListScrollAlignment.swift +48 -0
- package/lib/nitrogen/generated/shared/c++/HybridNativeListSpec.cpp +43 -0
- package/lib/nitrogen/generated/shared/c++/HybridNativeListSpec.hpp +87 -0
- package/lib/nitrogen/generated/shared/c++/NativeListScrollAlignment.hpp +84 -0
- package/lib/nitrogen/generated/shared/c++/views/HybridNativeListComponent.cpp +46 -0
- package/lib/nitrogen/generated/shared/c++/views/HybridNativeListComponent.hpp +103 -0
- package/lib/nitrogen/generated/shared/json/NativeListConfig.json +16 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NativeList.d.ts +18 -0
- package/lib/typescript/src/NativeList.nitro.d.ts +29 -0
- package/lib/typescript/src/NativeList.types.d.ts +87 -0
- package/lib/typescript/src/NativeList.web.d.ts +19 -0
- package/lib/typescript/src/index.d.ts +7 -0
- package/lib/typescript/src/models.d.ts +456 -0
- package/lib/typescript/src/scrolling.d.ts +32 -0
- package/lib/typescript/src/selection.d.ts +27 -0
- package/lib/typescript/src/validation.d.ts +7 -0
- package/lib/typescript/src/web/NativeListWebEngine.d.ts +203 -0
- package/nitro.json +23 -0
- package/nitrogen/generated/.gitattributes +1 -0
- package/nitrogen/generated/android/c++/JFunc_void_std__string.hpp +76 -0
- package/nitrogen/generated/android/c++/JHybridNativeListSpec.cpp +201 -0
- package/nitrogen/generated/android/c++/JHybridNativeListSpec.hpp +84 -0
- package/nitrogen/generated/android/c++/JNativeListScrollAlignment.hpp +64 -0
- package/nitrogen/generated/android/c++/views/JHybridNativeListStateUpdater.cpp +104 -0
- package/nitrogen/generated/android/c++/views/JHybridNativeListStateUpdater.hpp +54 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/Func_void_std__string.kt +78 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/HybridNativeListSpec.kt +177 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/NativeListScrollAlignment.kt +25 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/nativelistOnLoad.kt +35 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/views/HybridNativeListManager.kt +96 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/views/HybridNativeListStateUpdater.kt +23 -0
- package/nitrogen/generated/android/nativelist+autolinking.cmake +83 -0
- package/nitrogen/generated/android/nativelist+autolinking.gradle +27 -0
- package/nitrogen/generated/android/nativelistOnLoad.cpp +58 -0
- package/nitrogen/generated/android/nativelistOnLoad.hpp +34 -0
- package/nitrogen/generated/ios/NativeListModule+autolinking.rb +62 -0
- package/nitrogen/generated/ios/NativeListModule-Swift-Cxx-Bridge.cpp +41 -0
- package/nitrogen/generated/ios/NativeListModule-Swift-Cxx-Bridge.hpp +91 -0
- package/nitrogen/generated/ios/NativeListModule-Swift-Cxx-Umbrella.hpp +49 -0
- package/nitrogen/generated/ios/NativeListModuleAutolinking.mm +33 -0
- package/nitrogen/generated/ios/NativeListModuleAutolinking.swift +26 -0
- package/nitrogen/generated/ios/c++/HybridNativeListSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridNativeListSpecSwift.hpp +180 -0
- package/nitrogen/generated/ios/c++/views/HybridNativeListComponent.mm +180 -0
- package/nitrogen/generated/ios/swift/Func_void_std__string.swift +46 -0
- package/nitrogen/generated/ios/swift/HybridNativeListSpec.swift +69 -0
- package/nitrogen/generated/ios/swift/HybridNativeListSpec_cxx.swift +447 -0
- package/nitrogen/generated/ios/swift/NativeListScrollAlignment.swift +48 -0
- package/nitrogen/generated/shared/c++/HybridNativeListSpec.cpp +43 -0
- package/nitrogen/generated/shared/c++/HybridNativeListSpec.hpp +87 -0
- package/nitrogen/generated/shared/c++/NativeListScrollAlignment.hpp +84 -0
- package/nitrogen/generated/shared/c++/views/HybridNativeListComponent.cpp +46 -0
- package/nitrogen/generated/shared/c++/views/HybridNativeListComponent.hpp +103 -0
- package/nitrogen/generated/shared/json/NativeListConfig.json +16 -0
- package/package.json +126 -0
- package/react-native-native-list.podspec +38 -0
- package/react-native.config.js +19 -0
- package/src/NativeList.nitro.ts +48 -0
- package/src/NativeList.tsx +298 -0
- package/src/NativeList.types.ts +125 -0
- package/src/NativeList.web.tsx +258 -0
- package/src/index.ts +35 -0
- package/src/models.ts +604 -0
- package/src/scrolling.ts +189 -0
- package/src/selection.ts +159 -0
- package/src/validation.ts +877 -0
- package/src/web/NativeListWebEngine.ts +3767 -0
package/README.md
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
# @onekeyfe/react-native-native-list
|
|
2
|
+
|
|
3
|
+
Nitro View, template-driven native list for React Native 0.86. iOS renders a
|
|
4
|
+
`UICollectionView`; Android renders a `RecyclerView`. JavaScript sends one
|
|
5
|
+
serializable snapshot or batch patch instead of mounting a React subtree for
|
|
6
|
+
every row.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
Keep NativeList and OneKeyImage on the same release because recycled image
|
|
11
|
+
slots use the native host exported by OneKeyImage.
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
yarn add @onekeyfe/react-native-native-list@3.0.101 \
|
|
15
|
+
@onekeyfe/react-native-image@3.0.101 \
|
|
16
|
+
react-native-nitro-modules@0.37.0
|
|
17
|
+
cd ios && pod install
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The package requires the React Native new architecture. Its deployment floors
|
|
21
|
+
are iOS 15.5 and Android API 24.
|
|
22
|
+
|
|
23
|
+
## Basic usage
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
import { useMemo, useRef, useState } from 'react';
|
|
27
|
+
import {
|
|
28
|
+
NativeList,
|
|
29
|
+
type NativeListRef,
|
|
30
|
+
type NativeListSnapshot,
|
|
31
|
+
type SelectionDeltaEvent,
|
|
32
|
+
} from '@onekeyfe/react-native-native-list';
|
|
33
|
+
|
|
34
|
+
export function AssetList() {
|
|
35
|
+
const listRef = useRef<NativeListRef>(null);
|
|
36
|
+
const [selectedKeys, setSelectedKeys] = useState<readonly string[]>([]);
|
|
37
|
+
const snapshot = useMemo<NativeListSnapshot>(
|
|
38
|
+
() => ({
|
|
39
|
+
schemaVersion: 1,
|
|
40
|
+
generation: 1,
|
|
41
|
+
layout: { kind: 'sectioned', stickyHeaders: true, itemSpacing: 1 },
|
|
42
|
+
selection: {
|
|
43
|
+
mode: 'multiple',
|
|
44
|
+
selectedKeys,
|
|
45
|
+
rowPressToggles: true,
|
|
46
|
+
},
|
|
47
|
+
rows: [
|
|
48
|
+
{
|
|
49
|
+
type: 'identity',
|
|
50
|
+
key: 'btc',
|
|
51
|
+
sectionKey: 'assets',
|
|
52
|
+
leading: {
|
|
53
|
+
kind: 'token',
|
|
54
|
+
image: {
|
|
55
|
+
uri: 'https://example.com/btc.png',
|
|
56
|
+
width: 40,
|
|
57
|
+
height: 40,
|
|
58
|
+
contentFit: 'cover',
|
|
59
|
+
cachePolicy: 'memory-disk',
|
|
60
|
+
},
|
|
61
|
+
fallbackText: 'BT',
|
|
62
|
+
},
|
|
63
|
+
title: 'Bitcoin',
|
|
64
|
+
subtitle: 'BTC · Bitcoin',
|
|
65
|
+
trailing: [
|
|
66
|
+
{ kind: 'value', text: '$64,230' },
|
|
67
|
+
{ kind: 'checkbox', state: 'unchecked', target: { scope: 'row' } },
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
}),
|
|
72
|
+
[selectedKeys]
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const handleSelection = (event: SelectionDeltaEvent) => {
|
|
76
|
+
setSelectedKeys((current) => {
|
|
77
|
+
const next = new Set(current);
|
|
78
|
+
event.removedKeys.forEach((key) => next.delete(key));
|
|
79
|
+
event.addedKeys.forEach((key) => next.add(key));
|
|
80
|
+
return [...next];
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<NativeList
|
|
86
|
+
ref={listRef}
|
|
87
|
+
style={{ flex: 1 }}
|
|
88
|
+
snapshot={snapshot}
|
|
89
|
+
onSelectionDelta={handleSelection}
|
|
90
|
+
onRowAction={({ rowKey, actionKey }) => {
|
|
91
|
+
console.log(rowKey, actionKey);
|
|
92
|
+
}}
|
|
93
|
+
/>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Native selection is authoritative for immediate feedback. Persist the emitted
|
|
99
|
+
delta in application state, then pass that state back in a later snapshot or
|
|
100
|
+
call `reconcileSelection(selectedKeys)` once. Reconciliation does not emit a
|
|
101
|
+
second delta.
|
|
102
|
+
|
|
103
|
+
## Row and layout model
|
|
104
|
+
|
|
105
|
+
`RowModel` is a strict discriminated union. It intentionally accepts no
|
|
106
|
+
`ReactNode`, render function, arbitrary style object, or native object handle.
|
|
107
|
+
|
|
108
|
+
| Row type | Intended template |
|
|
109
|
+
| --------------- | ---------------------------------------------------------- |
|
|
110
|
+
| `identity` | Asset, account, wallet, network, or settings identity |
|
|
111
|
+
| `rail` | Compact horizontal item with optional native drag support |
|
|
112
|
+
| `activity` | Transaction/activity with amounts and up to three actions |
|
|
113
|
+
| `message` | Notification/message with bounded body lines and thumbnail |
|
|
114
|
+
| `dataRow` | Two to four fixed table columns, optional index/checkbox |
|
|
115
|
+
| `mediaTile` | Gallery or browser-preview tile |
|
|
116
|
+
| `metricCard` | KPI or fixed Activity/Performance portfolio card |
|
|
117
|
+
| `sectionHeader` | Sticky/group, tri-state, or fixed list-summary header |
|
|
118
|
+
| `action` | Fixed action row or fixed footer |
|
|
119
|
+
| `system` | Loading, retry, end marker, or bounded spacer |
|
|
120
|
+
|
|
121
|
+
Snapshots support `linear`, `sectioned`, `grid`, and `table` layout semantics.
|
|
122
|
+
`linear` is a full-width row stream; `sectioned` gives section-header rows a
|
|
123
|
+
native visual break and optional pinning; `grid` uses two to four native spans
|
|
124
|
+
with structural rows spanning every column; and `table` uses compact,
|
|
125
|
+
alternating rows with stable weighted columns and column alignment. Vertical or
|
|
126
|
+
horizontal orientation, stable keys, grouped card geometry, empty state, and a
|
|
127
|
+
fixed footer remain common capabilities.
|
|
128
|
+
|
|
129
|
+
The required theme colors cover list, row, selection, text, separator, accent,
|
|
130
|
+
and semantic positive/negative states. The optional `subduedBackground`,
|
|
131
|
+
`strongBackground`, `disabledText`, `icon`, `iconSubdued`,
|
|
132
|
+
`criticalBackground`, `inverseBackground`, and `inverseText` tokens let native
|
|
133
|
+
templates match the OneKey palette without embedding platform-specific style
|
|
134
|
+
objects. Identity-row trailing accessories also accept semantic native icons,
|
|
135
|
+
for example `{ kind: 'icon', name: 'PlusCircleOutline' }`. A `valuePair` can
|
|
136
|
+
independently set `primaryTone` and `secondaryTone` to `primary`, `secondary`,
|
|
137
|
+
`positive`, or `negative`; omitted tones keep the original primary/secondary
|
|
138
|
+
defaults. Token visuals can provide `networkImage` or `cornerIcon`, while media
|
|
139
|
+
tiles can provide `networkImage`, to reproduce OneKey's bottom-right network
|
|
140
|
+
and token-state indicators. `dataRow` supports a two-line asset/volume and
|
|
141
|
+
price/change layout plus fixed leverage/venue badges. `metricCard` supports the
|
|
142
|
+
fixed `activity` and `performance` composite variants used by Portfolio & PnL;
|
|
143
|
+
their metrics and progress remain bounded serializable data.
|
|
144
|
+
|
|
145
|
+
Set a section header's `variant` to `summary` for the fixed 56-point list
|
|
146
|
+
summary template. Its optional `valueActionKey` renders a 16-point secondary
|
|
147
|
+
action beside the 16-point medium primary title; summary headers do not accept
|
|
148
|
+
a checkbox and do not become sticky.
|
|
149
|
+
|
|
150
|
+
For a native trailing section index, use a vertical `sectioned` layout, set
|
|
151
|
+
`capabilities.sectionIndex` to `{ enabled: true }`, and add an `indexTitle` to
|
|
152
|
+
each section header that should appear in the index. The index follows snapshot
|
|
153
|
+
order, skips headers without `indexTitle`, and scrolls to the header's existing
|
|
154
|
+
row `key`. Titles must be unique after Unicode NFC normalization, contain no
|
|
155
|
+
leading/trailing whitespace, and be at most eight Unicode code points. Set
|
|
156
|
+
`hapticsEnabled: false` to follow an application-level reduced-haptics setting.
|
|
157
|
+
The web implementation renders the same explicit index entries as a DOM
|
|
158
|
+
overlay, with click and pointer-drag navigation.
|
|
159
|
+
|
|
160
|
+
The native templates bundle OneKey's Roobert Regular, Medium, SemiBold, and
|
|
161
|
+
Bold faces and use them before the platform-font fallback. Their semantic
|
|
162
|
+
icons and checkbox marks are the same vector paths as the OneKey component
|
|
163
|
+
library, rendered by Core Graphics/UIKit on iOS and Canvas on Android.
|
|
164
|
+
|
|
165
|
+
For native reorder, set `capabilities.reorderable` and mark eligible rail rows
|
|
166
|
+
with `draggable: true`, or add a `drag` trailing accessory to an identity row.
|
|
167
|
+
Reordering never crosses a `sectionKey` boundary.
|
|
168
|
+
|
|
169
|
+
## OneKeyImage inside cells
|
|
170
|
+
|
|
171
|
+
Pass an `ImageSource` descriptor in the row model; do not pass a
|
|
172
|
+
`<OneKeyImage />` element:
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
const avatar = {
|
|
176
|
+
uri: 'https://example.com/avatar.webp',
|
|
177
|
+
width: 48,
|
|
178
|
+
height: 48,
|
|
179
|
+
headers: { Authorization: 'Bearer token' },
|
|
180
|
+
contentFit: 'cover',
|
|
181
|
+
cachePolicy: 'memory-disk',
|
|
182
|
+
autoplay: false,
|
|
183
|
+
optimizeTos: true,
|
|
184
|
+
overscan: 1.1,
|
|
185
|
+
loadingStrategy: 'static',
|
|
186
|
+
} as const;
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Each cell owns a fixed pool of native `OneKeyImageReusableView` slots. On bind,
|
|
190
|
+
NativeList forwards the URI, headers, content fit, cache policy, autoplay, TOS
|
|
191
|
+
options, overscan, and loading strategy. A stable `rowKey:slot` recycling key
|
|
192
|
+
is assigned automatically. Reuse cancels stale work before accepting the next
|
|
193
|
+
source, while retaining the same SDWebImage cache/pipeline on iOS and Glide
|
|
194
|
+
cache/pipeline on Android as `@onekeyfe/react-native-image`.
|
|
195
|
+
|
|
196
|
+
The fixed slots cover token/network overlays, two activity visuals, a message
|
|
197
|
+
thumbnail, and stacks of two or three images. Image width and height are
|
|
198
|
+
required and bounded to 1–4096 logical pixels.
|
|
199
|
+
|
|
200
|
+
## Batch updates and events
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
listRef.current?.applyPatches([
|
|
204
|
+
{
|
|
205
|
+
type: 'identity',
|
|
206
|
+
key: 'btc',
|
|
207
|
+
changes: { revision: 2, subtitle: 'Updated in one native command' },
|
|
208
|
+
},
|
|
209
|
+
]);
|
|
210
|
+
|
|
211
|
+
listRef.current?.scrollToKey('btc', true, 'center');
|
|
212
|
+
listRef.current?.scrollToIndex({
|
|
213
|
+
index: 24,
|
|
214
|
+
animated: true,
|
|
215
|
+
viewPosition: 0.5,
|
|
216
|
+
viewOffset: 12,
|
|
217
|
+
});
|
|
218
|
+
listRef.current?.scrollToItem({ item: snapshot.rows[24] });
|
|
219
|
+
listRef.current?.scrollToOffset({ offset: 320, animated: false });
|
|
220
|
+
listRef.current?.scrollToEnd({ animated: true });
|
|
221
|
+
listRef.current?.scrollToLocation({ sectionIndex: 2, itemIndex: 4 });
|
|
222
|
+
listRef.current?.setRefreshing(false);
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
The ref exposes `applySnapshot`, `applyPatches`, `reconcileSelection`,
|
|
226
|
+
`scrollToKey`, `scrollToIndex`, `scrollToItem`, `scrollToOffset`, `scrollToEnd`,
|
|
227
|
+
`scrollToLocation`, and `setRefreshing`. The legacy
|
|
228
|
+
`scrollToIndex(index, animated, alignment)` and
|
|
229
|
+
`scrollToKey(key, animated, alignment)` signatures remain supported. Object
|
|
230
|
+
parameters follow React Native list semantics: `viewPosition` is from `0`
|
|
231
|
+
(start) through `1` (end), and a positive `viewOffset` leaves space before the
|
|
232
|
+
target row.
|
|
233
|
+
|
|
234
|
+
Use `initialScrollIndex` or the stable-key extension `initialScrollKey` to set
|
|
235
|
+
the first position. They are mutually exclusive, run once after the first
|
|
236
|
+
snapshot and native layout are ready, and can be combined with
|
|
237
|
+
`initialScrollViewPosition` and `initialScrollViewOffset`. Invalid index and
|
|
238
|
+
location requests call `onScrollToIndexFailed`; native lists do not fail merely
|
|
239
|
+
because a target row has not been mounted yet. `scrollToLocation` counts
|
|
240
|
+
non-summary section headers, then rows carrying that header's `sectionKey`.
|
|
241
|
+
|
|
242
|
+
Patches are validated as a batch, keyed by row key, must preserve the row
|
|
243
|
+
discriminator, and are applied atomically. Prefer a new snapshot for insertions,
|
|
244
|
+
removals, layout changes, and section changes; use patches for frequently
|
|
245
|
+
changing fields.
|
|
246
|
+
|
|
247
|
+
Events are `onRowAction`, `onSelectionDelta`, `onReorder`, `onEndReached`,
|
|
248
|
+
`onVisibleRangeChanged`, and `onRefresh`. Visible-range events are coalesced to
|
|
249
|
+
one per display frame and only fire when the first or last visible item changes.
|
|
250
|
+
End-reached fires once per snapshot `generation`.
|
|
251
|
+
|
|
252
|
+
## Examples and performance checks
|
|
253
|
+
|
|
254
|
+
The React Native example application contains:
|
|
255
|
+
|
|
256
|
+
- **Native List**: a categorized entry page. Each of the four containers, ten
|
|
257
|
+
row templates, and checkbox selection opens its own source-labeled page; no
|
|
258
|
+
container or row paradigm is hidden behind tabs. The scenarios mirror the
|
|
259
|
+
corresponding list surfaces in the OneKey application.
|
|
260
|
+
- **Native List Benchmark**: reproducible 1,000/5,000-row load, fast scroll,
|
|
261
|
+
one-command 500-row patch, and one-command select-all paths.
|
|
262
|
+
- **Native List Account Selector**: two independently scrolling native lists
|
|
263
|
+
with a fixed Add Wallet footer. The stress fixture exposes 1,000 wallets x
|
|
264
|
+
1,000 accounts while materializing only the selected wallet's 1,000 account
|
|
265
|
+
rows and retaining at most three wallets / 3,000 account rows in an LRU cache.
|
|
266
|
+
|
|
267
|
+
### Account Selector performance snapshot (2026-09-05)
|
|
268
|
+
|
|
269
|
+
The current acceptance run exercised five page opens, two 101-switch Wallet 1 /
|
|
270
|
+
Wallet 2 batches, 25 downward plus 20 upward account-list drags, a repeated 15
|
|
271
|
+
downward account-list run, and 15 downward plus 15 upward wallet-list drags. It
|
|
272
|
+
also sampled process CPU and memory and verified, after momentum settled, that
|
|
273
|
+
the two lists scroll independently and Add Wallet remains fixed at the bottom.
|
|
274
|
+
Android additionally covered ART `speed` compilation and ten short fast flings.
|
|
275
|
+
|
|
276
|
+
| Metric | iOS Debug Simulator | Android Release-mode emulator |
|
|
277
|
+
| ------------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
278
|
+
| Environment | iPhone 16 Pro, iOS 18.6 | API 35 arm64, 1080 x 2400, fixed 60 Hz, non-debuggable Hermes |
|
|
279
|
+
| Page open, 5 runs | External tap-to-visible median 589 ms; the initial native visible-range callback did not emit | 5 / 5 native callbacks; mount-to-first-visible p50 110 ms; external observation p50 202 ms |
|
|
280
|
+
| Wallet switching | 202 / 202; mean 135.3 ms, p50 134 ms, p95 143 ms, max 159 ms | 202 / 202; mean 124.4 ms, p50 118 ms, p95 155 ms, max 213 ms |
|
|
281
|
+
| Account-list frame signal | 113.3 effective FPS; p50/p95 interval 6.67/18.33 ms; 6.6% over 17.5 ms | Repeated drag runs reported 92.09-93.06% deadline-missed frames and p50 450 ms |
|
|
282
|
+
| Wallet-list frame signal | 78.7 effective FPS; p50/p95 interval 13.33/20.00 ms; 17.8% over 17.5 ms | Down/up runs reported 89.39-100% deadline-missed frames and p50 400 ms |
|
|
283
|
+
| Process CPU | Wallet switching mean 48.9%; account scrolling mean 22.9% | Wallet switching mean 66.8%; account scrolling mean 67.1% on Android's per-core scale |
|
|
284
|
+
| Retained memory | Physical footprint 286 MB before, 275 MB after the first batch, 287 MB after the second; lifetime peak 335 MB | PSS 138,459 KiB with one wallet cached, 201,668 KiB after warming three wallets, 192,700 KiB after the second batch, 193,976 KiB after scrolling |
|
|
285
|
+
| Functional checks | Independent lists and fixed footer pass | Independent lists and fixed footer pass, including zero-difference stable screenshot crops |
|
|
286
|
+
|
|
287
|
+
Across the tested environments, Android Release is faster for page opening and
|
|
288
|
+
median wallet switching: external page-open p50 is 202 ms versus 589 ms on iOS,
|
|
289
|
+
and wallet-switch p50 is 118 ms versus 134 ms. iOS has the tighter switch tail
|
|
290
|
+
at p95 143 ms versus 155 ms, clearly leads both account-list and wallet-list
|
|
291
|
+
frame results, and uses less process CPU in the measured switch and scroll runs.
|
|
292
|
+
Both platforms pass correctness, independent scrolling, the fixed footer,
|
|
293
|
+
switch responsiveness, and the short-run retained-memory check. The current
|
|
294
|
+
cross-platform performance priority is Android continuous scrolling, followed
|
|
295
|
+
by the iOS wallet list's 120 Hz tail behavior.
|
|
296
|
+
|
|
297
|
+
### Test Suite source map
|
|
298
|
+
|
|
299
|
+
| Entry | OneKey application source |
|
|
300
|
+
| ------------------- | -------------------------------------------------------------------------------------------- |
|
|
301
|
+
| Linear container | `AssetList/components/TokenManager/TokenManagerList.tsx` |
|
|
302
|
+
| Sectioned container | `ChainSelector/components/AllNetworksManager/NetworksSectionList.tsx` |
|
|
303
|
+
| Grid container | `Home/components/NFTListView/index.tsx` |
|
|
304
|
+
| Table container | `Perp/components/TokenSelector/PerpTokenSelectorRow.tsx` |
|
|
305
|
+
| Identity rows | `Developer/pages/Gallery/Components/stories/ListItem.tsx` |
|
|
306
|
+
| Rail rows | `Perp/components/FavoritesBar/FavoriteTokenItem.tsx` |
|
|
307
|
+
| Activity rows | `components/TxHistoryListView/TxHistoryListItem.tsx` |
|
|
308
|
+
| Message rows | `Notifications/components/NotificationListView.tsx` |
|
|
309
|
+
| Data rows | `Perp/components/TokenSelector/PerpTokenSelectorRow.tsx` |
|
|
310
|
+
| Media tile rows | `Home/components/NFTListView/NFTListItem.tsx` |
|
|
311
|
+
| Metric card rows | `Perp/components/Portfolio/PerpPortfolioContent.tsx` |
|
|
312
|
+
| Section header rows | `AllNetworksManager/NetworksSectionList.tsx`, `TxHistoryListView/TxHistorySectionHeader.tsx` |
|
|
313
|
+
| Action rows | `TokenManager/TokenManagerList.tsx`, `Discovery/pages/BookmarkListModal/index.tsx` |
|
|
314
|
+
| System rows | `components/Loading/ListLoading.tsx`, `TokenListView/CrossNetworkSearchRows.tsx` |
|
|
315
|
+
| Checkbox selection | `components/forms/Checkbox/index.tsx`, `AllNetworksManager/NetworksSectionList.tsx` |
|
|
316
|
+
|
|
317
|
+
The checkbox page exercises list, section, and row targets plus checked,
|
|
318
|
+
unchecked, indeterminate, loading, and disabled presentation. The rail page
|
|
319
|
+
keeps horizontal selection and native reorder isolated from the other pages.
|
|
320
|
+
|
|
321
|
+
Measure a release build on a physical device. Run each scenario at least three
|
|
322
|
+
times, record cold and warm first-visible latency, JS batch-dispatch latency,
|
|
323
|
+
UI-thread frame time/dropped frames, and peak memory. During repeated fast
|
|
324
|
+
scrolls verify that no stale image from a recycled row becomes visible. The
|
|
325
|
+
benchmark page reports deterministic JS timings and visible-range milestones;
|
|
326
|
+
use Instruments or Android Studio Profiler for native frame and memory data.
|
|
327
|
+
|
|
328
|
+
## Limits
|
|
329
|
+
|
|
330
|
+
- Nitro View/new architecture only; no Paper component.
|
|
331
|
+
- Fixed templates only. Arbitrary children, per-row render functions, and
|
|
332
|
+
arbitrary style dictionaries are rejected by the public model.
|
|
333
|
+
- Template heights and text line counts are bounded. There is no unbounded
|
|
334
|
+
self-sizing content, nested list, or React component embedded in a cell.
|
|
335
|
+
- A snapshot prop is the declarative baseline. Re-rendering with an older
|
|
336
|
+
snapshot after imperative patches or reorder will intentionally restore the
|
|
337
|
+
older state.
|
|
338
|
+
- The web implementation uses a pure DOM, windowed, recycled row engine behind
|
|
339
|
+
the React component. It mirrors the mobile data and imperative APIs, but its
|
|
340
|
+
performance must still be measured independently from iOS and Android.
|
|
341
|
+
|
|
342
|
+
See [docs/DESIGN.md](docs/DESIGN.md) for the architecture and ownership model.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
project(nativelist)
|
|
2
|
+
cmake_minimum_required(VERSION 3.9.0)
|
|
3
|
+
|
|
4
|
+
set(PACKAGE_NAME nativelist)
|
|
5
|
+
set(CMAKE_VERBOSE_MAKEFILE ON)
|
|
6
|
+
set(CMAKE_CXX_STANDARD 20)
|
|
7
|
+
|
|
8
|
+
add_library(${PACKAGE_NAME} SHARED src/main/cpp/cpp-adapter.cpp)
|
|
9
|
+
|
|
10
|
+
include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/nativelist+autolinking.cmake)
|
|
11
|
+
|
|
12
|
+
include_directories("src/main/cpp")
|
|
13
|
+
|
|
14
|
+
find_library(LOG_LIB log)
|
|
15
|
+
|
|
16
|
+
target_link_libraries(
|
|
17
|
+
${PACKAGE_NAME}
|
|
18
|
+
${LOG_LIB}
|
|
19
|
+
android
|
|
20
|
+
)
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
buildscript {
|
|
2
|
+
ext.getExtOrDefault = { name ->
|
|
3
|
+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['NativeList_' + name]
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
def kotlinVersion = getExtOrDefault('kotlinVersion')
|
|
7
|
+
repositories {
|
|
8
|
+
google()
|
|
9
|
+
mavenCentral()
|
|
10
|
+
}
|
|
11
|
+
dependencies {
|
|
12
|
+
classpath "com.android.tools.build:gradle:8.7.2"
|
|
13
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
def reactNativeArchitectures() {
|
|
18
|
+
def value = rootProject.getProperties().get("reactNativeArchitectures")
|
|
19
|
+
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
apply plugin: "com.android.library"
|
|
23
|
+
apply plugin: "kotlin-android"
|
|
24
|
+
apply from: '../nitrogen/generated/android/nativelist+autolinking.gradle'
|
|
25
|
+
apply plugin: "com.facebook.react"
|
|
26
|
+
|
|
27
|
+
def getExtOrIntegerDefault(name) {
|
|
28
|
+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["NativeList_" + name].toInteger()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
android {
|
|
32
|
+
namespace "com.margelo.nitro.nativelist"
|
|
33
|
+
compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
|
|
34
|
+
|
|
35
|
+
defaultConfig {
|
|
36
|
+
minSdkVersion getExtOrIntegerDefault("minSdkVersion")
|
|
37
|
+
targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
|
|
38
|
+
|
|
39
|
+
externalNativeBuild {
|
|
40
|
+
cmake {
|
|
41
|
+
cppFlags "-frtti -fexceptions -Wall -fstack-protector-all"
|
|
42
|
+
arguments "-DANDROID_STL=c++_shared", "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
|
|
43
|
+
abiFilters (*reactNativeArchitectures())
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
externalNativeBuild {
|
|
49
|
+
cmake {
|
|
50
|
+
path "CMakeLists.txt"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
packagingOptions {
|
|
55
|
+
excludes = [
|
|
56
|
+
"META-INF", "META-INF/**", "**/libc++_shared.so", "**/libfbjni.so",
|
|
57
|
+
"**/libjsi.so", "**/libfolly_json.so", "**/libfolly_runtime.so",
|
|
58
|
+
"**/libglog.so", "**/libhermes.so", "**/libhermes_executor.so",
|
|
59
|
+
"**/libreactnative.so", "**/libreactnativejni.so"
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
buildFeatures {
|
|
64
|
+
buildConfig true
|
|
65
|
+
prefab true
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
buildTypes {
|
|
69
|
+
release {
|
|
70
|
+
minifyEnabled false
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
lintOptions {
|
|
75
|
+
disable "GradleCompatible"
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
compileOptions {
|
|
79
|
+
sourceCompatibility JavaVersion.VERSION_1_8
|
|
80
|
+
targetCompatibility JavaVersion.VERSION_1_8
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
sourceSets {
|
|
84
|
+
main {
|
|
85
|
+
java.srcDirs += ["generated/java", "generated/jni"]
|
|
86
|
+
assets.srcDirs += ["../common"]
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
repositories {
|
|
92
|
+
google()
|
|
93
|
+
mavenCentral()
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
def kotlinVersion = getExtOrDefault("kotlinVersion")
|
|
97
|
+
|
|
98
|
+
dependencies {
|
|
99
|
+
implementation "com.facebook.react:react-android"
|
|
100
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
|
|
101
|
+
implementation "androidx.recyclerview:recyclerview:1.4.0"
|
|
102
|
+
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
|
103
|
+
implementation project(":react-native-nitro-modules")
|
|
104
|
+
implementation project(":onekeyfe_react-native-image")
|
|
105
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android" />
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
package com.margelo.nitro.nativelist
|
|
2
|
+
|
|
3
|
+
import android.os.Looper
|
|
4
|
+
import android.view.View
|
|
5
|
+
import com.facebook.proguard.annotations.DoNotStrip
|
|
6
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
7
|
+
|
|
8
|
+
@DoNotStrip
|
|
9
|
+
class HybridNativeList(context: ThemedReactContext) : HybridNativeListSpec() {
|
|
10
|
+
private val hostView = NativeListView(context)
|
|
11
|
+
|
|
12
|
+
override val view: View = hostView
|
|
13
|
+
|
|
14
|
+
override var snapshotJson: String = ""
|
|
15
|
+
get() = field
|
|
16
|
+
set(value) {
|
|
17
|
+
if (field == value) return
|
|
18
|
+
field = value
|
|
19
|
+
dispatchToUi { hostView.applySnapshot(value) }
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
override var onRowAction: ((payloadJson: String) -> Unit)? = null
|
|
23
|
+
set(value) { field = value; hostView.onRowAction = value }
|
|
24
|
+
override var onActionAnchorInvalidated: ((payloadJson: String) -> Unit)? = null
|
|
25
|
+
set(value) { field = value; hostView.onActionAnchorInvalidated = value }
|
|
26
|
+
override var onSelectionDelta: ((payloadJson: String) -> Unit)? = null
|
|
27
|
+
set(value) { field = value; hostView.onSelectionDelta = value }
|
|
28
|
+
override var onReorder: ((payloadJson: String) -> Unit)? = null
|
|
29
|
+
set(value) { field = value; hostView.onReorder = value }
|
|
30
|
+
override var onEndReached: ((payloadJson: String) -> Unit)? = null
|
|
31
|
+
set(value) { field = value; hostView.onEndReached = value }
|
|
32
|
+
override var onVisibleRangeChanged: ((payloadJson: String) -> Unit)? = null
|
|
33
|
+
set(value) { field = value; hostView.onVisibleRangeChanged = value }
|
|
34
|
+
|
|
35
|
+
override fun applySnapshot(snapshotJson: String) {
|
|
36
|
+
dispatchToUi { hostView.applySnapshot(snapshotJson) }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
override fun applyPatches(patchesJson: String) {
|
|
40
|
+
dispatchToUi { hostView.applyPatches(patchesJson) }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
override fun reconcileSelection(selectedKeysJson: String) {
|
|
44
|
+
dispatchToUi { hostView.reconcileSelection(selectedKeysJson) }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
override fun scrollToKey(
|
|
48
|
+
key: String,
|
|
49
|
+
animated: Boolean,
|
|
50
|
+
alignment: NativeListScrollAlignment,
|
|
51
|
+
viewPosition: Double,
|
|
52
|
+
viewOffset: Double,
|
|
53
|
+
) {
|
|
54
|
+
dispatchToUi {
|
|
55
|
+
hostView.scrollToKey(
|
|
56
|
+
key,
|
|
57
|
+
animated,
|
|
58
|
+
alignment.stringValue(),
|
|
59
|
+
viewPosition,
|
|
60
|
+
viewOffset,
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
override fun scrollToIndex(
|
|
66
|
+
index: Double,
|
|
67
|
+
animated: Boolean,
|
|
68
|
+
alignment: NativeListScrollAlignment,
|
|
69
|
+
viewPosition: Double,
|
|
70
|
+
viewOffset: Double,
|
|
71
|
+
) {
|
|
72
|
+
if (!index.isFinite() || index < 0 || index % 1.0 != 0.0 || index > Int.MAX_VALUE) return
|
|
73
|
+
dispatchToUi {
|
|
74
|
+
hostView.scrollToIndex(
|
|
75
|
+
index.toInt(),
|
|
76
|
+
animated,
|
|
77
|
+
alignment.stringValue(),
|
|
78
|
+
viewPosition,
|
|
79
|
+
viewOffset,
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
override fun scrollToOffset(offset: Double, animated: Boolean) {
|
|
85
|
+
if (!offset.isFinite() || offset < 0) return
|
|
86
|
+
dispatchToUi { hostView.scrollToOffset(offset, animated) }
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
override fun scrollToEnd(animated: Boolean) {
|
|
90
|
+
dispatchToUi { hostView.scrollToEnd(animated) }
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
override fun setActionAnchorState(stateJson: String) {
|
|
94
|
+
dispatchToUi { hostView.setActionAnchorState(stateJson) }
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
override fun setRefreshing(refreshing: Boolean) {
|
|
98
|
+
dispatchToUi { hostView.setRefreshing(refreshing) }
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
override fun onDropView() {
|
|
102
|
+
hostView.dispose()
|
|
103
|
+
super.onDropView()
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
override fun dispose() {
|
|
107
|
+
hostView.dispose()
|
|
108
|
+
super.dispose()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Nitro prop setters can run off the Android UI thread. Apply synchronously
|
|
113
|
+
* during a UI commit; only off-main calls need to be posted to this host.
|
|
114
|
+
*/
|
|
115
|
+
private fun dispatchToUi(action: () -> Unit) {
|
|
116
|
+
if (Looper.myLooper() == Looper.getMainLooper()) action() else hostView.post(action)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private fun NativeListScrollAlignment.stringValue(): String = when (this) {
|
|
120
|
+
NativeListScrollAlignment.START -> "start"
|
|
121
|
+
NativeListScrollAlignment.CENTER -> "center"
|
|
122
|
+
NativeListScrollAlignment.END -> "end"
|
|
123
|
+
NativeListScrollAlignment.NEAREST -> "nearest"
|
|
124
|
+
}
|
|
125
|
+
}
|