@onekeyfe/react-native-native-list 3.0.136 → 3.0.137
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/src/main/java/com/onekey/nativelist/NativeListModels.kt +25 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRowView.kt +6 -3
- package/android/src/test/java/com/margelo/nitro/nativelist/NativeListSourceFallbackStateKeyTest.kt +43 -0
- package/ios/NativeListCell.swift +19 -10
- package/lib/module/web/NativeListWebEngine.js +4 -2
- package/package.json +3 -3
- package/src/web/NativeListWebEngine.ts +4 -2
|
@@ -2,6 +2,9 @@ package com.margelo.nitro.nativelist
|
|
|
2
2
|
|
|
3
3
|
import org.json.JSONArray
|
|
4
4
|
import org.json.JSONObject
|
|
5
|
+
import java.nio.ByteBuffer
|
|
6
|
+
import java.security.MessageDigest
|
|
7
|
+
import java.util.Locale
|
|
5
8
|
|
|
6
9
|
internal fun isNativeListRowPressEnabled(
|
|
7
10
|
type: String,
|
|
@@ -22,6 +25,28 @@ internal fun isNativeListWholeRowInteractive(
|
|
|
22
25
|
pressDisabled = pressDisabled,
|
|
23
26
|
)
|
|
24
27
|
|
|
28
|
+
// The image fallback-state cache is process-wide, so it is keyed by a digest of the request
|
|
29
|
+
// identity instead of the raw headers, which can carry credentials such as Authorization.
|
|
30
|
+
internal fun nativeListSourceFallbackStateKey(uri: String, headers: Map<String, String>): String? {
|
|
31
|
+
val trimmedUri = uri.trim().takeIf(String::isNotEmpty) ?: return null
|
|
32
|
+
val digest = MessageDigest.getInstance("SHA-256")
|
|
33
|
+
updateLengthPrefixed(digest, trimmedUri)
|
|
34
|
+
headers.entries
|
|
35
|
+
.map { it.key.lowercase(Locale.ROOT) to it.value }
|
|
36
|
+
.sortedWith(compareBy<Pair<String, String>>({ it.first }, { it.second }))
|
|
37
|
+
.forEach { (name, value) ->
|
|
38
|
+
updateLengthPrefixed(digest, name)
|
|
39
|
+
updateLengthPrefixed(digest, value)
|
|
40
|
+
}
|
|
41
|
+
return digest.digest().joinToString("") { "%02x".format(Locale.ROOT, it.toInt() and 0xff) }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private fun updateLengthPrefixed(digest: MessageDigest, value: String) {
|
|
45
|
+
val bytes = value.toByteArray(Charsets.UTF_8)
|
|
46
|
+
digest.update(ByteBuffer.allocate(Int.SIZE_BYTES).putInt(bytes.size).array())
|
|
47
|
+
digest.update(bytes)
|
|
48
|
+
}
|
|
49
|
+
|
|
25
50
|
internal data class NativeListItem(
|
|
26
51
|
val key: String,
|
|
27
52
|
val type: String,
|
|
@@ -3538,9 +3538,12 @@ internal class NativeListRowView(
|
|
|
3538
3538
|
}
|
|
3539
3539
|
|
|
3540
3540
|
private fun sourceFallbackStateKey(source: JSONObject): String? =
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3541
|
+
nativeListSourceFallbackStateKey(
|
|
3542
|
+
uri = source.optString("uri"),
|
|
3543
|
+
headers = source.optJSONObject("headers")?.let { headers ->
|
|
3544
|
+
headers.keys().asSequence().associateWith { headers.optString(it) }
|
|
3545
|
+
}.orEmpty(),
|
|
3546
|
+
)
|
|
3544
3547
|
|
|
3545
3548
|
private fun leadingImageLayout(
|
|
3546
3549
|
index: Int,
|
package/android/src/test/java/com/margelo/nitro/nativelist/NativeListSourceFallbackStateKeyTest.kt
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
package com.margelo.nitro.nativelist
|
|
2
|
+
|
|
3
|
+
import org.junit.Assert.assertEquals
|
|
4
|
+
import org.junit.Assert.assertFalse
|
|
5
|
+
import org.junit.Assert.assertNull
|
|
6
|
+
import org.junit.Assert.assertTrue
|
|
7
|
+
import org.junit.Test
|
|
8
|
+
|
|
9
|
+
class NativeListSourceFallbackStateKeyTest {
|
|
10
|
+
private val uri = "https://example.com/token.png"
|
|
11
|
+
|
|
12
|
+
@Test
|
|
13
|
+
fun keyIsADigestThatDoesNotRetainHeaderValues() {
|
|
14
|
+
val key = nativeListSourceFallbackStateKey(uri, mapOf("Authorization" to "Bearer secret-token"))
|
|
15
|
+
|
|
16
|
+
assertTrue(key.orEmpty().matches(Regex("[0-9a-f]{64}")))
|
|
17
|
+
assertFalse(key.orEmpty().contains("secret-token"))
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@Test
|
|
21
|
+
fun keyIgnoresHeaderOrderAndNameCase() {
|
|
22
|
+
assertEquals(
|
|
23
|
+
nativeListSourceFallbackStateKey(uri, linkedMapOf("Authorization" to "Bearer a", "X-Trace" to "1")),
|
|
24
|
+
nativeListSourceFallbackStateKey(uri, linkedMapOf("x-trace" to "1", "authorization" to "Bearer a")),
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@Test
|
|
29
|
+
fun keyDistinguishesSourcesThatDifferOnlyByHeaders() {
|
|
30
|
+
val keys = listOf(
|
|
31
|
+
nativeListSourceFallbackStateKey(uri, emptyMap()),
|
|
32
|
+
nativeListSourceFallbackStateKey(uri, mapOf("Authorization" to "Bearer a")),
|
|
33
|
+
nativeListSourceFallbackStateKey(uri, mapOf("Authorization" to "Bearer b")),
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
assertEquals(keys.size, keys.toSet().size)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@Test
|
|
40
|
+
fun blankUriHasNoKey() {
|
|
41
|
+
assertNull(nativeListSourceFallbackStateKey(" ", mapOf("Authorization" to "Bearer a")))
|
|
42
|
+
}
|
|
43
|
+
}
|
package/ios/NativeListCell.swift
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Foundation
|
|
2
2
|
// OneKey patch: preserve native font faces while enabling tabular number features.
|
|
3
3
|
import CoreText
|
|
4
|
+
import CryptoKit
|
|
4
5
|
import OneKeyImage
|
|
5
6
|
import UIKit
|
|
6
7
|
|
|
@@ -3694,15 +3695,21 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
3694
3695
|
private func sourceFallbackStateKey(_ source: [String: Any]) -> String? {
|
|
3695
3696
|
let uri = source.string("uri").trimmingCharacters(in: .whitespacesAndNewlines)
|
|
3696
3697
|
guard !uri.isEmpty else { return nil }
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
}
|
|
3703
|
-
|
|
3698
|
+
// The fallback-state cache is process-wide, so key it by a digest of the request identity
|
|
3699
|
+
// instead of retaining raw header values, which can carry credentials such as Authorization.
|
|
3700
|
+
let headers = source.dictionary("headers") ?? [:]
|
|
3701
|
+
let fields: [(name: String, value: String)] = headers.map { key, value in
|
|
3702
|
+
(name: key.lowercased(), value: String(describing: value))
|
|
3703
|
+
}
|
|
3704
|
+
let sortedFields = fields.sorted { lhs, rhs in
|
|
3705
|
+
lhs.name == rhs.name ? lhs.value < rhs.value : lhs.name < rhs.name
|
|
3706
|
+
}
|
|
3707
|
+
var canonicalValue = "\(uri.utf8.count):\(uri)"
|
|
3708
|
+
for field in sortedFields {
|
|
3709
|
+
canonicalValue += "\(field.name.utf8.count):\(field.name)\(field.value.utf8.count):\(field.value)"
|
|
3704
3710
|
}
|
|
3705
|
-
|
|
3711
|
+
let digest = SHA256.hash(data: Data(canonicalValue.utf8))
|
|
3712
|
+
return digest.map { String(format: "%02x", $0) }.joined()
|
|
3706
3713
|
}
|
|
3707
3714
|
|
|
3708
3715
|
private func leadingConstraints(
|
|
@@ -4147,8 +4154,10 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
4147
4154
|
},
|
|
4148
4155
|
onError: retryLimit == 0 ? handleError : { [weak self, weak imageView] in
|
|
4149
4156
|
guard let self, self.bindingEpoch == expectedEpoch, let imageView else { return }
|
|
4150
|
-
|
|
4151
|
-
|
|
4157
|
+
// Report every failed attempt: a rebind during the retry delay cancels the pending retry,
|
|
4158
|
+
// so deferring to the last attempt would never record the source fallback state.
|
|
4159
|
+
handleError?()
|
|
4160
|
+
guard retryAttempt < retryLimit, self.selectorImageRetries[imageID] == nil else { return }
|
|
4152
4161
|
let retry = DispatchWorkItem { [weak self, weak imageView] in
|
|
4153
4162
|
guard let self, self.bindingEpoch == expectedEpoch, let imageView else { return }
|
|
4154
4163
|
self.selectorImageRetries.removeValue(forKey: imageID)
|
|
@@ -537,8 +537,10 @@ export const WEB_LIST_CSS = `
|
|
|
537
537
|
.ok-native-list-account-row[data-native-list-selector="accountSelector"]>.ok-native-list-accessories[data-native-list-account-control="createAddress"]{position:absolute;top:18px;right:12px}
|
|
538
538
|
.ok-native-list-account-row[data-native-list-selector="accountSelector"] .ok-native-list-accessories>[data-native-list-account-control="createAddress"]{flex-basis:36px;width:36px;height:36px;padding:6px;border-radius:8px}
|
|
539
539
|
.ok-native-list-account-action-row{padding-left:12px;padding-right:12px}.ok-native-list-account-action-row .ok-native-list-action-title{font-size:16px;line-height:24px;font-weight:400}.ok-native-list-account-action-row .ok-native-list-action-title[data-tone="primary"]{color:var(--nl-primary)}
|
|
540
|
-
/* OneKey patch: account selector wallets and accounts keep the default cursor instead of pointer or grab affordances.
|
|
541
|
-
|
|
540
|
+
/* OneKey patch: account selector wallets and accounts keep the default cursor instead of pointer or grab affordances.
|
|
541
|
+
Only the row surface is matched: cursor inherits, so plain children follow the row, while icon buttons,
|
|
542
|
+
checkboxes, and action buttons keep advertising themselves with their own pointer cursor. */
|
|
543
|
+
.ok-native-list-root .ok-native-list-item>.ok-native-list-wallet-row,.ok-native-list-root .ok-native-list-wallet-member>.ok-native-list-wallet-row,.ok-native-list-root .ok-native-list-item>.ok-native-list-account-row,.ok-native-list-root .ok-native-list-item>.ok-native-list-account-action-row,.ok-native-list-wallet-member{cursor:default}
|
|
542
544
|
/* OneKey patch: Add account hover and pressed backgrounds keep the account row corner radius. */
|
|
543
545
|
.ok-native-list-account-action-row{border-radius:12px}
|
|
544
546
|
`;
|
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.137",
|
|
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.137",
|
|
87
|
+
"@onekeyfe/react-native-native-logger": "3.0.137",
|
|
88
88
|
"react": "*",
|
|
89
89
|
"react-native": "*",
|
|
90
90
|
"react-native-nitro-modules": "0.37.0"
|
|
@@ -965,8 +965,10 @@ export const WEB_LIST_CSS = `
|
|
|
965
965
|
.ok-native-list-account-row[data-native-list-selector="accountSelector"]>.ok-native-list-accessories[data-native-list-account-control="createAddress"]{position:absolute;top:18px;right:12px}
|
|
966
966
|
.ok-native-list-account-row[data-native-list-selector="accountSelector"] .ok-native-list-accessories>[data-native-list-account-control="createAddress"]{flex-basis:36px;width:36px;height:36px;padding:6px;border-radius:8px}
|
|
967
967
|
.ok-native-list-account-action-row{padding-left:12px;padding-right:12px}.ok-native-list-account-action-row .ok-native-list-action-title{font-size:16px;line-height:24px;font-weight:400}.ok-native-list-account-action-row .ok-native-list-action-title[data-tone="primary"]{color:var(--nl-primary)}
|
|
968
|
-
/* OneKey patch: account selector wallets and accounts keep the default cursor instead of pointer or grab affordances.
|
|
969
|
-
|
|
968
|
+
/* OneKey patch: account selector wallets and accounts keep the default cursor instead of pointer or grab affordances.
|
|
969
|
+
Only the row surface is matched: cursor inherits, so plain children follow the row, while icon buttons,
|
|
970
|
+
checkboxes, and action buttons keep advertising themselves with their own pointer cursor. */
|
|
971
|
+
.ok-native-list-root .ok-native-list-item>.ok-native-list-wallet-row,.ok-native-list-root .ok-native-list-wallet-member>.ok-native-list-wallet-row,.ok-native-list-root .ok-native-list-item>.ok-native-list-account-row,.ok-native-list-root .ok-native-list-item>.ok-native-list-account-action-row,.ok-native-list-wallet-member{cursor:default}
|
|
970
972
|
/* OneKey patch: Add account hover and pressed backgrounds keep the account row corner radius. */
|
|
971
973
|
.ok-native-list-account-action-row{border-radius:12px}
|
|
972
974
|
`;
|