@onekeyfe/react-native-native-list 3.0.115 → 3.0.117
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/NativeListAdapter.kt +30 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRowView.kt +309 -32
- package/android/src/main/java/com/onekey/nativelist/NativeListView.kt +41 -1
- package/ios/NativeListCell.swift +191 -18
- package/ios/RNCNativeListView.swift +4 -0
- package/lib/module/validation.js +24 -1
- package/lib/module/web/NativeListWebEngine.js +11 -0
- package/lib/typescript/src/models.d.ts +30 -1
- package/package.json +3 -3
- package/src/models.ts +25 -0
- package/src/validation.ts +54 -0
- package/src/web/NativeListWebEngine.ts +18 -0
|
@@ -94,6 +94,8 @@ class NativeListView(
|
|
|
94
94
|
private var configuredTopPaddingPx = 0
|
|
95
95
|
private var configuredBottomPaddingPx = 0
|
|
96
96
|
private val refreshLayout = SwipeRefreshLayout(context)
|
|
97
|
+
private val refreshIndicatorTravelPx = refreshLayout.progressViewEndOffset
|
|
98
|
+
private var refreshIndicatorOffsetPx = 0
|
|
97
99
|
private val contentContainer = FrameLayout(context)
|
|
98
100
|
private val adapter = NativeListAdapter(reactContext)
|
|
99
101
|
private val layoutManager = GridLayoutManager(context, 1)
|
|
@@ -251,6 +253,11 @@ class NativeListView(
|
|
|
251
253
|
JSONObject().put("actionKey", "nativeList.refresh"),
|
|
252
254
|
)
|
|
253
255
|
}
|
|
256
|
+
recyclerView.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
|
|
257
|
+
// OneKey patch: a collapsible pager owns the extra padding above the rows.
|
|
258
|
+
// Keep the refresh control below that header without moving ordinary lists.
|
|
259
|
+
updateRefreshIndicatorOffset((recyclerView.paddingTop - configuredTopPaddingPx).coerceAtLeast(0))
|
|
260
|
+
}
|
|
254
261
|
|
|
255
262
|
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
|
256
263
|
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
|
@@ -274,6 +281,12 @@ class NativeListView(
|
|
|
274
281
|
|
|
275
282
|
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
|
276
283
|
super.onLayout(changed, left, top, right, bottom)
|
|
284
|
+
val first = config?.items?.firstOrNull()
|
|
285
|
+
if (recyclerView.isLayoutRequested && (first?.type == "market" || first?.json?.optString("presentation") == "market")) {
|
|
286
|
+
// A retained Market page can keep cached parent measurements after its diff.
|
|
287
|
+
// Drain the child's pending layout so its committed rows replace the old cells.
|
|
288
|
+
relayoutRecyclerViewImmediately()
|
|
289
|
+
}
|
|
277
290
|
val nextWidth = right - left
|
|
278
291
|
val nextHeight = bottom - top
|
|
279
292
|
if (
|
|
@@ -288,6 +301,28 @@ class NativeListView(
|
|
|
288
301
|
performPendingScrollIfNeeded()
|
|
289
302
|
}
|
|
290
303
|
|
|
304
|
+
private fun updateRefreshIndicatorOffset(offset: Int) {
|
|
305
|
+
if (refreshIndicatorOffsetPx == offset) return
|
|
306
|
+
refreshIndicatorOffsetPx = offset
|
|
307
|
+
val refreshing = refreshLayout.isRefreshing
|
|
308
|
+
val start = offset - refreshLayout.progressCircleDiameter
|
|
309
|
+
refreshLayout.setProgressViewOffset(false, start, start + refreshIndicatorTravelPx)
|
|
310
|
+
refreshLayout.isRefreshing = refreshing
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
override fun onAttachedToWindow() {
|
|
314
|
+
super.onAttachedToWindow()
|
|
315
|
+
val first = config?.items?.firstOrNull()
|
|
316
|
+
if (recyclerView.isLayoutRequested && (first?.type == "market" || first?.json?.optString("presentation") == "market")) {
|
|
317
|
+
relayoutContents()
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
override fun onDetachedFromWindow() {
|
|
322
|
+
updateRefreshIndicatorOffset(0)
|
|
323
|
+
super.onDetachedFromWindow()
|
|
324
|
+
}
|
|
325
|
+
|
|
291
326
|
fun applySnapshot(snapshotJson: String) {
|
|
292
327
|
val next = try {
|
|
293
328
|
NativeListConfig.parse(snapshotJson)
|
|
@@ -1121,7 +1156,12 @@ class NativeListView(
|
|
|
1121
1156
|
.put("source", origin.source)
|
|
1122
1157
|
.put("generation", generation)
|
|
1123
1158
|
.put("layoutDirection", if (origin.sourceView.layoutDirection == LAYOUT_DIRECTION_RTL) "rtl" else "ltr")
|
|
1124
|
-
.also { anchor ->
|
|
1159
|
+
.also { anchor ->
|
|
1160
|
+
origin.slot?.let { anchor.put("slot", it) }
|
|
1161
|
+
origin.windowPointPixels?.let { point ->
|
|
1162
|
+
anchor.put("windowPoint", JSONObject().put("x", point.x / density).put("y", point.y / density))
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1125
1165
|
}
|
|
1126
1166
|
|
|
1127
1167
|
private fun isOriginValid(origin: NativeListActionOrigin): Boolean =
|
package/ios/NativeListCell.swift
CHANGED
|
@@ -79,6 +79,7 @@ final class NativeListActionOrigin {
|
|
|
79
79
|
let slot: Int?
|
|
80
80
|
// OneKey patch: expose the layout slot while preserving the larger hit target.
|
|
81
81
|
let anchorInset: CGFloat
|
|
82
|
+
var windowPoint: CGPoint?
|
|
82
83
|
|
|
83
84
|
init(
|
|
84
85
|
sourceView: UIView,
|
|
@@ -443,12 +444,17 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
443
444
|
private let titleRowStack = UIStackView()
|
|
444
445
|
private let titleLabel = NativeListDottedUnderlineLabel()
|
|
445
446
|
private let subtitleLabel = UILabel()
|
|
447
|
+
// OneKey patch: keep Market name and volume in independent line boxes.
|
|
448
|
+
private let marketSubtitleStack = UIStackView()
|
|
449
|
+
private let marketSubtitleSpacer = UIView()
|
|
446
450
|
private let tertiaryLabel = UILabel()
|
|
447
451
|
private let statusLabel = NativeListInsetLabel()
|
|
448
452
|
private let metricSubtitleLabel = UILabel()
|
|
449
453
|
private let metricCompositeStack = UIStackView()
|
|
450
454
|
private let badgeLabel = NativeListInsetLabel()
|
|
451
|
-
|
|
455
|
+
// OneKey patch: reuse the existing explicit line-box layout for styled Market badges.
|
|
456
|
+
// private let marketBadgeButtons = (0..<3).map { _ in UIButton(type: .system) }
|
|
457
|
+
private let marketBadgeButtons = (0..<3).map { _ in NativeListAccessoryButton(type: .system) }
|
|
452
458
|
private let marketBadgeImages = (0..<3).map { _ in OneKeyImageReusableView(frame: .zero) }
|
|
453
459
|
private let actionStack = UIStackView()
|
|
454
460
|
private let actionButtons = (0..<3).map { _ in UIButton(type: .system) }
|
|
@@ -797,6 +803,19 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
797
803
|
|
|
798
804
|
override func layoutSubviews() {
|
|
799
805
|
super.layoutSubviews()
|
|
806
|
+
if let item = currentItem, item.type == "system", item.data.string("presentation") == "market",
|
|
807
|
+
["noMatch", "retry"].contains(item.data.string("variant")), !titleLabel.isHidden {
|
|
808
|
+
// The cell content view owns the root constraints and must settle before reading descendants.
|
|
809
|
+
contentView.layoutIfNeeded()
|
|
810
|
+
// React Native floors text origins to physical pixels after centering the line box.
|
|
811
|
+
titleLabel.transform = .identity
|
|
812
|
+
let scale = max(1, window?.screen.scale ?? traitCollection.displayScale)
|
|
813
|
+
let origin = titleLabel.convert(titleLabel.bounds, to: contentView).origin
|
|
814
|
+
let x = floor((contentView.bounds.width - titleLabel.bounds.width) / 2 * scale) / scale
|
|
815
|
+
let contentHeight: CGFloat = item.data.string("variant") == "retry" ? 56 : 24
|
|
816
|
+
let y = floor(max(32, (contentView.bounds.height - contentHeight) / 2) * scale) / scale
|
|
817
|
+
titleLabel.transform = CGAffineTransform(translationX: x - origin.x, y: y - origin.y)
|
|
818
|
+
}
|
|
800
819
|
// OneKey patch: extend only the background across the section list outer inset.
|
|
801
820
|
if currentItem?.data.bool("backgroundFullWidth") == true {
|
|
802
821
|
selectorFullWidthBackground.frame = CGRect(x: -frame.minX, y: 0, width: superview?.bounds.width ?? bounds.width, height: bounds.height)
|
|
@@ -1140,6 +1159,7 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
1140
1159
|
}
|
|
1141
1160
|
|
|
1142
1161
|
private func reset() {
|
|
1162
|
+
titleLabel.transform = .identity
|
|
1143
1163
|
restoreSelectorTypography()
|
|
1144
1164
|
// OneKey patch: remove selector decorations before rebinding recycled cells.
|
|
1145
1165
|
selectorViews.forEach { $0.removeFromSuperview() }
|
|
@@ -1202,6 +1222,15 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
1202
1222
|
headerValueIconImageView.removeFromSuperview()
|
|
1203
1223
|
headerValueIconImageView.image = nil
|
|
1204
1224
|
headerValueIconImageView.isHidden = true
|
|
1225
|
+
// OneKey patch: restore the shared labels before any recycled row binds.
|
|
1226
|
+
marketSubtitleStack.arrangedSubviews.forEach {
|
|
1227
|
+
marketSubtitleStack.removeArrangedSubview($0)
|
|
1228
|
+
$0.removeFromSuperview()
|
|
1229
|
+
}
|
|
1230
|
+
mainStack.removeArrangedSubview(marketSubtitleStack)
|
|
1231
|
+
marketSubtitleStack.removeFromSuperview()
|
|
1232
|
+
mainStack.removeArrangedSubview(tertiaryLabel)
|
|
1233
|
+
tertiaryLabel.removeFromSuperview()
|
|
1205
1234
|
mediaMetadataStack.removeArrangedSubview(subtitleLabel)
|
|
1206
1235
|
mediaMetadataStack.removeArrangedSubview(mediaNetworkImage)
|
|
1207
1236
|
mediaMetadataStack.removeFromSuperview()
|
|
@@ -1211,6 +1240,7 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
1211
1240
|
subtitleLabel.removeFromSuperview()
|
|
1212
1241
|
mainStack.insertArrangedSubview(titleRowStack, at: 0)
|
|
1213
1242
|
mainStack.insertArrangedSubview(subtitleLabel, at: 1)
|
|
1243
|
+
mainStack.insertArrangedSubview(tertiaryLabel, at: 2)
|
|
1214
1244
|
leadingWidth.constant = 40
|
|
1215
1245
|
leadingHeight.constant = 40
|
|
1216
1246
|
leadingIconWidth.constant = 18
|
|
@@ -1246,6 +1276,8 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
1246
1276
|
leadingActionButton.isHidden = true
|
|
1247
1277
|
leadingActionButton.setImage(nil, for: .normal)
|
|
1248
1278
|
leadingActionButton.setImage(nil, for: .disabled)
|
|
1279
|
+
leadingActionButton.accessibilityIdentifier = nil
|
|
1280
|
+
leadingActionButton.accessibilityLabel = nil
|
|
1249
1281
|
unreadDot.isHidden = true
|
|
1250
1282
|
mediaBadgeLabel.isHidden = true
|
|
1251
1283
|
mediaBadgeLabel.text = nil
|
|
@@ -1265,6 +1297,13 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
1265
1297
|
titleLabel.textAlignment = .natural
|
|
1266
1298
|
subtitleLabel.text = nil
|
|
1267
1299
|
subtitleLabel.lineBreakMode = .byTruncatingTail
|
|
1300
|
+
subtitleLabel.attributedText = nil
|
|
1301
|
+
subtitleLabel.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
|
1302
|
+
subtitleLabel.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
|
|
1303
|
+
tertiaryLabel.attributedText = nil
|
|
1304
|
+
tertiaryLabel.lineBreakMode = .byTruncatingTail
|
|
1305
|
+
tertiaryLabel.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
|
1306
|
+
tertiaryLabel.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
|
|
1268
1307
|
tertiaryLabel.text = nil
|
|
1269
1308
|
statusLabel.text = nil
|
|
1270
1309
|
statusLabel.topInset = 0
|
|
@@ -1291,6 +1330,15 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
1291
1330
|
$0.isHidden = true
|
|
1292
1331
|
$0.isEnabled = true
|
|
1293
1332
|
$0.isUserInteractionEnabled = false
|
|
1333
|
+
// OneKey patch: a recycled badge must not retain an attributed title or font.
|
|
1334
|
+
$0.setAttributedTitle(nil, for: .normal)
|
|
1335
|
+
$0.marketLineHeight = nil
|
|
1336
|
+
$0.selectorSummaryLineHeight = nil
|
|
1337
|
+
$0.titleLabel?.font = nativeListFont(ofSize: 11, weight: .medium)
|
|
1338
|
+
$0.titleLabel?.numberOfLines = 1
|
|
1339
|
+
$0.contentHorizontalAlignment = .center
|
|
1340
|
+
$0.accessibilityLabel = nil
|
|
1341
|
+
$0.accessibilityTraits = .staticText
|
|
1294
1342
|
$0.setTitle(nil, for: .normal)
|
|
1295
1343
|
$0.setImage(nil, for: .normal)
|
|
1296
1344
|
$0.setTitleColor(nil, for: .normal)
|
|
@@ -2266,6 +2314,28 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
2266
2314
|
rootTopConstraint.constant = verticalPadding
|
|
2267
2315
|
rootBottomConstraint.constant = -verticalPadding
|
|
2268
2316
|
rootStack.spacing = CGFloat(style?.double("leadingGap", default: variant == "perp" ? 8 : 14) ?? (variant == "perp" ? 8 : 14))
|
|
2317
|
+
if let leadingAction = item.data.dictionary("leadingAction") {
|
|
2318
|
+
leadingActionButton.isHidden = false
|
|
2319
|
+
let tintColor = UIColor(
|
|
2320
|
+
nativeListHex: leadingAction.string("tintColor", default: "#646464"),
|
|
2321
|
+
fallback: .darkGray
|
|
2322
|
+
)
|
|
2323
|
+
leadingActionButton.tintColor = tintColor
|
|
2324
|
+
if let image = nativeListIcon(named: leadingAction.string("name")) {
|
|
2325
|
+
leadingActionButton.setImage(image, for: .normal)
|
|
2326
|
+
leadingActionButton.setImage(
|
|
2327
|
+
image.withTintColor(tintColor, renderingMode: .alwaysOriginal),
|
|
2328
|
+
for: .disabled
|
|
2329
|
+
)
|
|
2330
|
+
}
|
|
2331
|
+
leadingActionButton.isEnabled = !leadingAction.bool("disabled")
|
|
2332
|
+
leadingActionButton.alpha = leadingActionButton.isEnabled ? 1 : 0.4
|
|
2333
|
+
leadingActionButton.accessibilityIdentifier = leadingAction["testID"] as? String
|
|
2334
|
+
leadingActionButton.accessibilityLabel = leadingAction["accessibilityLabel"] as? String
|
|
2335
|
+
leadingActionKey = leadingAction.string("actionKey")
|
|
2336
|
+
rootStack.addArrangedSubview(leadingActionButton)
|
|
2337
|
+
rootStack.setCustomSpacing(5, after: leadingActionButton)
|
|
2338
|
+
}
|
|
2269
2339
|
leadingWidth.constant = imageWidth
|
|
2270
2340
|
leadingHeight.constant = imageHeight
|
|
2271
2341
|
if let visual = marketLeading(item, style: style) {
|
|
@@ -2295,15 +2365,29 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
2295
2365
|
}
|
|
2296
2366
|
}
|
|
2297
2367
|
rootStack.addArrangedSubview(mainStack)
|
|
2298
|
-
|
|
2368
|
+
// OneKey patch: opt in to the source Market row's content gap.
|
|
2369
|
+
// rootStack.setCustomSpacing(0, after: mainStack)
|
|
2370
|
+
rootStack.setCustomSpacing(CGFloat(style?.double("contentTrailingGap", default: 0) ?? 0), after: mainStack)
|
|
2299
2371
|
mainStack.spacing = CGFloat(style?.double("lineGap", default: 0) ?? 0)
|
|
2300
2372
|
titleRowStack.spacing = CGFloat(style?.double("titleBadgeGap", default: 4) ?? 4)
|
|
2373
|
+
// OneKey patch: opt in without changing the other row templates' filled layout.
|
|
2374
|
+
if style?.string("titleBadgeLayout") == "inline" {
|
|
2375
|
+
mainStack.alignment = .leading
|
|
2376
|
+
titleRowStack.setContentHuggingPriority(.required, for: .horizontal)
|
|
2377
|
+
}
|
|
2301
2378
|
show(titleLabel, item.data.string("title"), lines: style?.dictionary("title")?.int("lines", default: 1) ?? 1)
|
|
2302
2379
|
applyMarketTextStyle(titleLabel, data: style?.dictionary("title"), theme: theme, defaultSize: 16, defaultLineHeight: 24, defaultWeight: .medium, defaultColor: nativeListColor(theme, "primaryText", "#202020"))
|
|
2303
2380
|
let badges = Array(item.data.dictionaries("badges").prefix(marketBadgeButtons.count))
|
|
2304
2381
|
marketBadgeActionKeys = badges.map { $0["actionKey"] as? String }
|
|
2305
2382
|
for (index, badge) in badges.enumerated() {
|
|
2306
2383
|
let button = marketBadgeButtons[index]
|
|
2384
|
+
let badgeStyle = badge.dictionary("style")
|
|
2385
|
+
let badgeFontSize = CGFloat(badgeStyle?.double("fontSize", default: 11) ?? 11)
|
|
2386
|
+
let badgeFontWeight = marketFontWeight(badgeStyle?.string("fontWeight") ?? "", fallback: .medium)
|
|
2387
|
+
// OneKey patch: SizableText supplies tabular numerals for explicit Market metrics.
|
|
2388
|
+
let badgeFont = badgeStyle == nil
|
|
2389
|
+
? nativeListFont(ofSize: badgeFontSize, weight: badgeFontWeight)
|
|
2390
|
+
: nativeListTabularFont(ofSize: badgeFontSize, weight: badgeFontWeight)
|
|
2307
2391
|
let hasBuiltInIcon = badge.string("iconName") == "verified"
|
|
2308
2392
|
let hasRemoteIcon = badge.dictionary("icon") != nil
|
|
2309
2393
|
let hasIcon = hasBuiltInIcon || hasRemoteIcon
|
|
@@ -2326,6 +2410,12 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
2326
2410
|
button.accessibilityTraits = button.isUserInteractionEnabled ? .button : .staticText
|
|
2327
2411
|
button.setTitle(text, for: .normal)
|
|
2328
2412
|
button.setTitleColor(foreground, for: .normal)
|
|
2413
|
+
button.titleLabel?.font = badgeFont
|
|
2414
|
+
if let lineHeight = badgeStyle?["lineHeight"] as? Double {
|
|
2415
|
+
setButtonLine(button, text: text, font: badgeFont, color: foreground, lineHeight: CGFloat(lineHeight))
|
|
2416
|
+
// The explicit text-only line box must not cover an adjacent icon.
|
|
2417
|
+
if hasIcon { button.marketLineHeight = nil }
|
|
2418
|
+
}
|
|
2329
2419
|
button.tintColor = foreground
|
|
2330
2420
|
button.backgroundColor = UIColor(
|
|
2331
2421
|
nativeListHex: badge.string("backgroundColor", default: ""),
|
|
@@ -2335,7 +2425,12 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
2335
2425
|
)
|
|
2336
2426
|
let iconOnly = hasIcon && text.isEmpty
|
|
2337
2427
|
let iconSize: CGFloat = hasBuiltInIcon ? 16 : 14
|
|
2338
|
-
|
|
2428
|
+
// OneKey patch: preserve the native defaults unless the caller supplies padding.
|
|
2429
|
+
let padding = CGFloat(badgeStyle?.double("horizontalPadding", default: 5) ?? 5)
|
|
2430
|
+
let hasCustomPadding = badgeStyle?["horizontalPadding"] != nil
|
|
2431
|
+
let leftPadding = hasCustomPadding ? padding + (hasRemoteIcon ? iconSize + 2 : 0) : hasRemoteIcon ? 20 : hasIcon ? 3 : 5
|
|
2432
|
+
// button.contentEdgeInsets = UIEdgeInsets(top: 0, left: iconOnly ? 0 : hasRemoteIcon ? 20 : hasIcon ? 3 : 5, bottom: 0, right: iconOnly ? 0 : 5)
|
|
2433
|
+
button.contentEdgeInsets = UIEdgeInsets(top: 0, left: iconOnly ? 0 : leftPadding, bottom: 0, right: iconOnly ? 0 : padding)
|
|
2339
2434
|
button.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: text.isEmpty ? 0 : 3)
|
|
2340
2435
|
button.titleEdgeInsets = .zero
|
|
2341
2436
|
button.imageView?.contentMode = .scaleAspectFit
|
|
@@ -2345,11 +2440,15 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
2345
2440
|
for: .normal
|
|
2346
2441
|
)
|
|
2347
2442
|
}
|
|
2348
|
-
|
|
2349
|
-
let
|
|
2350
|
-
|
|
2351
|
-
).width
|
|
2352
|
-
let
|
|
2443
|
+
// OneKey patch: match source badge metrics at physical-pixel precision.
|
|
2444
|
+
// let height = button.heightAnchor.constraint(equalToConstant: 18)
|
|
2445
|
+
let height = button.heightAnchor.constraint(equalToConstant: CGFloat(badgeStyle?.double("height", default: 18) ?? 18))
|
|
2446
|
+
let textWidth = (text as NSString).size(withAttributes: [.font: badgeFont]).width
|
|
2447
|
+
let scale = max(1, traitCollection.displayScale)
|
|
2448
|
+
let roundedTextWidth = badgeStyle == nil ? ceil(textWidth) : ceil(textWidth * scale) / scale
|
|
2449
|
+
let extraWidth = hasCustomPadding ? padding * 2 + (hasIcon ? iconSize + 2 : 0) : hasIcon ? iconSize + 11 : 10
|
|
2450
|
+
// let width = button.widthAnchor.constraint(equalToConstant: iconOnly ? iconSize : ceil(textWidth) + (hasIcon ? iconSize + 11 : 10))
|
|
2451
|
+
let width = button.widthAnchor.constraint(equalToConstant: iconOnly ? iconSize : roundedTextWidth + extraWidth)
|
|
2353
2452
|
NSLayoutConstraint.activate([width, height])
|
|
2354
2453
|
selectorConstraints.append(contentsOf: [width, height])
|
|
2355
2454
|
if let icon = badge.dictionary("icon") {
|
|
@@ -2370,6 +2469,41 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
2370
2469
|
subtitleLabel.attributedText = marketAttributedText(item.data.string("subtitle"), segments: item.data.dictionaries("subtitleSegments"), style: style?.dictionary("subtitle"), defaultSize: 14, defaultLineHeight: 20, defaultWeight: .regular, color: nativeListColor(theme, "secondaryText", "#646464"), defaultAlignment: .natural)
|
|
2371
2470
|
}
|
|
2372
2471
|
}
|
|
2472
|
+
// OneKey patch: preserve volume width while the localized name truncates.
|
|
2473
|
+
let subtitlePrefix = item.data.dictionary("subtitlePrefix")
|
|
2474
|
+
let subtitlePadding = CGFloat(style?.double("subtitleTrailingPadding", default: 0) ?? 0)
|
|
2475
|
+
if subtitlePrefix != nil || subtitlePadding > 0 {
|
|
2476
|
+
mainStack.removeArrangedSubview(subtitleLabel)
|
|
2477
|
+
subtitleLabel.removeFromSuperview()
|
|
2478
|
+
mainStack.removeArrangedSubview(tertiaryLabel)
|
|
2479
|
+
tertiaryLabel.removeFromSuperview()
|
|
2480
|
+
marketSubtitleStack.axis = .horizontal
|
|
2481
|
+
marketSubtitleStack.alignment = .center
|
|
2482
|
+
marketSubtitleStack.spacing = 0
|
|
2483
|
+
marketSubtitleStack.clipsToBounds = true
|
|
2484
|
+
show(tertiaryLabel, subtitlePrefix?.string("text") ?? "", lines: 1)
|
|
2485
|
+
applyMarketTextStyle(tertiaryLabel, data: subtitlePrefix?.dictionary("style"), theme: theme, defaultSize: 12, defaultLineHeight: 16, defaultWeight: .regular, defaultColor: nativeListColor(theme, "secondaryText", "#646464"))
|
|
2486
|
+
tertiaryLabel.setContentHuggingPriority(.required, for: .horizontal)
|
|
2487
|
+
tertiaryLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
|
2488
|
+
subtitleLabel.setContentHuggingPriority(.required, for: .horizontal)
|
|
2489
|
+
subtitleLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
|
|
2490
|
+
marketSubtitleStack.addArrangedSubview(tertiaryLabel)
|
|
2491
|
+
marketSubtitleStack.addArrangedSubview(subtitleLabel)
|
|
2492
|
+
marketSubtitleStack.addArrangedSubview(marketSubtitleSpacer)
|
|
2493
|
+
if !tertiaryLabel.isHidden && !subtitleLabel.isHidden {
|
|
2494
|
+
marketSubtitleStack.setCustomSpacing(CGFloat(subtitlePrefix?.double("gap", default: 4) ?? 4), after: tertiaryLabel)
|
|
2495
|
+
}
|
|
2496
|
+
mainStack.insertArrangedSubview(marketSubtitleStack, at: 1)
|
|
2497
|
+
let width = marketSubtitleStack.widthAnchor.constraint(equalTo: mainStack.widthAnchor, constant: -subtitlePadding)
|
|
2498
|
+
width.isActive = true
|
|
2499
|
+
selectorConstraints.append(width)
|
|
2500
|
+
if let maxWidth = subtitlePrefix?["maxWidth"] as? Double {
|
|
2501
|
+
let limit = tertiaryLabel.widthAnchor.constraint(lessThanOrEqualToConstant: CGFloat(maxWidth))
|
|
2502
|
+
limit.isActive = true
|
|
2503
|
+
selectorConstraints.append(limit)
|
|
2504
|
+
}
|
|
2505
|
+
marketSubtitleStack.isHidden = tertiaryLabel.isHidden && subtitleLabel.isHidden
|
|
2506
|
+
}
|
|
2373
2507
|
rootStack.addArrangedSubview(trailingStack)
|
|
2374
2508
|
trailingStack.axis = .horizontal
|
|
2375
2509
|
trailingStack.alignment = .center
|
|
@@ -3039,6 +3173,41 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
3039
3173
|
rootTopConstraint.constant = 12
|
|
3040
3174
|
rootBottomConstraint.constant = -12
|
|
3041
3175
|
}
|
|
3176
|
+
if isMarket && variant == "retry" {
|
|
3177
|
+
let message = item.data.string("message")
|
|
3178
|
+
let text = item.data.string("actionText", default: "Retry")
|
|
3179
|
+
rootStack.axis = .vertical
|
|
3180
|
+
// The source tertiary Button has -5 vertical margins around its 30pt frame.
|
|
3181
|
+
rootStack.spacing = 7
|
|
3182
|
+
rootLeadingConstraint.constant = 32
|
|
3183
|
+
rootTrailingConstraint.constant = -32
|
|
3184
|
+
let height = CGFloat(item.data.double("height", default: message.isEmpty ? 52 : 120))
|
|
3185
|
+
let top = message.isEmpty ? 11 : max(32, (height - 56) / 2)
|
|
3186
|
+
rootTopConstraint.constant = top
|
|
3187
|
+
rootBottomConstraint.constant = -(height - top - (message.isEmpty ? 30 : 61))
|
|
3188
|
+
if !message.isEmpty {
|
|
3189
|
+
show(titleLabel, message, lines: 2)
|
|
3190
|
+
titleLabel.font = nativeListTabularFont(ofSize: 16)
|
|
3191
|
+
titleLabel.textColor = nativeListColor(theme, "secondaryText", "#646464")
|
|
3192
|
+
titleLabel.textAlignment = .center
|
|
3193
|
+
setLineHeight(titleLabel, text: message, lineHeight: 24)
|
|
3194
|
+
rootStack.addArrangedSubview(mainStack)
|
|
3195
|
+
}
|
|
3196
|
+
showAccessory(0, text, action: (item.data.string("actionKey"), nil))
|
|
3197
|
+
let button = accessoryButtons[0]
|
|
3198
|
+
button.backgroundColor = .clear
|
|
3199
|
+
button.layer.cornerRadius = 15
|
|
3200
|
+
setButtonLine(button, text: text, font: nativeListTabularFont(ofSize: 14, weight: .medium),
|
|
3201
|
+
color: nativeListColor(theme, "secondaryText", "#646464"), lineHeight: 20)
|
|
3202
|
+
let textWidth = button.intrinsicContentSize.width
|
|
3203
|
+
selectorConstraints.append(contentsOf: [
|
|
3204
|
+
button.widthAnchor.constraint(equalToConstant: textWidth + 18),
|
|
3205
|
+
button.heightAnchor.constraint(equalToConstant: 30),
|
|
3206
|
+
])
|
|
3207
|
+
NSLayoutConstraint.activate(selectorConstraints)
|
|
3208
|
+
rootStack.addArrangedSubview(trailingStack)
|
|
3209
|
+
return
|
|
3210
|
+
}
|
|
3042
3211
|
if variant == "loading" && item.data.string("loadingStyle") == "skeleton" {
|
|
3043
3212
|
rootLeadingConstraint.constant = 20
|
|
3044
3213
|
rootTrailingConstraint.constant = -20
|
|
@@ -3065,12 +3234,13 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
3065
3234
|
return
|
|
3066
3235
|
}
|
|
3067
3236
|
if isMarket && variant == "noMatch" {
|
|
3068
|
-
|
|
3069
|
-
|
|
3237
|
+
let padding = max(32, (CGFloat(item.data.double("height", default: 88)) - 24) / 2)
|
|
3238
|
+
rootTopConstraint.constant = padding
|
|
3239
|
+
rootBottomConstraint.constant = -padding
|
|
3070
3240
|
rootStack.addArrangedSubview(mainStack)
|
|
3071
3241
|
mainStack.alignment = .center
|
|
3072
3242
|
mainStack.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
|
3073
|
-
titleLabel.font =
|
|
3243
|
+
titleLabel.font = nativeListTabularFont(ofSize: 16)
|
|
3074
3244
|
titleLabel.textColor = nativeListColor(theme, "secondaryText", "#646464")
|
|
3075
3245
|
titleLabel.textAlignment = .center
|
|
3076
3246
|
show(titleLabel, item.data.string("message"), lines: 1)
|
|
@@ -3080,6 +3250,8 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
3080
3250
|
if isMarket && variant == "end" {
|
|
3081
3251
|
rootTopConstraint.constant = 16
|
|
3082
3252
|
rootBottomConstraint.constant = -16
|
|
3253
|
+
// OneKey patch: an empty title stack must not consume the dot's line height.
|
|
3254
|
+
titleRowStack.isHidden = true
|
|
3083
3255
|
rootStack.addArrangedSubview(mainStack)
|
|
3084
3256
|
mainStack.alignment = .center
|
|
3085
3257
|
mainStack.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
|
@@ -3558,7 +3730,7 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
3558
3730
|
.foregroundColor: label.textColor as Any,
|
|
3559
3731
|
.paragraphStyle: paragraphStyle,
|
|
3560
3732
|
]
|
|
3561
|
-
if currentItem?.type == "market" || (currentItem?.data["height"] != nil && (["accountSelector", "walletSidebar"].contains(currentItem?.data.string("presentation") ?? "") || currentItem?.type == "sectionHeader" && currentItem?.data.string("presentation") == "networkSelector")) || currentItem?.type == "system" && currentItem?.data.string("variant") == "warning" {
|
|
3733
|
+
if currentItem?.type == "market" || currentItem?.type == "system" && currentItem?.data.string("presentation") == "market" && currentItem?.data.string("variant") == "noMatch" || (currentItem?.data["height"] != nil && (["accountSelector", "walletSidebar"].contains(currentItem?.data.string("presentation") ?? "") || currentItem?.type == "sectionHeader" && currentItem?.data.string("presentation") == "networkSelector")) || currentItem?.type == "system" && currentItem?.data.string("variant") == "warning" {
|
|
3562
3734
|
// OneKey patch: React Native centers font metrics inside explicit line heights.
|
|
3563
3735
|
let baselineOffset = max(0, (lineHeight - label.font.lineHeight) / 2)
|
|
3564
3736
|
// OneKey patch: TextKit's 14/20 headings align their baseline to the upper physical pixel.
|
|
@@ -3566,7 +3738,7 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
3566
3738
|
let scale = window?.screen.scale ?? traitCollection.displayScale
|
|
3567
3739
|
attributes[.baselineOffset] = isSelectorHeading && scale > 0 ? ceil(baselineOffset * scale) / scale : baselineOffset
|
|
3568
3740
|
}
|
|
3569
|
-
if letterSpacing != 0 || currentItem?.type == "market" { attributes[.kern] = letterSpacing }
|
|
3741
|
+
if letterSpacing != 0 || currentItem?.type == "market" || currentItem?.data.string("presentation") == "market" { attributes[.kern] = letterSpacing }
|
|
3570
3742
|
label.attributedText = NSAttributedString(string: text, attributes: attributes)
|
|
3571
3743
|
}
|
|
3572
3744
|
|
|
@@ -3581,13 +3753,14 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
3581
3753
|
let paragraphStyle = NSMutableParagraphStyle()
|
|
3582
3754
|
paragraphStyle.minimumLineHeight = lineHeight
|
|
3583
3755
|
paragraphStyle.maximumLineHeight = lineHeight
|
|
3756
|
+
let isMarketText = currentItem?.type == "market" || currentItem?.type == "system" && currentItem?.data.string("presentation") == "market" && currentItem?.data.string("variant") == "retry"
|
|
3584
3757
|
let isSelectorValue = currentItem?.data.string("presentation") == "networkSelector" && currentItem?.data["height"] != nil && currentItem?.data.string("variant") != "summary"
|
|
3585
3758
|
let isSelectorSummary = currentItem?.type == "sectionHeader" && currentItem?.data.string("presentation") == "networkSelector" && currentItem?.data["height"] != nil && currentItem?.data.string("variant") == "summary"
|
|
3586
3759
|
(button as? NativeListAccessoryButton)?.selectorSummaryLineHeight = isSelectorSummary ? lineHeight : nil
|
|
3587
|
-
(button as? NativeListAccessoryButton)?.marketLineHeight =
|
|
3760
|
+
(button as? NativeListAccessoryButton)?.marketLineHeight = isMarketText ? lineHeight : nil
|
|
3588
3761
|
// OneKey patch: summary text uses its source line box; currency retains trailing alignment.
|
|
3589
3762
|
// Market's line box already handles alignment; source text starts at its origin.
|
|
3590
|
-
paragraphStyle.alignment = isSelectorValue ? .right : isSelectorSummary ||
|
|
3763
|
+
paragraphStyle.alignment = isSelectorValue ? .right : isSelectorSummary || isMarketText ? .natural : .center
|
|
3591
3764
|
if isSelectorSummary {
|
|
3592
3765
|
button.contentHorizontalAlignment = .leading
|
|
3593
3766
|
button.titleLabel?.textAlignment = .natural
|
|
@@ -3596,14 +3769,14 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
3596
3769
|
button.contentHorizontalAlignment = .trailing
|
|
3597
3770
|
button.titleLabel?.textAlignment = .right
|
|
3598
3771
|
}
|
|
3599
|
-
let baselineOffset: CGFloat =
|
|
3772
|
+
let baselineOffset: CGFloat = isMarketText || currentItem?.type == "sectionHeader" && currentItem?.data.string("presentation") == "networkSelector" && currentItem?.data["height"] != nil ? max(0, (lineHeight - font.lineHeight) / 2) : 0
|
|
3600
3773
|
var attributes: [NSAttributedString.Key: Any] = [
|
|
3601
3774
|
.font: font,
|
|
3602
3775
|
.foregroundColor: color,
|
|
3603
3776
|
.paragraphStyle: paragraphStyle,
|
|
3604
|
-
.baselineOffset:
|
|
3777
|
+
.baselineOffset: isMarketText && lineHeight == 20 && font.pointSize == 14 ? ceil(baselineOffset * max(1, traitCollection.displayScale)) / max(1, traitCollection.displayScale) : baselineOffset,
|
|
3605
3778
|
]
|
|
3606
|
-
if
|
|
3779
|
+
if isMarketText { attributes[.kern] = 0 }
|
|
3607
3780
|
button.setAttributedTitle(
|
|
3608
3781
|
NSAttributedString(string: text, attributes: attributes),
|
|
3609
3782
|
for: .normal
|
|
@@ -1052,6 +1052,7 @@ final class NativeListView: UIView {
|
|
|
1052
1052
|
let actionKey = item.data.string("longPressActionKey")
|
|
1053
1053
|
guard !actionKey.isEmpty else { return }
|
|
1054
1054
|
let origin = (collectionView.cellForItem(at: indexPath) as? NativeListCell)?.rowActionOrigin()
|
|
1055
|
+
origin?.windowPoint = gesture.location(in: window)
|
|
1055
1056
|
handleAction(item: item, actionKey: actionKey, target: nil, origin: origin)
|
|
1056
1057
|
}
|
|
1057
1058
|
|
|
@@ -1478,6 +1479,9 @@ final class NativeListView: UIView {
|
|
|
1478
1479
|
? "rtl"
|
|
1479
1480
|
: "ltr",
|
|
1480
1481
|
]
|
|
1482
|
+
if let point = origin.windowPoint {
|
|
1483
|
+
anchor["windowPoint"] = ["x": point.x, "y": point.y]
|
|
1484
|
+
}
|
|
1481
1485
|
if let slot = origin.slot { anchor["slot"] = slot }
|
|
1482
1486
|
return anchor
|
|
1483
1487
|
}
|
package/lib/module/validation.js
CHANGED
|
@@ -84,9 +84,13 @@ function assertMarketTextStyle(style, path) {
|
|
|
84
84
|
}
|
|
85
85
|
function assertMarketStyle(style, path) {
|
|
86
86
|
if (!style) return;
|
|
87
|
-
for (const field of ['horizontalPadding', 'verticalPadding', 'leadingGap', 'titleBadgeGap', 'trailingGap']) {
|
|
87
|
+
for (const field of ['horizontalPadding', 'verticalPadding', 'leadingGap', 'titleBadgeGap', 'trailingGap', 'contentTrailingGap', 'subtitleTrailingPadding']) {
|
|
88
88
|
assertBoundedStyleNumber(style[field], `${path}.${field}`, 0, 64);
|
|
89
89
|
}
|
|
90
|
+
// OneKey patch: validate the opt-in Market badge layout.
|
|
91
|
+
if (style.titleBadgeLayout !== undefined && style.titleBadgeLayout !== 'inline') {
|
|
92
|
+
fail(`${path}.titleBadgeLayout`, 'must be inline when provided');
|
|
93
|
+
}
|
|
90
94
|
assertBoundedStyleNumber(style.lineGap, `${path}.lineGap`, 0, 16);
|
|
91
95
|
assertBoundedStyleNumber(style.changeWidth, `${path}.changeWidth`, 1, 160);
|
|
92
96
|
assertBoundedStyleNumber(style.changeHeight, `${path}.changeHeight`, 1, 160);
|
|
@@ -111,8 +115,22 @@ function assertMarketRow(row, path) {
|
|
|
111
115
|
}
|
|
112
116
|
assertText(row.title, `${path}.title`);
|
|
113
117
|
assertText(row.subtitle, `${path}.subtitle`);
|
|
118
|
+
// OneKey patch: validate the independently laid out Market name.
|
|
119
|
+
if (row.subtitlePrefix) {
|
|
120
|
+
assertText(row.subtitlePrefix.text, `${path}.subtitlePrefix.text`);
|
|
121
|
+
assertBoundedStyleNumber(row.subtitlePrefix.gap, `${path}.subtitlePrefix.gap`, 0, 64);
|
|
122
|
+
assertBoundedStyleNumber(row.subtitlePrefix.maxWidth, `${path}.subtitlePrefix.maxWidth`, 1, 320);
|
|
123
|
+
assertMarketTextStyle(row.subtitlePrefix.style, `${path}.subtitlePrefix.style`);
|
|
124
|
+
}
|
|
114
125
|
assertText(row.price, `${path}.price`);
|
|
115
126
|
assertText(row.change.text, `${path}.change.text`);
|
|
127
|
+
assertTrailingAccessories(row.leadingAction ? [row.leadingAction] : undefined, `${path}.leadingAction`);
|
|
128
|
+
if (row.leadingAction) {
|
|
129
|
+
assertText(row.leadingAction.name, `${path}.leadingAction.name`);
|
|
130
|
+
if (row.leadingAction.actionKey !== undefined) {
|
|
131
|
+
assertKey(row.leadingAction.actionKey, `${path}.leadingAction.actionKey`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
116
134
|
assertLeadingVisual(row.leading, `${path}.leading`);
|
|
117
135
|
const assertSegments = (segments, segmentPath) => {
|
|
118
136
|
segments?.forEach((segment, index) => {
|
|
@@ -140,6 +158,10 @@ function assertMarketRow(row, path) {
|
|
|
140
158
|
}
|
|
141
159
|
badgeKeys.add(badge.key);
|
|
142
160
|
assertText(badge.text, `${badgePath}.text`);
|
|
161
|
+
// OneKey patch: share typography bounds with Market text styles.
|
|
162
|
+
assertMarketTextStyle(badge.style, `${badgePath}.style`);
|
|
163
|
+
assertBoundedStyleNumber(badge.style?.height, `${badgePath}.style.height`, 1, 64);
|
|
164
|
+
assertBoundedStyleNumber(badge.style?.horizontalPadding, `${badgePath}.style.horizontalPadding`, 0, 32);
|
|
143
165
|
if (badge.iconName !== undefined && badge.iconName !== 'verified') {
|
|
144
166
|
fail(`${badgePath}.iconName`, 'must be verified when provided');
|
|
145
167
|
}
|
|
@@ -451,6 +473,7 @@ function assertRow(row, index, path = `rows[${index}]`) {
|
|
|
451
473
|
}
|
|
452
474
|
if (row.variant === 'retry') {
|
|
453
475
|
assertKey(row.actionKey, `${path}.actionKey`);
|
|
476
|
+
assertText(row.actionText, `${path}.actionText`);
|
|
454
477
|
}
|
|
455
478
|
break;
|
|
456
479
|
}
|
|
@@ -1747,6 +1747,17 @@ function createMarketRow(context, row) {
|
|
|
1747
1747
|
const layoutStyle = resolveWebMarketLayoutStyle(row);
|
|
1748
1748
|
body.style.padding = String(layoutStyle.verticalPadding) + 'px ' + String(layoutStyle.horizontalPadding) + 'px';
|
|
1749
1749
|
body.style.gap = '0px';
|
|
1750
|
+
if (row.leadingAction) {
|
|
1751
|
+
const action = createIconAction(context, row.leadingAction.name, row.leadingAction.actionKey, row.leadingAction.disabled, row.leadingAction.tintColor);
|
|
1752
|
+
action.style.flex = '0 0 36px';
|
|
1753
|
+
action.style.width = '36px';
|
|
1754
|
+
action.style.height = '36px';
|
|
1755
|
+
action.style.marginRight = '5px';
|
|
1756
|
+
setData(action, 'testid', row.leadingAction.testID);
|
|
1757
|
+
if (row.leadingAction.accessibilityLabel) action.setAttribute('aria-label', row.leadingAction.accessibilityLabel);
|
|
1758
|
+
markActionAnchorSource(action, 'leadingAction');
|
|
1759
|
+
body.appendChild(action);
|
|
1760
|
+
}
|
|
1750
1761
|
const visual = createVisual(context, row.leading);
|
|
1751
1762
|
if (visual) {
|
|
1752
1763
|
const width = layoutStyle.imageWidth;
|
|
@@ -50,7 +50,12 @@ export type MarketRowStyle = Readonly<{
|
|
|
50
50
|
/** Space between title and subtitle; 0 by default, bounded to 0..16. */
|
|
51
51
|
lineGap?: number;
|
|
52
52
|
titleBadgeGap?: number;
|
|
53
|
+
/** OneKey patch: keep badges next to the intrinsic title width. */
|
|
54
|
+
titleBadgeLayout?: 'inline';
|
|
53
55
|
trailingGap?: number;
|
|
56
|
+
/** OneKey patch: preserve separate Market content and subtitle insets. */
|
|
57
|
+
contentTrailingGap?: number;
|
|
58
|
+
subtitleTrailingPadding?: number;
|
|
54
59
|
image?: MarketImageStyle;
|
|
55
60
|
title?: MarketTextStyle;
|
|
56
61
|
subtitle?: MarketTextStyle;
|
|
@@ -71,6 +76,14 @@ export type MarketBadgeModel = Readonly<{
|
|
|
71
76
|
backgroundColor?: string;
|
|
72
77
|
actionKey?: string;
|
|
73
78
|
accessibilityLabel?: string;
|
|
79
|
+
/** OneKey patch: optional Market badge metrics; legacy native defaults remain unchanged. */
|
|
80
|
+
style?: Readonly<{
|
|
81
|
+
fontSize?: number;
|
|
82
|
+
fontWeight?: MarketTextStyle['fontWeight'];
|
|
83
|
+
lineHeight?: number;
|
|
84
|
+
height?: number;
|
|
85
|
+
horizontalPadding?: number;
|
|
86
|
+
}>;
|
|
74
87
|
}>;
|
|
75
88
|
export type MarketChangeModel = Readonly<{
|
|
76
89
|
text: string;
|
|
@@ -316,9 +329,19 @@ export type DataRow = RowBase & Readonly<{
|
|
|
316
329
|
export type MarketRow = RowBase & Readonly<{
|
|
317
330
|
type: 'market';
|
|
318
331
|
variant: 'token' | 'stock' | 'perp';
|
|
332
|
+
leadingAction?: Extract<TrailingAccessory, {
|
|
333
|
+
kind: 'icon';
|
|
334
|
+
}>;
|
|
319
335
|
leading: LeadingVisual;
|
|
320
336
|
title: string;
|
|
321
337
|
subtitle?: string;
|
|
338
|
+
/** OneKey patch: localized name shrinks independently of the volume. */
|
|
339
|
+
subtitlePrefix?: Readonly<{
|
|
340
|
+
text: string;
|
|
341
|
+
gap?: number;
|
|
342
|
+
maxWidth?: number;
|
|
343
|
+
style?: MarketTextStyle;
|
|
344
|
+
}>;
|
|
322
345
|
subtitleSegments?: readonly ValueTextSegment[];
|
|
323
346
|
price: string;
|
|
324
347
|
priceSegments?: readonly ValueTextSegment[];
|
|
@@ -415,6 +438,7 @@ export type SystemRow = RowBase & (Readonly<{
|
|
|
415
438
|
presentation?: 'market';
|
|
416
439
|
message: string;
|
|
417
440
|
actionKey: string;
|
|
441
|
+
actionText?: string;
|
|
418
442
|
}> | Readonly<{
|
|
419
443
|
type: 'system';
|
|
420
444
|
variant: 'warning';
|
|
@@ -524,7 +548,7 @@ export type RowPatch = Readonly<{
|
|
|
524
548
|
}> | Readonly<{
|
|
525
549
|
type: 'market';
|
|
526
550
|
key: string;
|
|
527
|
-
changes: Partial<Pick<MarketRow, CommonPatchFields | 'leading' | 'title' | 'subtitle' | 'subtitleSegments' | 'price' | 'priceSegments' | 'change' | 'badges' | 'pressActionKey' | 'pressInActionKey' | 'longPressActionKey' | 'diagnostics' | 'style'>>;
|
|
551
|
+
changes: Partial<Pick<MarketRow, CommonPatchFields | 'leadingAction' | 'leading' | 'title' | 'subtitle' | 'subtitleSegments' | 'price' | 'priceSegments' | 'change' | 'badges' | 'pressActionKey' | 'pressInActionKey' | 'longPressActionKey' | 'diagnostics' | 'style'>>;
|
|
528
552
|
}> | Readonly<{
|
|
529
553
|
type: 'mediaTile';
|
|
530
554
|
key: string;
|
|
@@ -562,6 +586,11 @@ export type NativeListActionAnchor = Readonly<{
|
|
|
562
586
|
token: string;
|
|
563
587
|
/** Window-relative logical units: CSS px on Web, points on iOS, dp on Android. */
|
|
564
588
|
windowRect: NativeListWindowRect;
|
|
589
|
+
/** Actual long-press point, in the same logical units as windowRect. */
|
|
590
|
+
windowPoint?: Readonly<{
|
|
591
|
+
x: number;
|
|
592
|
+
y: number;
|
|
593
|
+
}>;
|
|
565
594
|
source: NativeListActionSource;
|
|
566
595
|
slot?: number;
|
|
567
596
|
generation: number;
|
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.117",
|
|
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.117",
|
|
87
|
+
"@onekeyfe/react-native-native-logger": "3.0.117",
|
|
88
88
|
"react": "*",
|
|
89
89
|
"react-native": "*",
|
|
90
90
|
"react-native-nitro-modules": "0.37.0"
|