@onekeyfe/react-native-native-list 3.0.157-alpha.248 → 3.0.157-alpha.250
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -5
- package/android/src/main/java/com/onekey/nativelist/NativeListAccessoryStack.kt +711 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListActionRenderer.kt +169 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListActivityRenderer.kt +243 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListAdapter.kt +20 -6
- package/android/src/main/java/com/onekey/nativelist/NativeListDataRowRenderer.kt +487 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListIdentityRenderer.kt +820 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListImageSlot.kt +147 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListLeadingVisual.kt +453 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListMarketRenderer.kt +997 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListMediaTileRenderer.kt +234 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListMessageRenderer.kt +232 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListMetricCardRenderer.kt +551 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListModels.kt +24 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListPrimitives.kt +475 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRailRenderer.kt +143 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRendererRegistry.kt +42 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRendererRowView.kt +415 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListResolvedText.kt +163 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRowHost.kt +70 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListSectionHeaderRenderer.kt +748 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListSystemRenderer.kt +464 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListTextView.kt +25 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListView.kt +174 -104
- package/android/src/main/java/com/onekey/nativelist/NativeListWalletGroupRenderer.kt +407 -0
- package/android/src/test/java/com/margelo/nitro/nativelist/NativeListSelectorBackgroundColorTest.kt +34 -0
- package/docs/DESIGN.md +518 -9
- package/docs/MIGRATION_BASELINE.md +117 -0
- package/docs/ROW_TEMPLATES.md +359 -0
- package/docs/SPEC.md +358 -0
- package/docs/STYLE_SPEC.md +978 -0
- package/docs/images/list-capabilities.svg +39 -0
- package/docs/images/row-action.svg +17 -0
- package/docs/images/row-activity.svg +24 -0
- package/docs/images/row-data.svg +24 -0
- package/docs/images/row-identity.svg +25 -0
- package/docs/images/row-market.svg +23 -0
- package/docs/images/row-media-tile.svg +26 -0
- package/docs/images/row-message.svg +20 -0
- package/docs/images/row-metric-card.svg +33 -0
- package/docs/images/row-rail.svg +18 -0
- package/docs/images/row-section-header.svg +19 -0
- package/docs/images/row-style-regions.svg +30 -0
- package/docs/images/row-system.svg +30 -0
- package/docs/images/row-wallet-group.svg +26 -0
- package/ios/NativeListAccessoryStack.swift +680 -0
- package/ios/NativeListActionRenderer.swift +108 -0
- package/ios/NativeListActivityRenderer.swift +179 -0
- package/ios/NativeListDataRowRenderer.swift +444 -0
- package/ios/NativeListIdentityRenderer.swift +685 -0
- package/ios/NativeListImageSlot.swift +140 -0
- package/ios/NativeListLeadingVisual.swift +372 -0
- package/ios/NativeListMarketRenderer.swift +698 -0
- package/ios/NativeListMediaTileRenderer.swift +184 -0
- package/ios/NativeListMessageRenderer.swift +168 -0
- package/ios/NativeListMetricCardRenderer.swift +420 -0
- package/ios/NativeListModels.swift +32 -0
- package/ios/NativeListRailRenderer.swift +152 -0
- package/ios/NativeListRendererCell.swift +311 -0
- package/ios/NativeListRendererRegistry.swift +50 -0
- package/ios/NativeListResolvedText.swift +122 -0
- package/ios/NativeListRowHost.swift +63 -0
- package/ios/NativeListSectionHeaderRenderer.swift +708 -0
- package/ios/NativeListSystemRenderer.swift +568 -0
- package/ios/NativeListTextLabel.swift +42 -0
- package/ios/NativeListTextStyles.swift +236 -0
- package/ios/NativeListWalletGroupRenderer.swift +255 -0
- package/ios/RNCNativeListView.swift +111 -180
- package/lib/module/models.js +54 -0
- package/lib/module/validation.js +324 -26
- package/lib/module/web/NativeListWebEngine.js +148 -936
- package/lib/module/web/templates/ActionRowRenderer.js +97 -0
- package/lib/module/web/templates/ActivityRowRenderer.js +95 -0
- package/lib/module/web/templates/DataRowRenderer.js +145 -0
- package/lib/module/web/templates/IdentityRowRenderer.js +289 -0
- package/lib/module/web/templates/MarketRowRenderer.js +310 -0
- package/lib/module/web/templates/MediaTileRowRenderer.js +132 -0
- package/lib/module/web/templates/MessageRowRenderer.js +165 -0
- package/lib/module/web/templates/MetricCardRowRenderer.js +172 -0
- package/lib/module/web/templates/RailRowRenderer.js +98 -0
- package/lib/module/web/templates/RowContainerStyle.js +100 -0
- package/lib/module/web/templates/RowElements.js +93 -0
- package/lib/module/web/templates/RowRendererRegistry.js +70 -0
- package/lib/module/web/templates/RowText.js +121 -0
- package/lib/module/web/templates/RowVisual.js +43 -0
- package/lib/module/web/templates/SectionHeaderRowRenderer.js +146 -0
- package/lib/module/web/templates/SystemRowRenderer.js +161 -0
- package/lib/module/web/templates/WalletGroupRowRenderer.js +96 -0
- package/lib/typescript/src/models.d.ts +166 -13
- package/lib/typescript/src/web/NativeListWebEngine.d.ts +18 -16
- package/lib/typescript/src/web/templates/ActionRowRenderer.d.ts +15 -0
- package/lib/typescript/src/web/templates/ActivityRowRenderer.d.ts +15 -0
- package/lib/typescript/src/web/templates/DataRowRenderer.d.ts +15 -0
- package/lib/typescript/src/web/templates/IdentityRowRenderer.d.ts +16 -0
- package/lib/typescript/src/web/templates/MarketRowRenderer.d.ts +30 -0
- package/lib/typescript/src/web/templates/MediaTileRowRenderer.d.ts +15 -0
- package/lib/typescript/src/web/templates/MessageRowRenderer.d.ts +44 -0
- package/lib/typescript/src/web/templates/MetricCardRowRenderer.d.ts +15 -0
- package/lib/typescript/src/web/templates/RailRowRenderer.d.ts +28 -0
- package/lib/typescript/src/web/templates/RowContainerStyle.d.ts +9 -0
- package/lib/typescript/src/web/templates/RowElements.d.ts +38 -0
- package/lib/typescript/src/web/templates/RowRendererRegistry.d.ts +83 -0
- package/lib/typescript/src/web/templates/RowText.d.ts +9 -0
- package/lib/typescript/src/web/templates/RowVisual.d.ts +20 -0
- package/lib/typescript/src/web/templates/SectionHeaderRowRenderer.d.ts +15 -0
- package/lib/typescript/src/web/templates/SystemRowRenderer.d.ts +16 -0
- package/lib/typescript/src/web/templates/WalletGroupRowRenderer.d.ts +20 -0
- package/package.json +3 -3
- package/src/models.ts +281 -19
- package/src/validation.ts +501 -46
- package/src/web/NativeListWebEngine.ts +361 -1932
- package/src/web/templates/ActionRowRenderer.ts +123 -0
- package/src/web/templates/ActivityRowRenderer.ts +159 -0
- package/src/web/templates/DataRowRenderer.ts +212 -0
- package/src/web/templates/IdentityRowRenderer.ts +527 -0
- package/src/web/templates/MarketRowRenderer.ts +467 -0
- package/src/web/templates/MediaTileRowRenderer.ts +182 -0
- package/src/web/templates/MessageRowRenderer.ts +306 -0
- package/src/web/templates/MetricCardRowRenderer.ts +337 -0
- package/src/web/templates/RailRowRenderer.ts +136 -0
- package/src/web/templates/RowContainerStyle.ts +131 -0
- package/src/web/templates/RowElements.ts +160 -0
- package/src/web/templates/RowRendererRegistry.ts +111 -0
- package/src/web/templates/RowText.ts +181 -0
- package/src/web/templates/RowVisual.ts +115 -0
- package/src/web/templates/SectionHeaderRowRenderer.ts +243 -0
- package/src/web/templates/SystemRowRenderer.ts +282 -0
- package/src/web/templates/WalletGroupRowRenderer.ts +131 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRowView.kt +0 -4538
- package/ios/NativeListCell.swift +0 -4300
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
final class NativeListActionCell: NativeListRendererCell {
|
|
4
|
+
override class func measure(
|
|
5
|
+
_ item: NativeListItem, width: CGFloat, theme: [String: Any]?, layout: String
|
|
6
|
+
) -> CGFloat? {
|
|
7
|
+
return item.data.string("presentation") == "accountSelector"
|
|
8
|
+
? 48 : item.data.dictionary("icon") == nil ? 44 : 60
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
private let visual = NativeListLeadingVisual(frame: .zero)
|
|
12
|
+
private let title = NativeListTextLabel()
|
|
13
|
+
private let accessories = NativeListAccessoryStack(frame: .zero)
|
|
14
|
+
private var visualWidth: NSLayoutConstraint!
|
|
15
|
+
private var visualHeight: NSLayoutConstraint!
|
|
16
|
+
override var assetFields: [String] { ["icon"] }
|
|
17
|
+
|
|
18
|
+
override init(frame: CGRect) {
|
|
19
|
+
super.init(frame: frame)
|
|
20
|
+
visual.glyphSize = 24
|
|
21
|
+
root.axis = .horizontal
|
|
22
|
+
root.alignment = .center
|
|
23
|
+
[visual, title, accessories].forEach(root.addArrangedSubview)
|
|
24
|
+
visual.translatesAutoresizingMaskIntoConstraints = false
|
|
25
|
+
visualWidth = visual.widthAnchor.constraint(equalToConstant: 40)
|
|
26
|
+
visualHeight = visual.heightAnchor.constraint(equalToConstant: 40)
|
|
27
|
+
NSLayoutConstraint.activate([visualWidth, visualHeight])
|
|
28
|
+
title.setContentHuggingPriority(UILayoutPriority(1), for: .horizontal)
|
|
29
|
+
title.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
|
30
|
+
accessories.onAction = { [weak self] key, view, slot, target in
|
|
31
|
+
self?.emitAction(
|
|
32
|
+
key, from: view, source: "trailingAccessory", slot: slot, target: target,
|
|
33
|
+
anchorInset: self?.accessories.anchorInset(for: view) ?? 0)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
|
|
37
|
+
override func bindContent(
|
|
38
|
+
_ item: NativeListItem, theme: [String: Any]?, layout: String,
|
|
39
|
+
checkboxState: (NativeListItem, NativeSelectionTarget?, String) -> String
|
|
40
|
+
) {
|
|
41
|
+
let style = item.data.dictionary("style") ?? [:]
|
|
42
|
+
root.alignment =
|
|
43
|
+
style.dictionary("container")?.string("contentVerticalAlignment") == "top"
|
|
44
|
+
? .top
|
|
45
|
+
: style.dictionary("container")?.string("contentVerticalAlignment") == "bottom"
|
|
46
|
+
? .bottom : .center
|
|
47
|
+
let selector = item.data.string("presentation") == "accountSelector"
|
|
48
|
+
let icon = item.data.dictionary("icon")
|
|
49
|
+
let descriptors =
|
|
50
|
+
item.data.dictionary("checkbox").map { checkbox -> [[String: Any]] in
|
|
51
|
+
var checkbox = checkbox
|
|
52
|
+
if checkbox["kind"] == nil { checkbox["kind"] = "checkbox" }
|
|
53
|
+
return [checkbox]
|
|
54
|
+
} ?? item.data.dictionaries("trailing")
|
|
55
|
+
accessories.bind(
|
|
56
|
+
item, descriptors: descriptors, theme: theme, style: style, checkboxState: checkboxState)
|
|
57
|
+
let hp = CGFloat(style.double("horizontalPadding", default: layout == "table" ? 16 : 12))
|
|
58
|
+
let vp = CGFloat(style.double("verticalPadding", default: 8))
|
|
59
|
+
let end =
|
|
60
|
+
descriptors.count == 1 && descriptors[0].string("kind") == "chevron"
|
|
61
|
+
? 6 : accessories.endInset ?? hp
|
|
62
|
+
contentInsets = UIEdgeInsets(
|
|
63
|
+
top: vp, left: hp, bottom: vp, right: style["horizontalPadding"] == nil ? end : hp)
|
|
64
|
+
root.spacing = 12
|
|
65
|
+
root.setCustomSpacing(CGFloat(style.double("leadingGap", default: 12)), after: visual)
|
|
66
|
+
root.setCustomSpacing(accessories.contentGap ?? 12, after: title)
|
|
67
|
+
let tone = item.data.string("tone")
|
|
68
|
+
let color =
|
|
69
|
+
selector
|
|
70
|
+
? nativeListColor(
|
|
71
|
+
theme, tone == "primary" ? "primaryText" : "secondaryText",
|
|
72
|
+
tone == "primary" ? "#202020" : "#646464")
|
|
73
|
+
: nativeListColor(
|
|
74
|
+
theme, tone == "danger" ? "negative" : "primaryText",
|
|
75
|
+
tone == "danger" ? "#CE2C31" : "#202020")
|
|
76
|
+
NativeListResolvedText(
|
|
77
|
+
item.data.string("title"), style: style.dictionary("title"), size: 16,
|
|
78
|
+
weight: selector && icon == nil ? .regular : .medium, color: color, lineHeight: 24, lines: 1
|
|
79
|
+
).bind(title)
|
|
80
|
+
visual.isHidden = icon == nil
|
|
81
|
+
if var icon {
|
|
82
|
+
// Legacy kept the icon hairline border unless the selector or a transparent default
|
|
83
|
+
// background (no explicit backgroundColor) removed it.
|
|
84
|
+
let keepsBorder = !selector && icon["backgroundColor"] != nil
|
|
85
|
+
if icon["backgroundColor"] == nil { icon["backgroundColor"] = "#00000000" }
|
|
86
|
+
var image = style.dictionary("image") ?? [:]
|
|
87
|
+
if selector && image["cornerRadius"] == nil && image["shape"] == nil {
|
|
88
|
+
image["cornerRadius"] = 8
|
|
89
|
+
}
|
|
90
|
+
visualWidth.constant = CGFloat(image.double("width", default: selector ? 32 : 40))
|
|
91
|
+
visualHeight.constant = CGFloat(image.double("height", default: selector ? 32 : 40))
|
|
92
|
+
visual.bind(icon, style: image, key: item.key, theme: theme, isUnread: false)
|
|
93
|
+
if !keepsBorder { visual.layer.borderWidth = 0 }
|
|
94
|
+
} else {
|
|
95
|
+
visual.recycle()
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
override func bindSelectionContent(
|
|
99
|
+
_ item: NativeListItem,
|
|
100
|
+
checkboxState: (NativeListItem, NativeSelectionTarget?, String) -> String
|
|
101
|
+
) {
|
|
102
|
+
accessories.updateSelection(item, checkboxState: checkboxState)
|
|
103
|
+
}
|
|
104
|
+
override func recycleContent() {
|
|
105
|
+
visual.recycle()
|
|
106
|
+
accessories.reset()
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
final class NativeListActivityCell: NativeListRendererCell {
|
|
4
|
+
override class func measure(
|
|
5
|
+
_ item: NativeListItem, width: CGFloat, theme: [String: Any]?, layout: String
|
|
6
|
+
) -> CGFloat? {
|
|
7
|
+
return item.data.dictionaries("footerActions").isEmpty ? 60 : 100
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
private let visual = NativeListLeadingVisual()
|
|
11
|
+
private let column = UIStackView()
|
|
12
|
+
private let titleLine = UIStackView()
|
|
13
|
+
private let title = NativeListTextLabel()
|
|
14
|
+
private let descriptionLabel = NativeListTextLabel()
|
|
15
|
+
private let status = NativeListTextLabel()
|
|
16
|
+
private let failure = NativeListTextLabel()
|
|
17
|
+
private let amounts = UIStackView()
|
|
18
|
+
private let amountLabels = [
|
|
19
|
+
NativeListAccessoryButton(type: .system), NativeListAccessoryButton(type: .system),
|
|
20
|
+
]
|
|
21
|
+
private let actions = UIStackView()
|
|
22
|
+
private let buttons = (0..<3).map { _ in UIButton(type: .system) }
|
|
23
|
+
private var actionKeys: [String] = []
|
|
24
|
+
private var dimensions: [NSLayoutConstraint] = []
|
|
25
|
+
override var assetFields: [String] { ["leading", "secondaryLeading"] }
|
|
26
|
+
|
|
27
|
+
override init(frame: CGRect) {
|
|
28
|
+
super.init(frame: frame)
|
|
29
|
+
root.axis = .horizontal
|
|
30
|
+
column.axis = .vertical
|
|
31
|
+
column.alignment = .fill
|
|
32
|
+
column.setContentHuggingPriority(UILayoutPriority(1), for: .horizontal)
|
|
33
|
+
column.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
|
|
34
|
+
titleLine.axis = .horizontal
|
|
35
|
+
titleLine.alignment = .center
|
|
36
|
+
titleLine.spacing = 8
|
|
37
|
+
title.setContentCompressionResistancePriority(.required, for: .horizontal)
|
|
38
|
+
failure.setContentHuggingPriority(.required, for: .horizontal)
|
|
39
|
+
titleLine.addArrangedSubview(title)
|
|
40
|
+
titleLine.addArrangedSubview(failure)
|
|
41
|
+
[titleLine, descriptionLabel, status, actions].forEach(column.addArrangedSubview)
|
|
42
|
+
amounts.axis = .vertical
|
|
43
|
+
amounts.alignment = .trailing
|
|
44
|
+
amounts.setContentHuggingPriority(.required, for: .horizontal)
|
|
45
|
+
amounts.setContentCompressionResistancePriority(.required, for: .horizontal)
|
|
46
|
+
amountLabels.forEach {
|
|
47
|
+
amounts.addArrangedSubview($0)
|
|
48
|
+
// Legacy amounts keep their full width; the text column yields first.
|
|
49
|
+
$0.setContentHuggingPriority(.required, for: .horizontal)
|
|
50
|
+
$0.setContentCompressionResistancePriority(.required, for: .horizontal)
|
|
51
|
+
}
|
|
52
|
+
actions.axis = .horizontal
|
|
53
|
+
actions.alignment = .center
|
|
54
|
+
actions.spacing = 8
|
|
55
|
+
for (index, button) in buttons.enumerated() {
|
|
56
|
+
button.tag = index
|
|
57
|
+
button.titleLabel?.font = nativeListFont(ofSize: 12, weight: .medium)
|
|
58
|
+
button.layer.cornerRadius = 8
|
|
59
|
+
button.contentEdgeInsets = UIEdgeInsets(top: 4, left: 8, bottom: 4, right: 8)
|
|
60
|
+
button.addTarget(self, action: #selector(pressed(_:)), for: .touchUpInside)
|
|
61
|
+
actions.addArrangedSubview(button)
|
|
62
|
+
}
|
|
63
|
+
[visual, column, amounts].forEach(root.addArrangedSubview)
|
|
64
|
+
}
|
|
65
|
+
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
|
|
66
|
+
override func bindContent(
|
|
67
|
+
_ item: NativeListItem, theme: [String: Any]?, layout: String,
|
|
68
|
+
checkboxState: (NativeListItem, NativeSelectionTarget?, String) -> String
|
|
69
|
+
) {
|
|
70
|
+
let data = item.data
|
|
71
|
+
let style = data.dictionary("style") ?? [:]
|
|
72
|
+
let image = style.dictionary("image") ?? [:]
|
|
73
|
+
root.spacing = 12
|
|
74
|
+
root.setCustomSpacing(CGFloat(style.double("leadingGap", default: 12)), after: visual)
|
|
75
|
+
switch style.dictionary("container")?.string("contentVerticalAlignment") {
|
|
76
|
+
case "top": root.alignment = .top
|
|
77
|
+
case "bottom": root.alignment = .bottom
|
|
78
|
+
default: root.alignment = .center
|
|
79
|
+
}
|
|
80
|
+
column.spacing = CGFloat(style.double("lineGap"))
|
|
81
|
+
titleLine.spacing = CGFloat(style.double("titleBadgeGap", default: 8))
|
|
82
|
+
amounts.spacing = CGFloat(style.double("trailingGap", default: 2))
|
|
83
|
+
contentInsets = UIEdgeInsets(
|
|
84
|
+
top: CGFloat(style.double("verticalPadding", default: 8)),
|
|
85
|
+
left: CGFloat(style.double("horizontalPadding", default: layout == "table" ? 16 : 12)),
|
|
86
|
+
bottom: CGFloat(style.double("verticalPadding", default: 8)),
|
|
87
|
+
right: CGFloat(style.double("horizontalPadding", default: layout == "table" ? 16 : 12)))
|
|
88
|
+
NSLayoutConstraint.deactivate(dimensions)
|
|
89
|
+
dimensions = [
|
|
90
|
+
visual.widthAnchor.constraint(equalToConstant: CGFloat(image.double("width", default: 40))),
|
|
91
|
+
visual.heightAnchor.constraint(equalToConstant: CGFloat(image.double("height", default: 40))),
|
|
92
|
+
]
|
|
93
|
+
NSLayoutConstraint.activate(dimensions)
|
|
94
|
+
if let leading = data.dictionary("leading") {
|
|
95
|
+
visual.bind(
|
|
96
|
+
leading, style: image, key: item.key, theme: theme, isUnread: false,
|
|
97
|
+
secondaryVisual: data.dictionary("secondaryLeading"))
|
|
98
|
+
} else {
|
|
99
|
+
// Legacy kept an empty leading slot (no placeholder disc) when no visual was given.
|
|
100
|
+
visual.clear()
|
|
101
|
+
}
|
|
102
|
+
func bind(
|
|
103
|
+
_ view: NativeListTextLabel, _ value: String, _ slot: String, size: CGFloat,
|
|
104
|
+
weight: NativeListFontWeight = .regular, color: UIColor, line: CGFloat, lines: Int = 1
|
|
105
|
+
) {
|
|
106
|
+
NativeListResolvedText(
|
|
107
|
+
value, style: style.dictionary(slot), size: size, weight: weight, color: color,
|
|
108
|
+
lineHeight: line, lines: lines
|
|
109
|
+
).bind(view)
|
|
110
|
+
}
|
|
111
|
+
bind(
|
|
112
|
+
title, data.string("title"), "title", size: 16, weight: .medium,
|
|
113
|
+
color: nativeListColor(theme, "primaryText", "#202020"), line: 24)
|
|
114
|
+
bind(
|
|
115
|
+
descriptionLabel, data.string("description"), "description", size: 14,
|
|
116
|
+
color: nativeListColor(theme, "secondaryText", "#646464"), line: 20, lines: 2)
|
|
117
|
+
let failed = data.string("status") == "Failed"
|
|
118
|
+
bind(
|
|
119
|
+
status, failed ? "" : data.string("status"), "status", size: 12,
|
|
120
|
+
color: nativeListColor(theme, "secondaryText", "#646464"),
|
|
121
|
+
line: nativeListFont(ofSize: 12).lineHeight)
|
|
122
|
+
bind(
|
|
123
|
+
failure, failed ? " Failed " : "", "status", size: 12, weight: .medium,
|
|
124
|
+
color: nativeListColor(theme, "negative", "#CE2C31"),
|
|
125
|
+
line: nativeListFont(ofSize: 12, weight: .medium).lineHeight)
|
|
126
|
+
failure.backgroundColor = nativeListColor(theme, "criticalBackground", "#F3000D14")
|
|
127
|
+
failure.layer.cornerRadius = 4
|
|
128
|
+
failure.clipsToBounds = true
|
|
129
|
+
for (index, slot) in ["primaryAmount", "secondaryAmount"].enumerated() {
|
|
130
|
+
let button = amountLabels[index]
|
|
131
|
+
let value = data.string(slot)
|
|
132
|
+
let color =
|
|
133
|
+
index == 0
|
|
134
|
+
? nativeListColor(
|
|
135
|
+
theme, value.hasPrefix("+") ? "positive" : "primaryText",
|
|
136
|
+
value.hasPrefix("+") ? "#218358" : "#202020")
|
|
137
|
+
: nativeListColor(theme, "secondaryText", "#646464")
|
|
138
|
+
button.titleLabel?.numberOfLines = 1
|
|
139
|
+
button.titleLabel?.lineBreakMode = .byTruncatingTail
|
|
140
|
+
button.contentHorizontalAlignment = .center
|
|
141
|
+
button.contentVerticalAlignment = .center
|
|
142
|
+
button.rowTextOffsetY = 0
|
|
143
|
+
let resolved = NativeListResolvedText(
|
|
144
|
+
value, style: nil, size: index == 0 ? 16 : 14, weight: index == 0 ? .medium : .regular,
|
|
145
|
+
color: color, lineHeight: index == 0 ? 24 : 20, lines: 1, tabular: true)
|
|
146
|
+
button.setAttributedTitle(
|
|
147
|
+
resolved.attributed(direction: button.effectiveUserInterfaceLayoutDirection), for: .normal)
|
|
148
|
+
button.titleLabel?.font = resolved.font
|
|
149
|
+
button.isHidden = value.isEmpty
|
|
150
|
+
if let text = style.dictionary(slot) { NativeListTextStyles.applyStyledButton(button, text) }
|
|
151
|
+
}
|
|
152
|
+
let descriptors = Array(data.dictionaries("footerActions").prefix(3))
|
|
153
|
+
actions.isHidden = descriptors.isEmpty
|
|
154
|
+
actionKeys = descriptors.map { $0.string("key") }
|
|
155
|
+
for (index, button) in buttons.enumerated() {
|
|
156
|
+
button.isHidden = index >= descriptors.count
|
|
157
|
+
guard index < descriptors.count else { continue }
|
|
158
|
+
let action = descriptors[index]
|
|
159
|
+
button.setTitle(action.string("label"), for: .normal)
|
|
160
|
+
// Legacy: only the action's own flag disables it; a disabled row is already dimmed
|
|
161
|
+
// and non-interactive as a whole.
|
|
162
|
+
button.isEnabled = !action.bool("disabled")
|
|
163
|
+
button.backgroundColor = nativeListColor(theme, "strongBackground", "#F0F0F0")
|
|
164
|
+
button.setTitleColor(
|
|
165
|
+
nativeListColor(
|
|
166
|
+
theme, action.string("tone") == "danger" ? "negative" : "primaryText",
|
|
167
|
+
action.string("tone") == "danger" ? "#CE2C31" : "#202020"), for: .normal)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
@objc private func pressed(_ button: UIButton) {
|
|
171
|
+
guard button.tag < actionKeys.count else { return }
|
|
172
|
+
emitAction(actionKeys[button.tag], from: button, source: "footerAction", slot: button.tag)
|
|
173
|
+
}
|
|
174
|
+
override func recycleContent() {
|
|
175
|
+
visual.recycle()
|
|
176
|
+
actionKeys = []
|
|
177
|
+
buttons.forEach { $0.isHidden = true }
|
|
178
|
+
}
|
|
179
|
+
}
|