@onekeyfe/react-native-native-list 3.0.134 → 3.0.135
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/android/build.gradle +1 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListModels.kt +33 -3
- package/android/src/main/java/com/onekey/nativelist/NativeListRowView.kt +5 -0
- package/android/src/test/java/com/margelo/nitro/nativelist/NativeListPressPolicyTest.kt +43 -0
- package/ios/RNCNativeListView.swift +31 -3
- package/package.json +3 -3
package/android/build.gradle
CHANGED
|
@@ -3,6 +3,25 @@ package com.margelo.nitro.nativelist
|
|
|
3
3
|
import org.json.JSONArray
|
|
4
4
|
import org.json.JSONObject
|
|
5
5
|
|
|
6
|
+
internal fun isNativeListRowPressEnabled(
|
|
7
|
+
type: String,
|
|
8
|
+
variant: String,
|
|
9
|
+
disabled: Boolean,
|
|
10
|
+
pressDisabled: Boolean,
|
|
11
|
+
): Boolean = !disabled && !pressDisabled && (type != "system" || variant == "retry")
|
|
12
|
+
|
|
13
|
+
internal fun isNativeListWholeRowInteractive(
|
|
14
|
+
type: String,
|
|
15
|
+
variant: String,
|
|
16
|
+
disabled: Boolean,
|
|
17
|
+
pressDisabled: Boolean,
|
|
18
|
+
): Boolean = type != "walletGroup" && isNativeListRowPressEnabled(
|
|
19
|
+
type = type,
|
|
20
|
+
variant = variant,
|
|
21
|
+
disabled = disabled,
|
|
22
|
+
pressDisabled = pressDisabled,
|
|
23
|
+
)
|
|
24
|
+
|
|
6
25
|
internal data class NativeListItem(
|
|
7
26
|
val key: String,
|
|
8
27
|
val type: String,
|
|
@@ -22,9 +41,20 @@ internal data class NativeListItem(
|
|
|
22
41
|
get() = !json.optBoolean("disabled", false) && type in SELECTABLE_TYPES
|
|
23
42
|
|
|
24
43
|
val isRowPressEnabled: Boolean
|
|
25
|
-
get() =
|
|
26
|
-
|
|
27
|
-
|
|
44
|
+
get() = isNativeListRowPressEnabled(
|
|
45
|
+
type = type,
|
|
46
|
+
variant = json.optString("variant"),
|
|
47
|
+
disabled = json.optBoolean("disabled", false),
|
|
48
|
+
pressDisabled = json.optBoolean("pressDisabled", false),
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
val isWholeRowInteractive: Boolean
|
|
52
|
+
get() = isNativeListWholeRowInteractive(
|
|
53
|
+
type = type,
|
|
54
|
+
variant = json.optString("variant"),
|
|
55
|
+
disabled = json.optBoolean("disabled", false),
|
|
56
|
+
pressDisabled = json.optBoolean("pressDisabled", false),
|
|
57
|
+
)
|
|
28
58
|
|
|
29
59
|
val isReorderable: Boolean
|
|
30
60
|
get() {
|
|
@@ -985,6 +985,11 @@ internal class NativeListRowView(
|
|
|
985
985
|
"action" -> bindAction(item, theme, checkboxState)
|
|
986
986
|
"system" -> bindSystem(item, theme)
|
|
987
987
|
}
|
|
988
|
+
// Keep passive rows out of accessibility and keyboard focus while allowing
|
|
989
|
+
// their independently bound accessory controls to remain interactive.
|
|
990
|
+
val wholeRowPressEnabled = item.isWholeRowInteractive
|
|
991
|
+
isClickable = wholeRowPressEnabled
|
|
992
|
+
isFocusable = wholeRowPressEnabled
|
|
988
993
|
applySize(item)
|
|
989
994
|
if (item.type == "system" && item.json.optString("variant") == "warning") {
|
|
990
995
|
title.typeface = NativeListFonts.medium(context)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
package com.margelo.nitro.nativelist
|
|
2
|
+
|
|
3
|
+
import org.junit.Assert.assertEquals
|
|
4
|
+
import org.junit.Test
|
|
5
|
+
|
|
6
|
+
class NativeListPressPolicyTest {
|
|
7
|
+
@Test
|
|
8
|
+
fun wholeRowInteractionMatchesPassiveAndAccessoryOnlyRows() {
|
|
9
|
+
data class Case(
|
|
10
|
+
val type: String,
|
|
11
|
+
val variant: String = "",
|
|
12
|
+
val disabled: Boolean = false,
|
|
13
|
+
val pressDisabled: Boolean = false,
|
|
14
|
+
val expected: Boolean,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
val cases = listOf(
|
|
18
|
+
Case(type = "identity", expected = true),
|
|
19
|
+
Case(type = "identity", pressDisabled = true, expected = false),
|
|
20
|
+
Case(type = "identity", disabled = true, expected = false),
|
|
21
|
+
Case(type = "system", variant = "retry", expected = true),
|
|
22
|
+
Case(type = "system", variant = "retry", pressDisabled = true, expected = false),
|
|
23
|
+
Case(type = "system", variant = "loading", expected = false),
|
|
24
|
+
Case(type = "system", variant = "noMatch", expected = false),
|
|
25
|
+
Case(type = "system", variant = "warning", expected = false),
|
|
26
|
+
Case(type = "system", variant = "end", expected = false),
|
|
27
|
+
Case(type = "system", variant = "spacer", expected = false),
|
|
28
|
+
Case(type = "walletGroup", expected = false),
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
assertEquals(
|
|
32
|
+
cases.map(Case::expected),
|
|
33
|
+
cases.map { case ->
|
|
34
|
+
isNativeListWholeRowInteractive(
|
|
35
|
+
type = case.type,
|
|
36
|
+
variant = case.variant,
|
|
37
|
+
disabled = case.disabled,
|
|
38
|
+
pressDisabled = case.pressDisabled,
|
|
39
|
+
)
|
|
40
|
+
},
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -115,6 +115,7 @@ final class NativeListView: UIView {
|
|
|
115
115
|
private let reorderStartFeedback = UIImpactFeedbackGenerator(style: .medium)
|
|
116
116
|
private let reorderMoveFeedback = UISelectionFeedbackGenerator()
|
|
117
117
|
private var interactiveReorderFeedbackIndex: Int?
|
|
118
|
+
private var interactiveMovementKeys: [String]?
|
|
118
119
|
private var actionAnchor: ActionAnchorRecord?
|
|
119
120
|
private let actionAnchorInstanceID = UUID().uuidString
|
|
120
121
|
private var actionAnchorCounter = 0
|
|
@@ -731,6 +732,9 @@ final class NativeListView: UIView {
|
|
|
731
732
|
collectionView.layoutIfNeeded()
|
|
732
733
|
return
|
|
733
734
|
}
|
|
735
|
+
if !interactiveReorderUsesAtomicTargeting {
|
|
736
|
+
interactiveMovementKeys = dataSource.snapshot().itemIdentifiers
|
|
737
|
+
}
|
|
734
738
|
interactiveReorderFeedbackIndex = indexPath.item
|
|
735
739
|
reorderStartFeedback.impactOccurred(intensity: 0.7)
|
|
736
740
|
reorderStartFeedback.prepare()
|
|
@@ -838,9 +842,11 @@ final class NativeListView: UIView {
|
|
|
838
842
|
interactiveReorderAnimator?.stopAnimation(true)
|
|
839
843
|
interactiveReorderFeedbackIndex = nil
|
|
840
844
|
if cancelled {
|
|
845
|
+
interactiveMovementKeys = nil
|
|
841
846
|
collectionView.cancelInteractiveMovement()
|
|
842
847
|
} else {
|
|
843
848
|
collectionView.endInteractiveMovement()
|
|
849
|
+
interactiveMovementKeys = nil
|
|
844
850
|
}
|
|
845
851
|
let animator = UIViewPropertyAnimator(
|
|
846
852
|
duration: ReorderAnimation.duration,
|
|
@@ -874,6 +880,7 @@ final class NativeListView: UIView {
|
|
|
874
880
|
guard interactiveReorderSource != nil else { return }
|
|
875
881
|
interactiveReorderAnimator?.stopAnimation(true)
|
|
876
882
|
interactiveReorderAnimator = nil
|
|
883
|
+
interactiveMovementKeys = nil
|
|
877
884
|
collectionView.cancelInteractiveMovement()
|
|
878
885
|
interactiveReorderCell?.setPressed(false)
|
|
879
886
|
if interactiveReorderCompactKey != nil {
|
|
@@ -978,6 +985,23 @@ final class NativeListView: UIView {
|
|
|
978
985
|
return collectionView.cellForItem(at: IndexPath(item: index, section: 0)) as? NativeListCell
|
|
979
986
|
}
|
|
980
987
|
|
|
988
|
+
// OneKey patch: flow layout sizes an interactive move in UIKit's in-flight order,
|
|
989
|
+
// while the diffable snapshot and cell index paths keep the pre-drag order until
|
|
990
|
+
// the move commits. Resolving sizes from the snapshot swaps row heights.
|
|
991
|
+
private func layoutItem(at indexPath: IndexPath) -> NativeListItem? {
|
|
992
|
+
guard let keys = interactiveMovementKeys else { return item(at: indexPath) }
|
|
993
|
+
return keys[safe: indexPath.item].flatMap { itemsByKey[$0] }
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
private func updateInteractiveMovementKeys(movingFrom source: IndexPath, to target: IndexPath) {
|
|
997
|
+
guard interactiveMovementKeys != nil else { return }
|
|
998
|
+
var keys = dataSource.snapshot().itemIdentifiers
|
|
999
|
+
guard keys.indices.contains(source.item) else { return }
|
|
1000
|
+
let key = keys.remove(at: source.item)
|
|
1001
|
+
keys.insert(key, at: min(max(target.item, 0), keys.count))
|
|
1002
|
+
interactiveMovementKeys = keys
|
|
1003
|
+
}
|
|
1004
|
+
|
|
981
1005
|
private func item(at indexPath: IndexPath) -> NativeListItem? {
|
|
982
1006
|
if let key = dataSource.itemIdentifier(for: indexPath), let item = itemsByKey[key] {
|
|
983
1007
|
return item
|
|
@@ -2049,7 +2073,9 @@ extension NativeListView: UICollectionViewDelegateFlowLayout {
|
|
|
2049
2073
|
atCurrentIndexPath currentIndexPath: IndexPath,
|
|
2050
2074
|
toProposedIndexPath proposedIndexPath: IndexPath
|
|
2051
2075
|
) -> IndexPath {
|
|
2052
|
-
interactiveReorderUsesAtomicTargeting
|
|
2076
|
+
guard !interactiveReorderUsesAtomicTargeting else { return currentIndexPath }
|
|
2077
|
+
updateInteractiveMovementKeys(movingFrom: originalIndexPath, to: proposedIndexPath)
|
|
2078
|
+
return proposedIndexPath
|
|
2053
2079
|
}
|
|
2054
2080
|
|
|
2055
2081
|
func collectionView(
|
|
@@ -2057,7 +2083,9 @@ extension NativeListView: UICollectionViewDelegateFlowLayout {
|
|
|
2057
2083
|
targetIndexPathForMoveFromItemAt originalIndexPath: IndexPath,
|
|
2058
2084
|
toProposedIndexPath proposedIndexPath: IndexPath
|
|
2059
2085
|
) -> IndexPath {
|
|
2060
|
-
interactiveReorderUsesAtomicTargeting
|
|
2086
|
+
guard !interactiveReorderUsesAtomicTargeting else { return originalIndexPath }
|
|
2087
|
+
updateInteractiveMovementKeys(movingFrom: originalIndexPath, to: proposedIndexPath)
|
|
2088
|
+
return proposedIndexPath
|
|
2061
2089
|
}
|
|
2062
2090
|
|
|
2063
2091
|
func collectionView(
|
|
@@ -2065,7 +2093,7 @@ extension NativeListView: UICollectionViewDelegateFlowLayout {
|
|
|
2065
2093
|
layout collectionViewLayout: UICollectionViewLayout,
|
|
2066
2094
|
sizeForItemAt indexPath: IndexPath
|
|
2067
2095
|
) -> CGSize {
|
|
2068
|
-
guard let config, let item =
|
|
2096
|
+
guard let config, let item = layoutItem(at: indexPath) else { return .zero }
|
|
2069
2097
|
let insets = flowLayout.sectionInset
|
|
2070
2098
|
if config.orientation == "horizontal" {
|
|
2071
2099
|
let width: CGFloat = item.type == "rail" ? railWidth(item) : item.type == "mediaTile" ? 200 : 280
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/react-native-native-list",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.135",
|
|
4
4
|
"description": "Template-driven native RecyclerView and UICollectionView for React Native",
|
|
5
5
|
"source": "./src/index.ts",
|
|
6
6
|
"main": "./lib/module/index.js",
|
|
@@ -83,8 +83,8 @@
|
|
|
83
83
|
"typescript": "^5.9.2"
|
|
84
84
|
},
|
|
85
85
|
"peerDependencies": {
|
|
86
|
-
"@onekeyfe/react-native-image": "3.0.
|
|
87
|
-
"@onekeyfe/react-native-native-logger": "3.0.
|
|
86
|
+
"@onekeyfe/react-native-image": "3.0.135",
|
|
87
|
+
"@onekeyfe/react-native-native-logger": "3.0.135",
|
|
88
88
|
"react": "*",
|
|
89
89
|
"react-native": "*",
|
|
90
90
|
"react-native-nitro-modules": "0.37.0"
|