@onekeyfe/react-native-native-list 6.7.0-alpha.375 → 6.7.0-alpha.382
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/HybridNativeList.kt +14 -1
- package/android/src/main/java/com/onekey/nativelist/NativeListAccessoryStack.kt +240 -11
- package/android/src/main/java/com/onekey/nativelist/NativeListActivityDetailsView.kt +7 -4
- package/android/src/main/java/com/onekey/nativelist/NativeListActivityRenderer.kt +6 -3
- package/android/src/main/java/com/onekey/nativelist/NativeListButtonGroupRenderer.kt +102 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListContainerSlotAdapter.kt +12 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListDataRowRenderer.kt +87 -7
- package/android/src/main/java/com/onekey/nativelist/NativeListIdentityRenderer.kt +177 -1
- package/android/src/main/java/com/onekey/nativelist/NativeListLeadingVisual.kt +43 -14
- package/android/src/main/java/com/onekey/nativelist/NativeListMessageRenderer.kt +25 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListModels.kt +33 -2
- package/android/src/main/java/com/onekey/nativelist/NativeListPrimitives.kt +22 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRendererRegistry.kt +2 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRendererRowView.kt +2 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListResolvedText.kt +3 -2
- package/android/src/main/java/com/onekey/nativelist/NativeListSectionHeaderRenderer.kt +69 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListTextView.kt +55 -1
- package/android/src/main/java/com/onekey/nativelist/NativeListView.kt +1912 -107
- package/android/src/test/java/com/margelo/nitro/nativelist/NativeListPressPolicyTest.kt +1 -0
- package/docs/ROW_TEMPLATES.md +60 -9
- package/docs/SPEC.md +450 -5
- package/docs/STYLE_SPEC.md +6 -0
- package/ios/HybridNativeList.swift +21 -2
- package/ios/NativeListAccessoryStack.swift +227 -39
- package/ios/NativeListActivityDetailsView.swift +18 -8
- package/ios/NativeListActivityRenderer.swift +8 -2
- package/ios/NativeListButtonGroupRenderer.swift +89 -0
- package/ios/NativeListDataRowRenderer.swift +155 -27
- package/ios/NativeListDesignAssets.swift +3 -0
- package/ios/NativeListIdentityRenderer.swift +166 -30
- package/ios/NativeListLeadingVisual.swift +49 -14
- package/ios/NativeListMessageRenderer.swift +34 -1
- package/ios/NativeListModels.swift +42 -2
- package/ios/NativeListRendererRegistry.swift +1 -0
- package/ios/NativeListResolvedText.swift +2 -1
- package/ios/NativeListRowHost.swift +14 -0
- package/ios/NativeListSectionHeaderRenderer.swift +88 -0
- package/ios/RNCNativeListView.swift +1013 -55
- package/ios/Resources/NativeListIcons.xcassets/onekey_crypto_coin_outline.imageset/Contents.json +15 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_crypto_coin_outline.imageset/icon.svg +4 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_gas_solid.imageset/Contents.json +15 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_gas_solid.imageset/icon.svg +3 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_refresh_ccw_outline.imageset/Contents.json +15 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_refresh_ccw_outline.imageset/icon.svg +3 -0
- package/ios/tests/NativeListActivityPresentationTests.swift +56 -0
- package/ios/tests/NativeListLifecycleTests.swift +2720 -3
- package/lib/module/NativeList.js +175 -28
- package/lib/module/NativeList.web.js +129 -30
- package/lib/module/index.js +1 -1
- package/lib/module/models.js +1 -0
- package/lib/module/selection.js +1 -1
- package/lib/module/validation.js +421 -8
- package/lib/module/web/NativeListWebEngine.js +507 -19
- package/lib/module/web/templates/ActivityRowRenderer.js +8 -7
- package/lib/module/web/templates/ButtonGroupRowRenderer.js +47 -0
- package/lib/module/web/templates/DataRowRenderer.js +40 -5
- package/lib/module/web/templates/IdentityRowRenderer.js +90 -4
- package/lib/module/web/templates/MessageRowRenderer.js +18 -2
- package/lib/module/web/templates/RowContainerStyle.js +1 -0
- package/lib/module/web/templates/RowRendererRegistry.js +3 -0
- package/lib/module/web/templates/SectionHeaderRowRenderer.js +36 -2
- package/lib/nitrogen/generated/android/c++/JHybridNativeListSpec.cpp +26 -0
- package/lib/nitrogen/generated/android/c++/JHybridNativeListSpec.hpp +4 -0
- package/lib/nitrogen/generated/android/c++/views/JHybridNativeListStateUpdater.cpp +10 -0
- package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/HybridNativeListSpec.kt +20 -0
- package/lib/nitrogen/generated/ios/c++/HybridNativeListSpecSwift.hpp +14 -0
- package/lib/nitrogen/generated/ios/c++/views/HybridNativeListComponent.mm +12 -0
- package/lib/nitrogen/generated/ios/swift/HybridNativeListSpec.swift +2 -0
- package/lib/nitrogen/generated/ios/swift/HybridNativeListSpec_cxx.swift +43 -0
- package/lib/nitrogen/generated/shared/c++/HybridNativeListSpec.cpp +4 -0
- package/lib/nitrogen/generated/shared/c++/HybridNativeListSpec.hpp +4 -0
- package/lib/nitrogen/generated/shared/c++/views/HybridNativeListComponent.cpp +4 -0
- package/lib/nitrogen/generated/shared/c++/views/HybridNativeListComponent.hpp +6 -0
- package/lib/nitrogen/generated/shared/json/NativeListConfig.json +2 -0
- package/lib/typescript/src/NativeList.d.ts +1 -1
- package/lib/typescript/src/NativeList.nitro.d.ts +2 -0
- package/lib/typescript/src/NativeList.types.d.ts +18 -0
- package/lib/typescript/src/index.d.ts +2 -2
- package/lib/typescript/src/models.d.ts +105 -9
- package/lib/typescript/src/validation.d.ts +12 -0
- package/lib/typescript/src/web/NativeListWebEngine.d.ts +32 -0
- package/lib/typescript/src/web/templates/ButtonGroupRowRenderer.d.ts +14 -0
- package/lib/typescript/src/web/templates/IdentityRowRenderer.d.ts +1 -1
- package/lib/typescript/src/web/templates/MessageRowRenderer.d.ts +9 -3
- package/nitrogen/generated/android/c++/JHybridNativeListSpec.cpp +26 -0
- package/nitrogen/generated/android/c++/JHybridNativeListSpec.hpp +4 -0
- package/nitrogen/generated/android/c++/views/JHybridNativeListStateUpdater.cpp +10 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/HybridNativeListSpec.kt +20 -0
- package/nitrogen/generated/ios/c++/HybridNativeListSpecSwift.hpp +14 -0
- package/nitrogen/generated/ios/c++/views/HybridNativeListComponent.mm +12 -0
- package/nitrogen/generated/ios/swift/HybridNativeListSpec.swift +2 -0
- package/nitrogen/generated/ios/swift/HybridNativeListSpec_cxx.swift +43 -0
- package/nitrogen/generated/shared/c++/HybridNativeListSpec.cpp +4 -0
- package/nitrogen/generated/shared/c++/HybridNativeListSpec.hpp +4 -0
- package/nitrogen/generated/shared/c++/views/HybridNativeListComponent.cpp +4 -0
- package/nitrogen/generated/shared/c++/views/HybridNativeListComponent.hpp +6 -0
- package/nitrogen/generated/shared/json/NativeListConfig.json +2 -0
- package/package.json +3 -3
- package/react-native-native-list.podspec +1 -0
- package/src/NativeList.nitro.ts +2 -0
- package/src/NativeList.tsx +313 -44
- package/src/NativeList.types.ts +22 -0
- package/src/NativeList.web.tsx +204 -48
- package/src/index.ts +2 -0
- package/src/models.ts +117 -3
- package/src/selection.ts +1 -0
- package/src/validation.ts +852 -6
- package/src/web/NativeListWebEngine.ts +803 -20
- package/src/web/templates/ActivityRowRenderer.ts +14 -6
- package/src/web/templates/ButtonGroupRowRenderer.ts +58 -0
- package/src/web/templates/DataRowRenderer.ts +93 -20
- package/src/web/templates/IdentityRowRenderer.ts +150 -5
- package/src/web/templates/MessageRowRenderer.ts +23 -7
- package/src/web/templates/RowContainerStyle.ts +2 -0
- package/src/web/templates/RowRendererRegistry.ts +11 -1
- package/src/web/templates/SectionHeaderRowRenderer.ts +47 -4
|
@@ -6,7 +6,7 @@ final class NativeListDataRowCell: NativeListRendererCell {
|
|
|
6
6
|
fonts: NativeListFontFamilies
|
|
7
7
|
) -> CGFloat? {
|
|
8
8
|
let secondary = item.data.dictionaries("columns").contains {
|
|
9
|
-
|
|
9
|
+
!nativeListDataColumnText($0, "secondaryText").isEmpty
|
|
10
10
|
}
|
|
11
11
|
return secondary ? 60 : layout == "table" ? 48 : 56
|
|
12
12
|
}
|
|
@@ -14,9 +14,13 @@ final class NativeListDataRowCell: NativeListRendererCell {
|
|
|
14
14
|
private let visual = NativeListLeadingVisual()
|
|
15
15
|
private let favorite = UIImageView()
|
|
16
16
|
private let accessories = NativeListAccessoryStack()
|
|
17
|
+
private let trailingAccessories = NativeListAccessoryStack()
|
|
17
18
|
private let columns = UIStackView()
|
|
18
19
|
private let cells = (0..<4).map { _ in NativeListTableColumnView() }
|
|
19
20
|
private var rowConstraints: [NSLayoutConstraint] = []
|
|
21
|
+
private var trailingWidthConstraint: NSLayoutConstraint?
|
|
22
|
+
private var columnWidthConstraints: [NSLayoutConstraint] = []
|
|
23
|
+
private var columnWeights: [Int]?
|
|
20
24
|
override func unselectedBackground(
|
|
21
25
|
_ item: NativeListItem, theme: [String: Any]?, layout: String, itemIndex: Int?
|
|
22
26
|
) -> UIColor {
|
|
@@ -34,10 +38,13 @@ final class NativeListDataRowCell: NativeListRendererCell {
|
|
|
34
38
|
columns.alignment = .center
|
|
35
39
|
columns.spacing = 8
|
|
36
40
|
cells.forEach(columns.addArrangedSubview)
|
|
37
|
-
[favorite, visual, accessories, columns].forEach(root.addArrangedSubview)
|
|
41
|
+
[favorite, visual, accessories, columns, trailingAccessories].forEach(root.addArrangedSubview)
|
|
38
42
|
accessories.onAction = { [weak self] key, view, slot, target in
|
|
39
43
|
self?.emitAction(key, from: view, source: "trailingAccessory", slot: slot, target: target)
|
|
40
44
|
}
|
|
45
|
+
trailingAccessories.onAction = { [weak self] key, view, slot, target in
|
|
46
|
+
self?.emitAction(key, from: view, source: "trailingAccessory", slot: slot, target: target)
|
|
47
|
+
}
|
|
41
48
|
}
|
|
42
49
|
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
|
|
43
50
|
override func bindContent(
|
|
@@ -86,16 +93,55 @@ final class NativeListDataRowCell: NativeListRendererCell {
|
|
|
86
93
|
item, descriptors: descriptors, theme: theme, style: accessoryStyle,
|
|
87
94
|
checkboxState: checkboxState, fonts: fonts)
|
|
88
95
|
accessories.isHidden = descriptors.isEmpty
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
+
let trailing = data.dictionaries("trailing")
|
|
97
|
+
trailingAccessories.bind(
|
|
98
|
+
item, descriptors: trailing, theme: theme, style: style,
|
|
99
|
+
checkboxState: checkboxState, fonts: fonts)
|
|
100
|
+
trailingAccessories.isHidden = trailing.isEmpty
|
|
101
|
+
if rowConstraints.isEmpty {
|
|
102
|
+
rowConstraints = [
|
|
103
|
+
favorite.widthAnchor.constraint(equalToConstant: 20),
|
|
104
|
+
favorite.heightAnchor.constraint(equalToConstant: 20),
|
|
105
|
+
visual.widthAnchor.constraint(equalToConstant: 40),
|
|
106
|
+
visual.heightAnchor.constraint(equalToConstant: 40),
|
|
107
|
+
]
|
|
108
|
+
NSLayoutConstraint.activate(rowConstraints)
|
|
109
|
+
}
|
|
110
|
+
let visualWidth = CGFloat(image.double("width", default: 40))
|
|
111
|
+
let visualHeight = CGFloat(image.double("height", default: 40))
|
|
112
|
+
if rowConstraints[2].constant != visualWidth { rowConstraints[2].constant = visualWidth }
|
|
113
|
+
if rowConstraints[3].constant != visualHeight { rowConstraints[3].constant = visualHeight }
|
|
114
|
+
if !trailing.isEmpty {
|
|
115
|
+
// UIStackView has no intrinsic width of its own. Reserve the controls' fitted
|
|
116
|
+
// width so extra space goes to the weighted columns instead of this stack.
|
|
117
|
+
if trailingWidthConstraint == nil {
|
|
118
|
+
trailingWidthConstraint = trailingAccessories.widthAnchor.constraint(equalToConstant: 0)
|
|
119
|
+
}
|
|
120
|
+
if trailingWidthConstraint?.isActive == true { trailingWidthConstraint?.isActive = false }
|
|
121
|
+
let trailingWidth =
|
|
122
|
+
trailingAccessories.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).width
|
|
123
|
+
if trailingWidthConstraint?.constant != trailingWidth {
|
|
124
|
+
trailingWidthConstraint?.constant = trailingWidth
|
|
125
|
+
}
|
|
126
|
+
trailingWidthConstraint?.isActive = true
|
|
127
|
+
} else {
|
|
128
|
+
if trailingWidthConstraint?.isActive == true { trailingWidthConstraint?.isActive = false }
|
|
129
|
+
}
|
|
96
130
|
let values = Array(data.dictionaries("columns").prefix(4))
|
|
131
|
+
let weights = values.map { max(1, $0.int("weight", default: 1)) }
|
|
132
|
+
var divisor = weights.first ?? 1
|
|
133
|
+
for weight in weights.dropFirst() {
|
|
134
|
+
var a = divisor
|
|
135
|
+
var b = weight
|
|
136
|
+
while b != 0 { (a, b) = (b, a % b) }
|
|
137
|
+
divisor = a
|
|
138
|
+
}
|
|
139
|
+
let normalizedWeights = weights.map { $0 / divisor }
|
|
140
|
+
let columnsChanged = columnWeights != normalizedWeights
|
|
141
|
+
if columnsChanged { NSLayoutConstraint.deactivate(columnWidthConstraints) }
|
|
97
142
|
for (index, cell) in cells.enumerated() {
|
|
98
|
-
|
|
143
|
+
let hidden = index >= values.count
|
|
144
|
+
if cell.isHidden != hidden { cell.isHidden = hidden }
|
|
99
145
|
guard index < values.count else {
|
|
100
146
|
cell.reset()
|
|
101
147
|
continue
|
|
@@ -109,23 +155,29 @@ final class NativeListDataRowCell: NativeListRendererCell {
|
|
|
109
155
|
cell.applyStyle(style) { label, style in
|
|
110
156
|
NativeListTextStyles.applyStyledText(label, style, fonts: fonts)
|
|
111
157
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
158
|
+
cell.applySegments(values[index])
|
|
159
|
+
cell.bindTitleIcons(values[index], theme: theme)
|
|
160
|
+
}
|
|
161
|
+
if columnsChanged {
|
|
162
|
+
columnWidthConstraints = values.count > 1 ? (1..<values.count).map { index in
|
|
163
|
+
cells[index].widthAnchor.constraint(equalTo: cells[0].widthAnchor,
|
|
164
|
+
multiplier: CGFloat(weights[index]) / CGFloat(weights[0]))
|
|
165
|
+
} : []
|
|
166
|
+
NSLayoutConstraint.activate(columnWidthConstraints)
|
|
167
|
+
columnWeights = normalizedWeights
|
|
119
168
|
}
|
|
120
|
-
NSLayoutConstraint.activate(rowConstraints)
|
|
121
169
|
}
|
|
122
170
|
override func bindSelectionContent(
|
|
123
171
|
_ item: NativeListItem,
|
|
124
172
|
checkboxState: (NativeListItem, NativeSelectionTarget?, String) -> String
|
|
125
|
-
) {
|
|
173
|
+
) {
|
|
174
|
+
accessories.updateSelection(item, checkboxState: checkboxState)
|
|
175
|
+
trailingAccessories.updateSelection(item, checkboxState: checkboxState)
|
|
176
|
+
}
|
|
126
177
|
override func recycleContent() {
|
|
127
178
|
visual.recycle()
|
|
128
179
|
accessories.reset()
|
|
180
|
+
trailingAccessories.reset()
|
|
129
181
|
cells.forEach { $0.reset() }
|
|
130
182
|
}
|
|
131
183
|
}
|
|
@@ -133,6 +185,8 @@ final class NativeListDataRowCell: NativeListRendererCell {
|
|
|
133
185
|
private final class NativeListTableColumnView: UIStackView {
|
|
134
186
|
private let primaryLine = UIStackView()
|
|
135
187
|
private let primaryLabel = NativeListTextLabel()
|
|
188
|
+
private let titleIconView = UIImageView()
|
|
189
|
+
private let secondaryTitleIconView = UIImageView()
|
|
136
190
|
private let badgesStack = UIStackView()
|
|
137
191
|
private let secondaryLine = UIStackView()
|
|
138
192
|
private let secondaryLeadingLabel = NativeListTextLabel()
|
|
@@ -152,11 +206,21 @@ private final class NativeListTableColumnView: UIStackView {
|
|
|
152
206
|
primaryLabel.numberOfLines = 1
|
|
153
207
|
primaryLabel.lineBreakMode = .byTruncatingTail
|
|
154
208
|
primaryLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
|
209
|
+
for icon in [titleIconView, secondaryTitleIconView] {
|
|
210
|
+
icon.contentMode = .scaleAspectFit
|
|
211
|
+
icon.translatesAutoresizingMaskIntoConstraints = false
|
|
212
|
+
icon.widthAnchor.constraint(equalToConstant: 20).isActive = true
|
|
213
|
+
icon.heightAnchor.constraint(equalToConstant: 20).isActive = true
|
|
214
|
+
icon.setContentHuggingPriority(.required, for: .horizontal)
|
|
215
|
+
icon.isHidden = true
|
|
216
|
+
}
|
|
155
217
|
badgesStack.axis = .horizontal
|
|
156
218
|
badgesStack.alignment = .center
|
|
157
219
|
badgesStack.spacing = 4
|
|
158
220
|
badgesStack.setContentCompressionResistancePriority(.required, for: .horizontal)
|
|
159
221
|
primaryLine.addArrangedSubview(primaryLabel)
|
|
222
|
+
primaryLine.addArrangedSubview(titleIconView)
|
|
223
|
+
primaryLine.addArrangedSubview(secondaryTitleIconView)
|
|
160
224
|
primaryLine.addArrangedSubview(badgesStack)
|
|
161
225
|
|
|
162
226
|
secondaryLine.axis = .horizontal
|
|
@@ -178,8 +242,17 @@ private final class NativeListTableColumnView: UIStackView {
|
|
|
178
242
|
fatalError("init(coder:) has not been implemented")
|
|
179
243
|
}
|
|
180
244
|
|
|
181
|
-
func reset() {
|
|
245
|
+
func reset(clearPrimaryText: Bool = true) {
|
|
182
246
|
linear = false
|
|
247
|
+
primaryLine.alignment = .center
|
|
248
|
+
for icon in [titleIconView, secondaryTitleIconView] {
|
|
249
|
+
icon.image = nil
|
|
250
|
+
icon.isHidden = true
|
|
251
|
+
icon.accessibilityLabel = nil
|
|
252
|
+
icon.isAccessibilityElement = false
|
|
253
|
+
}
|
|
254
|
+
primaryLine.setCustomSpacing(UIStackView.spacingUseDefault, after: primaryLabel)
|
|
255
|
+
primaryLine.setCustomSpacing(UIStackView.spacingUseDefault, after: titleIconView)
|
|
183
256
|
for label in [primaryLabel, secondaryLeadingLabel, secondaryLabel] {
|
|
184
257
|
label.rowVerticalAlignment = nil
|
|
185
258
|
label.rowOffsetY = 0
|
|
@@ -190,7 +263,7 @@ private final class NativeListTableColumnView: UIStackView {
|
|
|
190
263
|
primaryLabel.numberOfLines = 1
|
|
191
264
|
secondaryLeadingLabel.numberOfLines = 1
|
|
192
265
|
secondaryLabel.numberOfLines = 1
|
|
193
|
-
primaryLabel.attributedText = nil
|
|
266
|
+
if clearPrimaryText { primaryLabel.attributedText = nil }
|
|
194
267
|
secondaryLeadingLabel.attributedText = nil
|
|
195
268
|
secondaryLabel.attributedText = nil
|
|
196
269
|
secondaryLeadingLabel.isHidden = true
|
|
@@ -202,6 +275,28 @@ private final class NativeListTableColumnView: UIStackView {
|
|
|
202
275
|
}
|
|
203
276
|
}
|
|
204
277
|
|
|
278
|
+
func bindTitleIcons(_ column: [String: Any], theme: [String: Any]?) {
|
|
279
|
+
let descriptors = [column.dictionary("titleIcon"), column.dictionary("secondaryTitleIcon")]
|
|
280
|
+
for (index, descriptor) in descriptors.enumerated() {
|
|
281
|
+
guard let descriptor else { continue }
|
|
282
|
+
let icon = index == 0 ? titleIconView : secondaryTitleIconView
|
|
283
|
+
icon.image = nativeListIcon(named: descriptor.string("name"))
|
|
284
|
+
icon.tintColor = UIColor(
|
|
285
|
+
nativeListHex: descriptor.string("tintColor",
|
|
286
|
+
default: theme?["iconSubdued"] as? String ?? "#8D8D8D"),
|
|
287
|
+
fallback: .gray)
|
|
288
|
+
icon.isHidden = false
|
|
289
|
+
let label = descriptor.string("accessibilityLabel")
|
|
290
|
+
icon.accessibilityLabel = label.isEmpty ? nil : label
|
|
291
|
+
icon.isAccessibilityElement = !label.isEmpty
|
|
292
|
+
}
|
|
293
|
+
if descriptors.contains(where: { $0 != nil }) {
|
|
294
|
+
primaryLine.setCustomSpacing(4, after: primaryLabel)
|
|
295
|
+
primaryLine.setCustomSpacing(4, after: titleIconView)
|
|
296
|
+
if linear { primaryLine.alignment = .top }
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
205
300
|
func bind(
|
|
206
301
|
column: [String: Any],
|
|
207
302
|
badges: [[String: Any]],
|
|
@@ -228,7 +323,7 @@ private final class NativeListTableColumnView: UIStackView {
|
|
|
228
323
|
secondaryLeadingLabel.font = nativeListFont(ofSize: 12, fonts: fonts)
|
|
229
324
|
secondaryLabel.font = nativeListFont(ofSize: 12, fonts: fonts)
|
|
230
325
|
primaryLabel.attributedText = line(
|
|
231
|
-
column
|
|
326
|
+
nativeListDataColumnText(column, "text"),
|
|
232
327
|
font: nativeListFont(ofSize: 14, weight: .medium, fonts: fonts),
|
|
233
328
|
color: textColor(column.string("tone"), theme: theme),
|
|
234
329
|
height: 20
|
|
@@ -261,7 +356,7 @@ private final class NativeListTableColumnView: UIStackView {
|
|
|
261
356
|
secondaryLeadingLabel.isHidden = false
|
|
262
357
|
secondaryLine.isHidden = false
|
|
263
358
|
}
|
|
264
|
-
let secondary = column
|
|
359
|
+
let secondary = nativeListDataColumnText(column, "secondaryText")
|
|
265
360
|
if !secondary.isEmpty {
|
|
266
361
|
secondaryLabel.attributedText = line(
|
|
267
362
|
secondary,
|
|
@@ -286,7 +381,7 @@ private final class NativeListTableColumnView: UIStackView {
|
|
|
286
381
|
column: [String: Any], badges: [[String: Any]], theme: [String: Any]?,
|
|
287
382
|
style: [String: Any] = [:], fonts: NativeListFontFamilies
|
|
288
383
|
) {
|
|
289
|
-
reset()
|
|
384
|
+
reset(clearPrimaryText: !linear)
|
|
290
385
|
linear = true
|
|
291
386
|
alignment = .fill
|
|
292
387
|
badgesStack.isHidden = true
|
|
@@ -331,14 +426,15 @@ private final class NativeListTableColumnView: UIStackView {
|
|
|
331
426
|
primaryLabel.textAlignment =
|
|
332
427
|
column.string("alignment") == "end"
|
|
333
428
|
? .right : column.string("alignment") == "center" ? .center : .left
|
|
334
|
-
let secondary = column
|
|
429
|
+
let secondary = nativeListDataColumnText(column, "secondaryText")
|
|
335
430
|
let primaryFont = font(primaryStyle, size: 14, weight: .medium)
|
|
336
431
|
let attributed = NSMutableAttributedString(
|
|
337
|
-
string: column
|
|
432
|
+
string: nativeListDataColumnText(column, "text"),
|
|
338
433
|
attributes: [
|
|
339
434
|
.font: primaryFont,
|
|
340
435
|
.foregroundColor: color(primaryStyle, textColor(column.string("tone"), theme: theme)),
|
|
341
436
|
])
|
|
437
|
+
attributed.setAttributedString(nativeListDataSegments(attributed, column.dictionaries("textSegments")))
|
|
342
438
|
let primaryLength = attributed.length
|
|
343
439
|
// Every badge run is the legacy " text " pill: both lead spaces sit inside the badge
|
|
344
440
|
// background and are its left padding. `titleBadgeGap` adds an exact, unfilled gap between
|
|
@@ -378,7 +474,10 @@ private final class NativeListTableColumnView: UIStackView {
|
|
|
378
474
|
textColor(column.string("secondaryTone", default: "secondary"), theme: theme)),
|
|
379
475
|
]
|
|
380
476
|
attributes.merge(paragraph(secondaryStyle, font: secondaryFont, spacing: nil)) { $1 }
|
|
381
|
-
attributed.append(NSAttributedString(string: "\n
|
|
477
|
+
attributed.append(NSAttributedString(string: "\n", attributes: attributes))
|
|
478
|
+
attributed.append(nativeListDataSegments(
|
|
479
|
+
NSAttributedString(string: secondary, attributes: attributes),
|
|
480
|
+
column.dictionaries("secondaryTextSegments")))
|
|
382
481
|
lines = min(3, lines + max(1, secondaryStyle.int("lines", default: 1)))
|
|
383
482
|
}
|
|
384
483
|
primaryLabel.font = nativeListFont(ofSize: 12, fonts: fonts)
|
|
@@ -400,6 +499,16 @@ private final class NativeListTableColumnView: UIStackView {
|
|
|
400
499
|
primaryStyle.double("offsetY", default: secondaryStyle.double("offsetY")))
|
|
401
500
|
}
|
|
402
501
|
|
|
502
|
+
func applySegments(_ column: [String: Any]) {
|
|
503
|
+
guard !linear else { return }
|
|
504
|
+
if let text = primaryLabel.attributedText {
|
|
505
|
+
primaryLabel.attributedText = nativeListDataSegments(text, column.dictionaries("textSegments"))
|
|
506
|
+
}
|
|
507
|
+
if let text = secondaryLabel.attributedText {
|
|
508
|
+
secondaryLabel.attributedText = nativeListDataSegments(text, column.dictionaries("secondaryTextSegments"))
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
403
512
|
func applyStyle(_ style: [String: Any], text: (UILabel, [String: Any]) -> Void) {
|
|
404
513
|
// The linear single label already mapped its styles onto attributed ranges.
|
|
405
514
|
guard !linear else { return }
|
|
@@ -446,3 +555,22 @@ private final class NativeListTableColumnView: UIStackView {
|
|
|
446
555
|
}
|
|
447
556
|
}
|
|
448
557
|
}
|
|
558
|
+
|
|
559
|
+
private func nativeListDataColumnText(_ column: [String: Any], _ field: String) -> String {
|
|
560
|
+
let segments = column.dictionaries("\(field)Segments")
|
|
561
|
+
return segments.isEmpty ? column.string(field) : segments.map { $0.string("text") }.joined()
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
private func nativeListDataSegments(_ fallback: NSAttributedString, _ segments: [[String: Any]]) -> NSAttributedString {
|
|
565
|
+
guard !segments.isEmpty, fallback.length > 0 else { return fallback }
|
|
566
|
+
let attributes = fallback.attributes(at: 0, effectiveRange: nil)
|
|
567
|
+
let result = NSMutableAttributedString(string: "")
|
|
568
|
+
for segment in segments {
|
|
569
|
+
var runAttributes = attributes
|
|
570
|
+
if segment.string("style") == "subscript", let font = attributes[.font] as? UIFont {
|
|
571
|
+
runAttributes[.font] = font.withSize(ceil(font.pointSize * 0.6))
|
|
572
|
+
}
|
|
573
|
+
result.append(NSAttributedString(string: segment.string("text"), attributes: runAttributes))
|
|
574
|
+
}
|
|
575
|
+
return result
|
|
576
|
+
}
|
|
@@ -110,6 +110,9 @@ func nativeListIcon(named name: String) -> UIImage? {
|
|
|
110
110
|
case "LockSolid": assetName = "onekey_selector_lock_solid"
|
|
111
111
|
// OneKey patch: official selector icon geometry.
|
|
112
112
|
case "GlobusOutline": assetName = "onekey_selector_globus_outline"
|
|
113
|
+
case "GasSolid": assetName = "onekey_gas_solid"
|
|
114
|
+
case "RefreshCcwOutline": assetName = "onekey_refresh_ccw_outline"
|
|
115
|
+
case "CryptoCoinOutline": assetName = "onekey_crypto_coin_outline"
|
|
113
116
|
case "ArrowBottomOutline": assetName = "onekey_arrow_bottom"
|
|
114
117
|
case "ArrowTopOutline": assetName = "onekey_arrow_top"
|
|
115
118
|
case "ChartTrendingUpOutline": assetName = "onekey_chart_trending_up"
|
|
@@ -4,6 +4,51 @@ final class NativeListIdentityCell: NativeListRendererCell {
|
|
|
4
4
|
override class func appliesSizePreset(_ item: NativeListItem) -> Bool {
|
|
5
5
|
!["walletSidebar", "networkSelector"].contains(item.data.string("presentation"))
|
|
6
6
|
}
|
|
7
|
+
private class func configureTrailingStack(
|
|
8
|
+
_ stack: NativeListAccessoryStack, descriptors: [[String: Any]]
|
|
9
|
+
) {
|
|
10
|
+
stack.axis = .vertical
|
|
11
|
+
stack.alignment = .trailing
|
|
12
|
+
stack.spacing = 2
|
|
13
|
+
if descriptors.contains(where: { $0.string("kind") == "checkbox" })
|
|
14
|
+
&& descriptors.contains(where: { $0.string("kind") == "value" })
|
|
15
|
+
{
|
|
16
|
+
stack.axis = .horizontal
|
|
17
|
+
stack.alignment = .center
|
|
18
|
+
stack.spacing = 12
|
|
19
|
+
} else if descriptors.count == 2,
|
|
20
|
+
descriptors[0].string("kind") == "valuePair",
|
|
21
|
+
(descriptors[1].string("kind") == "menu"
|
|
22
|
+
|| (descriptors[1].string("kind") == "icon"
|
|
23
|
+
&& descriptors[1].string("name") == "DotVerSolid"
|
|
24
|
+
&& descriptors[1].string("actionKey") == "menu"))
|
|
25
|
+
{
|
|
26
|
+
stack.axis = .horizontal
|
|
27
|
+
stack.alignment = .center
|
|
28
|
+
stack.spacing = 8
|
|
29
|
+
} else if descriptors.count == 2,
|
|
30
|
+
(descriptors[0].string("kind") == "valuePair"
|
|
31
|
+
&& descriptors[1].string("kind") == "chevron")
|
|
32
|
+
|| (descriptors[0].string("kind") == "icon"
|
|
33
|
+
&& descriptors[0].string("name") == "RefreshCcwOutline"
|
|
34
|
+
&& descriptors[0].string("actionKey").isEmpty
|
|
35
|
+
&& descriptors[1].string("kind") == "chevron")
|
|
36
|
+
{
|
|
37
|
+
stack.axis = .horizontal
|
|
38
|
+
stack.alignment = .center
|
|
39
|
+
stack.spacing = 12
|
|
40
|
+
} else if descriptors.count == 2,
|
|
41
|
+
descriptors[0].string("kind") == "icon",
|
|
42
|
+
descriptors[0].string("name") == "PencilOutline",
|
|
43
|
+
descriptors[1].string("kind") == "icon",
|
|
44
|
+
descriptors[1].string("name") == "DragOutline"
|
|
45
|
+
{
|
|
46
|
+
stack.axis = .horizontal
|
|
47
|
+
stack.alignment = .center
|
|
48
|
+
// Source 36-point icon frames with -7 margins need a 10-point gap.
|
|
49
|
+
stack.spacing = 10
|
|
50
|
+
}
|
|
51
|
+
}
|
|
7
52
|
override class func measure(
|
|
8
53
|
_ item: NativeListItem, width: CGFloat, theme: [String: Any]?, layout: String,
|
|
9
54
|
fonts: NativeListFontFamilies
|
|
@@ -12,6 +57,47 @@ final class NativeListIdentityCell: NativeListRendererCell {
|
|
|
12
57
|
return item.data.dictionaries("badges").isEmpty ? 68 : 92
|
|
13
58
|
}
|
|
14
59
|
if item.data.string("presentation") == "networkSelector" { return 47 }
|
|
60
|
+
if item.data.string("contentHeight") == "auto" {
|
|
61
|
+
let style = item.data.dictionary("style") ?? [:]
|
|
62
|
+
let horizontalPadding = CGFloat(style.double("horizontalPadding", default: layout == "table" ? 16 : 12))
|
|
63
|
+
let verticalPadding = CGFloat(style.double("verticalPadding", default: 8))
|
|
64
|
+
let imageWidth = CGFloat(style.dictionary("image")?.double("width", default: 40) ?? 40)
|
|
65
|
+
let imageHeight = CGFloat(style.dictionary("image")?.double("height", default: 40) ?? 40)
|
|
66
|
+
let leadingGap = CGFloat(style.double("leadingGap", default: 12))
|
|
67
|
+
let accessories = item.data.dictionaries("trailing")
|
|
68
|
+
let trailing = NativeListAccessoryStack(frame: .zero)
|
|
69
|
+
configureTrailingStack(trailing, descriptors: accessories)
|
|
70
|
+
trailing.bind(
|
|
71
|
+
item, descriptors: accessories, theme: theme, style: style,
|
|
72
|
+
defaultSpacing: trailing.spacing, checkboxState: { _, _, fallback in fallback }, fonts: fonts)
|
|
73
|
+
trailing.isHidden = false
|
|
74
|
+
let trailingSize = trailing.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
|
|
75
|
+
let rightInset = style["horizontalPadding"] != nil
|
|
76
|
+
? horizontalPadding : trailing.endInset ?? horizontalPadding
|
|
77
|
+
let contentGap = trailing.contentGap ?? 12
|
|
78
|
+
let textWidth = max(1,
|
|
79
|
+
width - horizontalPadding - rightInset - imageWidth - leadingGap
|
|
80
|
+
- trailingSize.width - contentGap)
|
|
81
|
+
let title = NativeListResolvedText(
|
|
82
|
+
item.data.string("title"), style: style.dictionary("title"), size: 16,
|
|
83
|
+
weight: .medium, color: .black, lineHeight: 24,
|
|
84
|
+
lines: item.data.int("titleLines", default: 1), fonts: fonts)
|
|
85
|
+
let subtitle = NativeListResolvedText(
|
|
86
|
+
item.data.string("subtitle"), style: style.dictionary("subtitle"), size: 14,
|
|
87
|
+
color: .black, lineHeight: 20,
|
|
88
|
+
lines: item.data.int("subtitleLines", default: 1),
|
|
89
|
+
breakMode: item.data.int("subtitleLines", default: 1) == 0 ? .byWordWrapping : .byTruncatingTail,
|
|
90
|
+
fonts: fonts)
|
|
91
|
+
let tertiary = NativeListResolvedText(
|
|
92
|
+
item.data.string("tertiary"), style: style.dictionary("tertiary"), size: 14,
|
|
93
|
+
color: .black, lineHeight: 20, lines: 1, fonts: fonts)
|
|
94
|
+
let textHeight = title.measure(width: textWidth)
|
|
95
|
+
+ subtitle.measure(width: textWidth)
|
|
96
|
+
+ tertiary.measure(width: textWidth)
|
|
97
|
+
+ (item.data.string("subtitle").isEmpty ? 0 : CGFloat(style.double("lineGap", default: 0)))
|
|
98
|
+
return max(item.data.string("subtitle").isEmpty ? 56 : 60,
|
|
99
|
+
verticalPadding * 2 + max(imageHeight, textHeight, trailingSize.height))
|
|
100
|
+
}
|
|
15
101
|
return !item.data.string("tertiary").isEmpty
|
|
16
102
|
? 72 : !item.data.string("subtitle").isEmpty ? 60 : 56
|
|
17
103
|
}
|
|
@@ -20,6 +106,7 @@ final class NativeListIdentityCell: NativeListRendererCell {
|
|
|
20
106
|
private let mainStack = UIStackView()
|
|
21
107
|
private let titleRowStack = UIStackView()
|
|
22
108
|
private let titleLabel = NativeListTextLabel()
|
|
109
|
+
private let titleIconView = UIImageView()
|
|
23
110
|
private let subtitleLabel = NativeListTextLabel()
|
|
24
111
|
private let tertiaryLabel = NativeListTextLabel()
|
|
25
112
|
private let badgeLabel = NativeListInsetLabel()
|
|
@@ -75,7 +162,17 @@ final class NativeListIdentityCell: NativeListRendererCell {
|
|
|
75
162
|
titleRowStack.axis = .horizontal
|
|
76
163
|
titleRowStack.alignment = .center
|
|
77
164
|
titleRowStack.addArrangedSubview(titleLabel)
|
|
165
|
+
titleRowStack.addArrangedSubview(titleIconView)
|
|
78
166
|
titleRowStack.addArrangedSubview(badgeLabel)
|
|
167
|
+
titleIconView.translatesAutoresizingMaskIntoConstraints = false
|
|
168
|
+
let titleIconWidth = titleIconView.widthAnchor.constraint(equalToConstant: 20)
|
|
169
|
+
titleIconWidth.priority = UILayoutPriority(999)
|
|
170
|
+
NSLayoutConstraint.activate([
|
|
171
|
+
titleIconWidth,
|
|
172
|
+
titleIconView.heightAnchor.constraint(equalToConstant: 20),
|
|
173
|
+
])
|
|
174
|
+
titleIconView.contentMode = .scaleAspectFit
|
|
175
|
+
titleIconView.setContentHuggingPriority(.required, for: .horizontal)
|
|
79
176
|
[titleRowStack, subtitleLabel, tertiaryLabel].forEach(mainStack.addArrangedSubview)
|
|
80
177
|
visual.translatesAutoresizingMaskIntoConstraints = false
|
|
81
178
|
leadingWidth = visual.widthAnchor.constraint(equalToConstant: 40)
|
|
@@ -133,6 +230,10 @@ final class NativeListIdentityCell: NativeListRendererCell {
|
|
|
133
230
|
titleRowStack.setCustomSpacing(UIStackView.spacingUseDefault, after: $0)
|
|
134
231
|
}
|
|
135
232
|
titleRowStack.spacing = 8
|
|
233
|
+
titleIconView.image = nil
|
|
234
|
+
titleIconView.isHidden = true
|
|
235
|
+
titleIconView.accessibilityLabel = nil
|
|
236
|
+
titleIconView.isAccessibilityElement = false
|
|
136
237
|
titleRowStack.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
|
137
238
|
titleRowStack.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
|
|
138
239
|
for label in [titleLabel, subtitleLabel, tertiaryLabel, badgeLabel] {
|
|
@@ -165,6 +266,10 @@ final class NativeListIdentityCell: NativeListRendererCell {
|
|
|
165
266
|
leadingWidth.constant = 40
|
|
166
267
|
leadingHeight.constant = 40
|
|
167
268
|
visual.glyphSize = 18
|
|
269
|
+
visual.bitmapBorderWidth =
|
|
270
|
+
item.data.dictionary("leading")?.string("borderColor").isEmpty == false
|
|
271
|
+
&& item.data.dictionary("leading")?.string("borderStyle") != "dashed"
|
|
272
|
+
? 1 : 0
|
|
168
273
|
fallbackLabel.attributedText = nil
|
|
169
274
|
fallbackLabel.font = nativeListFont(ofSize: 13, weight: .bold, fonts: fonts)
|
|
170
275
|
trailingStack.reset()
|
|
@@ -175,6 +280,31 @@ final class NativeListIdentityCell: NativeListRendererCell {
|
|
|
175
280
|
leadingActionButton.setImage(nil, for: .normal)
|
|
176
281
|
bindIdentity(item, theme: theme, selected: item.data.bool("selected"), checkboxState)
|
|
177
282
|
let style = item.data.dictionary("style") ?? [:]
|
|
283
|
+
if let titleIcon = item.data.dictionary("titleIcon") {
|
|
284
|
+
titleIconView.image = nativeListIcon(named: titleIcon.string("name"))
|
|
285
|
+
titleIconView.tintColor = UIColor(
|
|
286
|
+
nativeListHex: titleIcon.string("tintColor",
|
|
287
|
+
default: theme?["iconSubdued"] as? String ?? "#8D8D8D"),
|
|
288
|
+
fallback: .gray)
|
|
289
|
+
titleIconView.isHidden = false
|
|
290
|
+
let label = titleIcon.string("accessibilityLabel")
|
|
291
|
+
titleIconView.accessibilityLabel = label.isEmpty ? nil : label
|
|
292
|
+
titleIconView.isAccessibilityElement = !label.isEmpty
|
|
293
|
+
titleRowStack.setCustomSpacing(4, after: titleLabel)
|
|
294
|
+
}
|
|
295
|
+
if let ratio = style["leadingContentMaxWidthRatio"] as? NSNumber,
|
|
296
|
+
root.arrangedSubviews.contains(visual)
|
|
297
|
+
{
|
|
298
|
+
titleLabel.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
|
|
299
|
+
let visualWidth = CGFloat(style.dictionary("image")?.double("width", default: 40) ?? 40)
|
|
300
|
+
let leadingGap = CGFloat(style.double("leadingGap", default: 12))
|
|
301
|
+
let constraint = mainStack.widthAnchor.constraint(
|
|
302
|
+
lessThanOrEqualTo: root.widthAnchor,
|
|
303
|
+
multiplier: CGFloat(ratio.doubleValue),
|
|
304
|
+
constant: -(visualWidth + leadingGap))
|
|
305
|
+
constraint.isActive = true
|
|
306
|
+
selectorConstraints.append(constraint)
|
|
307
|
+
}
|
|
178
308
|
if style["horizontalPadding"] != nil {
|
|
179
309
|
leftInset = CGFloat(style.double("horizontalPadding"))
|
|
180
310
|
rightInset = -leftInset
|
|
@@ -196,7 +326,9 @@ final class NativeListIdentityCell: NativeListRendererCell {
|
|
|
196
326
|
if walletBadgeLine != nil {
|
|
197
327
|
mainStack.setCustomSpacing(CGFloat(style.double("titleBadgeGap")), after: titleRowStack)
|
|
198
328
|
} else {
|
|
199
|
-
titleRowStack.setCustomSpacing(
|
|
329
|
+
titleRowStack.setCustomSpacing(
|
|
330
|
+
CGFloat(style.double("titleBadgeGap")),
|
|
331
|
+
after: titleIconView.isHidden ? titleLabel : titleIconView)
|
|
200
332
|
}
|
|
201
333
|
}
|
|
202
334
|
if style["trailingGap"] != nil { trailingStack.spacing = CGFloat(style.double("trailingGap")) }
|
|
@@ -440,9 +572,37 @@ final class NativeListIdentityCell: NativeListRendererCell {
|
|
|
440
572
|
}
|
|
441
573
|
root.addArrangedSubview(mainStack)
|
|
442
574
|
show(titleLabel, item.data.string("title"), lines: item.data.int("titleLines", default: 1))
|
|
575
|
+
let titleSuffixes = item.data.dictionaries("titleSuffixes")
|
|
576
|
+
if !titleSuffixes.isEmpty {
|
|
577
|
+
titleLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
|
578
|
+
let minimumTitleWidth = titleLabel.widthAnchor.constraint(greaterThanOrEqualToConstant: 80)
|
|
579
|
+
minimumTitleWidth.priority = UILayoutPriority(751)
|
|
580
|
+
minimumTitleWidth.isActive = true
|
|
581
|
+
selectorConstraints.append(minimumTitleWidth)
|
|
582
|
+
for suffix in titleSuffixes {
|
|
583
|
+
let label = NativeListTextLabel()
|
|
584
|
+
label.font = nativeListFont(ofSize: 12, fonts: fonts)
|
|
585
|
+
label.textColor = dataTextColor(suffix.string("tone", default: "secondary"), theme: theme)
|
|
586
|
+
label.numberOfLines = 1
|
|
587
|
+
label.lineBreakMode = .byTruncatingTail
|
|
588
|
+
label.setContentHuggingPriority(.defaultHigh, for: .horizontal)
|
|
589
|
+
label.setContentCompressionResistancePriority(UILayoutPriority(749), for: .horizontal)
|
|
590
|
+
setLineHeight(label, text: suffix.string("text"), lineHeight: 16)
|
|
591
|
+
if let maxWidth = suffix["maxWidth"] as? NSNumber {
|
|
592
|
+
let limit = label.widthAnchor.constraint(lessThanOrEqualToConstant: CGFloat(truncating: maxWidth))
|
|
593
|
+
limit.isActive = true
|
|
594
|
+
selectorConstraints.append(limit)
|
|
595
|
+
}
|
|
596
|
+
titleRowStack.insertArrangedSubview(label, at: titleRowStack.arrangedSubviews.count - 1)
|
|
597
|
+
selectorViews.append(label)
|
|
598
|
+
}
|
|
599
|
+
}
|
|
443
600
|
show(
|
|
444
601
|
subtitleLabel, item.data.string("subtitle"), lines: item.data.int("subtitleLines", default: 1)
|
|
445
602
|
)
|
|
603
|
+
if item.data.int("subtitleLines", default: 1) == 0 {
|
|
604
|
+
subtitleLabel.lineBreakMode = .byWordWrapping
|
|
605
|
+
}
|
|
446
606
|
show(tertiaryLabel, item.data.string("tertiary"), lines: 1)
|
|
447
607
|
if !item.data.string("subtitle").isEmpty, item.data.string("tertiary").isEmpty {
|
|
448
608
|
mainStack.spacing = 0
|
|
@@ -556,32 +716,7 @@ final class NativeListIdentityCell: NativeListRendererCell {
|
|
|
556
716
|
}
|
|
557
717
|
root.addArrangedSubview(trailingStack)
|
|
558
718
|
let accessories = item.data.dictionaries("trailing")
|
|
559
|
-
|
|
560
|
-
&& accessories.contains(where: { $0.string("kind") == "value" })
|
|
561
|
-
{
|
|
562
|
-
trailingStack.axis = .horizontal
|
|
563
|
-
trailingStack.alignment = .center
|
|
564
|
-
trailingStack.spacing = 12
|
|
565
|
-
} else if accessories.count == 2,
|
|
566
|
-
accessories[0].string("kind") == "valuePair",
|
|
567
|
-
accessories[1].string("kind") == "menu"
|
|
568
|
-
{
|
|
569
|
-
trailingStack.axis = .horizontal
|
|
570
|
-
trailingStack.alignment = .center
|
|
571
|
-
trailingStack.spacing = 8
|
|
572
|
-
} else if accessories.count == 2,
|
|
573
|
-
accessories[0].string("kind") == "icon",
|
|
574
|
-
accessories[0].string("name") == "PencilOutline",
|
|
575
|
-
accessories[1].string("kind") == "icon",
|
|
576
|
-
accessories[1].string("name") == "DragOutline"
|
|
577
|
-
{
|
|
578
|
-
trailingStack.axis = .horizontal
|
|
579
|
-
trailingStack.alignment = .center
|
|
580
|
-
// Each source IconButton has a 36-point frame and m=-7. XStack gap=$6
|
|
581
|
-
// therefore places the physical frames 10 points apart (46-point
|
|
582
|
-
// center distance), not 24 points apart.
|
|
583
|
-
trailingStack.spacing = 10
|
|
584
|
-
}
|
|
719
|
+
Self.configureTrailingStack(trailingStack, descriptors: accessories)
|
|
585
720
|
trailingStack.bind(
|
|
586
721
|
item, descriptors: accessories, theme: theme, style: item.data.dictionary("style") ?? [:],
|
|
587
722
|
defaultSpacing: trailingStack.spacing, checkboxState: checkboxState, fonts: fonts)
|
|
@@ -590,12 +725,13 @@ final class NativeListIdentityCell: NativeListRendererCell {
|
|
|
590
725
|
trailingStack.isHidden = false
|
|
591
726
|
if let gap = trailingStack.contentGap { root.setCustomSpacing(gap, after: mainStack) }
|
|
592
727
|
if let inset = trailingStack.endInset { rightInset = -inset }
|
|
593
|
-
if
|
|
594
|
-
|
|
728
|
+
if accessories.count == 1,
|
|
729
|
+
(item.data.string("presentation") == "accountSelector"
|
|
730
|
+
|| accessories[0].string("kind") == "valuePair"),
|
|
595
731
|
let accessory = trailingStack.firstVisibleControl
|
|
596
732
|
{
|
|
597
733
|
// The vertical trailing stack has no stable intrinsic width, so keep its
|
|
598
|
-
// flexible space in the
|
|
734
|
+
// flexible space in the title and subtitle column.
|
|
599
735
|
let width = trailingStack.widthAnchor.constraint(equalTo: accessory.widthAnchor)
|
|
600
736
|
width.isActive = true
|
|
601
737
|
selectorConstraints.append(width)
|