@onekeyfe/react-native-native-list 6.7.0-alpha.412 → 6.7.0-alpha.413

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.
Files changed (121) hide show
  1. package/android/src/main/java/com/onekey/nativelist/NativeListAccessoryStack.kt +0 -5
  2. package/android/src/main/java/com/onekey/nativelist/NativeListLeadingVisual.kt +0 -5
  3. package/android/src/main/java/com/onekey/nativelist/NativeListPrimitives.kt +338 -117
  4. package/android/src/main/java/com/onekey/nativelist/NativeListRendererRowView.kt +0 -5
  5. package/docs/SPEC.md +7 -114
  6. package/ios/NativeListAccessoryStack.swift +16 -6
  7. package/ios/NativeListDataRowRenderer.swift +6 -15
  8. package/ios/NativeListDesignAssets.swift +84 -13
  9. package/ios/NativeListIdentityRenderer.swift +10 -12
  10. package/ios/NativeListLeadingVisual.swift +9 -11
  11. package/ios/NativeListMarketRenderer.swift +13 -7
  12. package/ios/NativeListMediaTileRenderer.swift +2 -6
  13. package/ios/NativeListMetricCardRenderer.swift +2 -4
  14. package/ios/NativeListSectionHeaderRenderer.swift +4 -12
  15. package/ios/Resources/NativeListIcons.xcassets/Contents.json +1 -0
  16. package/ios/Resources/NativeListIcons.xcassets/onekey_arrow_bottom.imageset/Contents.json +1 -0
  17. package/ios/Resources/NativeListIcons.xcassets/onekey_arrow_bottom.imageset/icon.svg +1 -0
  18. package/ios/Resources/NativeListIcons.xcassets/onekey_arrow_top.imageset/Contents.json +1 -0
  19. package/ios/Resources/NativeListIcons.xcassets/onekey_arrow_top.imageset/icon.svg +1 -0
  20. package/ios/Resources/NativeListIcons.xcassets/onekey_badge_verified_solid.imageset/Contents.json +1 -0
  21. package/ios/Resources/NativeListIcons.xcassets/onekey_badge_verified_solid.imageset/icon.svg +1 -0
  22. package/ios/Resources/NativeListIcons.xcassets/onekey_chart_trending_up.imageset/Contents.json +1 -0
  23. package/ios/Resources/NativeListIcons.xcassets/onekey_chart_trending_up.imageset/icon.svg +1 -0
  24. package/ios/Resources/NativeListIcons.xcassets/onekey_checkbox_checked.imageset/Contents.json +1 -0
  25. package/ios/Resources/NativeListIcons.xcassets/onekey_checkbox_checked.imageset/icon.svg +1 -0
  26. package/ios/Resources/NativeListIcons.xcassets/onekey_checkbox_indeterminate.imageset/Contents.json +1 -0
  27. package/ios/Resources/NativeListIcons.xcassets/onekey_checkbox_indeterminate.imageset/icon.svg +1 -0
  28. package/ios/Resources/NativeListIcons.xcassets/onekey_chevron_bottom.imageset/Contents.json +1 -0
  29. package/ios/Resources/NativeListIcons.xcassets/onekey_chevron_bottom.imageset/icon.svg +1 -0
  30. package/ios/Resources/NativeListIcons.xcassets/onekey_chevron_grabber_ver.imageset/Contents.json +1 -0
  31. package/ios/Resources/NativeListIcons.xcassets/onekey_chevron_grabber_ver.imageset/icon.svg +1 -0
  32. package/ios/Resources/NativeListIcons.xcassets/onekey_chevron_right_small.imageset/Contents.json +1 -0
  33. package/ios/Resources/NativeListIcons.xcassets/onekey_chevron_right_small.imageset/icon.svg +1 -0
  34. package/ios/Resources/NativeListIcons.xcassets/onekey_chevron_top.imageset/Contents.json +1 -0
  35. package/ios/Resources/NativeListIcons.xcassets/onekey_chevron_top.imageset/icon.svg +1 -0
  36. package/ios/Resources/NativeListIcons.xcassets/onekey_crypto_coin_outline.imageset/Contents.json +15 -0
  37. package/ios/Resources/NativeListIcons.xcassets/onekey_crypto_coin_outline.imageset/icon.svg +4 -0
  38. package/ios/Resources/NativeListIcons.xcassets/onekey_document2.imageset/Contents.json +1 -0
  39. package/ios/Resources/NativeListIcons.xcassets/onekey_document2.imageset/icon.svg +1 -0
  40. package/ios/Resources/NativeListIcons.xcassets/onekey_dot_hor.imageset/Contents.json +1 -0
  41. package/ios/Resources/NativeListIcons.xcassets/onekey_dot_hor.imageset/icon.svg +1 -0
  42. package/ios/Resources/NativeListIcons.xcassets/onekey_dot_ver_solid.imageset/Contents.json +1 -0
  43. package/ios/Resources/NativeListIcons.xcassets/onekey_dot_ver_solid.imageset/icon.svg +1 -0
  44. package/ios/Resources/NativeListIcons.xcassets/onekey_drag.imageset/Contents.json +1 -0
  45. package/ios/Resources/NativeListIcons.xcassets/onekey_drag.imageset/icon.svg +1 -0
  46. package/ios/Resources/NativeListIcons.xcassets/onekey_error_solid.imageset/Contents.json +1 -0
  47. package/ios/Resources/NativeListIcons.xcassets/onekey_error_solid.imageset/icon.svg +1 -0
  48. package/ios/Resources/NativeListIcons.xcassets/onekey_gas_solid.imageset/Contents.json +15 -0
  49. package/ios/Resources/NativeListIcons.xcassets/onekey_gas_solid.imageset/icon.svg +3 -0
  50. package/ios/Resources/NativeListIcons.xcassets/onekey_image_square_waves.imageset/Contents.json +1 -0
  51. package/ios/Resources/NativeListIcons.xcassets/onekey_image_square_waves.imageset/icon.svg +1 -0
  52. package/ios/Resources/NativeListIcons.xcassets/onekey_info_circle.imageset/Contents.json +1 -0
  53. package/ios/Resources/NativeListIcons.xcassets/onekey_info_circle.imageset/icon.svg +1 -0
  54. package/ios/Resources/NativeListIcons.xcassets/onekey_minus_circle.imageset/Contents.json +1 -0
  55. package/ios/Resources/NativeListIcons.xcassets/onekey_minus_circle.imageset/icon.svg +1 -0
  56. package/ios/Resources/NativeListIcons.xcassets/onekey_minus_circle_solid.imageset/Contents.json +1 -0
  57. package/ios/Resources/NativeListIcons.xcassets/onekey_minus_circle_solid.imageset/icon.svg +1 -0
  58. package/ios/Resources/NativeListIcons.xcassets/onekey_pencil.imageset/Contents.json +1 -0
  59. package/ios/Resources/NativeListIcons.xcassets/onekey_pencil.imageset/icon.svg +1 -0
  60. package/ios/Resources/NativeListIcons.xcassets/onekey_plus_circle.imageset/Contents.json +1 -0
  61. package/ios/Resources/NativeListIcons.xcassets/onekey_plus_circle.imageset/icon.svg +1 -0
  62. package/ios/Resources/NativeListIcons.xcassets/onekey_plus_large.imageset/Contents.json +1 -0
  63. package/ios/Resources/NativeListIcons.xcassets/onekey_plus_large.imageset/icon.svg +1 -0
  64. package/ios/Resources/NativeListIcons.xcassets/onekey_plus_small.imageset/Contents.json +1 -0
  65. package/ios/Resources/NativeListIcons.xcassets/onekey_plus_small.imageset/icon.svg +1 -0
  66. package/ios/Resources/NativeListIcons.xcassets/onekey_questionmark_solid.imageset/Contents.json +1 -0
  67. package/ios/Resources/NativeListIcons.xcassets/onekey_questionmark_solid.imageset/icon.svg +1 -0
  68. package/ios/Resources/NativeListIcons.xcassets/onekey_refresh_ccw_outline.imageset/Contents.json +15 -0
  69. package/ios/Resources/NativeListIcons.xcassets/onekey_refresh_ccw_outline.imageset/icon.svg +3 -0
  70. package/ios/Resources/NativeListIcons.xcassets/onekey_selector_account_error_custom.imageset/Contents.json +15 -0
  71. package/ios/Resources/NativeListIcons.xcassets/onekey_selector_account_error_custom.imageset/icon.svg +14 -0
  72. package/ios/Resources/NativeListIcons.xcassets/onekey_selector_all_networks_solid.imageset/Contents.json +15 -0
  73. package/ios/Resources/NativeListIcons.xcassets/onekey_selector_all_networks_solid.imageset/icon.svg +12 -0
  74. package/ios/Resources/NativeListIcons.xcassets/onekey_selector_apple_brand.imageset/Contents.json +15 -0
  75. package/ios/Resources/NativeListIcons.xcassets/onekey_selector_apple_brand.imageset/icon.svg +6 -0
  76. package/ios/Resources/NativeListIcons.xcassets/onekey_selector_bot_illus.imageset/Contents.json +15 -0
  77. package/ios/Resources/NativeListIcons.xcassets/onekey_selector_bot_illus.imageset/icon.svg +15 -0
  78. package/ios/Resources/NativeListIcons.xcassets/onekey_selector_crossed_small_solid.imageset/Contents.json +15 -0
  79. package/ios/Resources/NativeListIcons.xcassets/onekey_selector_crossed_small_solid.imageset/icon.svg +3 -0
  80. package/ios/Resources/NativeListIcons.xcassets/onekey_selector_globus_outline.imageset/Contents.json +15 -0
  81. package/ios/Resources/NativeListIcons.xcassets/onekey_selector_globus_outline.imageset/icon.svg +7 -0
  82. package/ios/Resources/NativeListIcons.xcassets/onekey_selector_google_illus.imageset/Contents.json +15 -0
  83. package/ios/Resources/NativeListIcons.xcassets/onekey_selector_google_illus.imageset/icon.svg +18 -0
  84. package/ios/Resources/NativeListIcons.xcassets/onekey_selector_lock_solid.imageset/Contents.json +15 -0
  85. package/ios/Resources/NativeListIcons.xcassets/onekey_selector_lock_solid.imageset/icon.svg +7 -0
  86. package/ios/Resources/NativeListIcons.xcassets/onekey_shield_exclamation.imageset/Contents.json +1 -0
  87. package/ios/Resources/NativeListIcons.xcassets/onekey_shield_exclamation.imageset/icon.svg +1 -0
  88. package/ios/Resources/NativeListIcons.xcassets/onekey_speaker_promote.imageset/Contents.json +1 -0
  89. package/ios/Resources/NativeListIcons.xcassets/onekey_speaker_promote.imageset/icon.svg +1 -0
  90. package/ios/Resources/NativeListIcons.xcassets/onekey_star.imageset/Contents.json +1 -0
  91. package/ios/Resources/NativeListIcons.xcassets/onekey_star.imageset/icon.svg +1 -0
  92. package/ios/Resources/NativeListIcons.xcassets/onekey_star_solid.imageset/Contents.json +1 -0
  93. package/ios/Resources/NativeListIcons.xcassets/onekey_star_solid.imageset/icon.svg +1 -0
  94. package/ios/Resources/NativeListIcons.xcassets/onekey_swap_hor.imageset/Contents.json +1 -0
  95. package/ios/Resources/NativeListIcons.xcassets/onekey_swap_hor.imageset/icon.svg +1 -0
  96. package/ios/Resources/NativeListIcons.xcassets/onekey_ticket.imageset/Contents.json +1 -0
  97. package/ios/Resources/NativeListIcons.xcassets/onekey_ticket.imageset/icon.svg +1 -0
  98. package/ios/Resources/NativeListIcons.xcassets/onekey_wallet.imageset/Contents.json +1 -0
  99. package/ios/Resources/NativeListIcons.xcassets/onekey_wallet.imageset/icon.svg +1 -0
  100. package/ios/tests/NativeListAccessoryStackTests.swift +0 -12
  101. package/lib/module/web/NativeListWebEngine.js +323 -21
  102. package/lib/module/web/templates/ActivityRowRenderer.js +24 -4
  103. package/lib/module/web/templates/MarketTableRowRenderer.js +15 -11
  104. package/lib/module/web/templates/MediaTileRowRenderer.js +12 -2
  105. package/lib/typescript/src/web/NativeListWebEngine.d.ts +1 -0
  106. package/package.json +4 -10
  107. package/react-native-native-list.podspec +5 -0
  108. package/src/web/NativeListWebEngine.ts +405 -25
  109. package/src/web/templates/ActivityRowRenderer.ts +53 -15
  110. package/src/web/templates/MarketTableRowRenderer.ts +29 -17
  111. package/src/web/templates/MediaTileRowRenderer.ts +15 -2
  112. package/android/src/main/java/com/onekey/nativelist/NativeListGeneratedIcons.kt +0 -47
  113. package/ios/NativeListGeneratedIcons.swift +0 -55
  114. package/ios/NativeListIconBinding.swift +0 -171
  115. package/ios/tests/NativeListSharedIconTests.swift +0 -236
  116. package/lib/module/web/NativeListGeneratedIcons.js +0 -31
  117. package/lib/typescript/src/web/NativeListGeneratedIcons.d.ts +0 -2
  118. package/scripts/generate-icons.mjs +0 -150
  119. package/scripts/generate-icons.test.mjs +0 -288
  120. package/scripts/native-list-icons.json +0 -260
  121. package/src/web/NativeListGeneratedIcons.ts +0 -28
package/docs/SPEC.md CHANGED
@@ -1,44 +1,5 @@
1
1
  # NativeList contract
2
2
 
3
- ## Shared image SVG integration — Implemented
4
-
5
- Static icons use the image package's named resources and SVG implementation:
6
- the main registry, Activity's ten private glyphs, Market stars/recognized badge,
7
- Media fallback and Android checkbox. The closed per-platform coverage, including
8
- the main-line asset-list additions, is recorded under Built-in icon metadata
9
- generation; unknown-name text fallbacks remain. The NativeList-only legacy name
10
- `BadgeVerifiedSolid` resolves to canonical `BadgeRecognizedSolid`. Circle and
11
- dynamic charts/spinners/dotted decoration remain local primitives.
12
-
13
- Each iOS glyph slot owns a request owner and revision, including overlays and
14
- UIButton states. Final graphical identity (name, raster geometry/scale and render
15
- strategy) controls requests. A private synchronous bind transaction preserves
16
- both an identical pending request and a ready raster across reset/rebind calls;
17
- changed or empty identities cancel and clear. Only the current attached revision
18
- may apply a completion. Detach, reuse and raster geometry changes invalidate
19
- ownership. UIKit template tint changes reuse the immutable mask. UIButton states
20
- share one decode, retaining template/original and disabled tint/alpha/action
21
- behavior. Name validity and descriptor geometry control visibility, layout and
22
- touch bounds; image availability does not control them.
23
- Detached binds and auto-height measurement use only known intrinsic metadata;
24
- they MUST NOT submit named requests or read/decode SVG resources. Initial attach
25
- starts loading without changing the measured glyph or button dimensions.
26
-
27
- iOS original brand/opacity modes and the size overload's always-template behavior
28
- remain. Android preserves Apple 16 × 20 width-based scaling and clipping by
29
- requesting a proportionate raster and drawing at the old origin. Checkboxes
30
- retain their 16 dp glyph plus 2 dp border offset in selector geometry, otherwise
31
- 80 percent centered geometry. Shared images are immutable; no cross-view mutable
32
- Drawable bounds or pixel changes are allowed. Named work uses image's existing
33
- two-worker and bounded cache service. Web consumers use its pure DOM external-icon
34
- helper while keeping inherited color, action labels, anchors and exact sizes.
35
-
36
- Acceptance must cover actual slots, first bind and repeated row reuse, unknown
37
- and empty inputs, detach/reattach, resize/tint changes, both UIButton states,
38
- checkboxes, Apple, original brands, legacy badge, and Web/desktop menus. All
39
- static path readers must be removed from migrated routes; procedural drawings
40
- and unrelated URI image loading retain their existing ownership.
41
-
42
3
  This is the entry point for the package's behavioral contract. The linked
43
4
  documents are part of this spec; implementation status is separate from target
44
5
  architecture and runtime evidence.
@@ -90,55 +51,6 @@ ordinary press for that gesture. Motion cancellation, row rebind/recycle,
90
51
  disabled state and disposal cancel pending recognition. Trailing accessory
91
52
  actions remain independent. Omission preserves existing tap behavior.
92
53
 
93
- ### Native Swap token menu backport
94
-
95
- Status: implemented in local native source, unreleased. Native build and runtime
96
- acceptance are separate checks. Web and Desktop layout and actions stay unchanged;
97
- their generated icon artwork is covered in the following section.
98
-
99
- iOS and Android render `DotVerSolid` with the app's existing 24-unit solid icon
100
- geometry. On Android, exactly two identity trailing accessories consisting of
101
- `valuePair` followed by an `icon` named `DotVerSolid` with `actionKey: 'menu'`
102
- lay out horizontally, matching iOS. Other icon names or action keys retain the
103
- existing axis rules. This backport does not change row padding, accessory spacing,
104
- button dimensions, actions, disabled state, or the public snapshot contract.
105
-
106
- `NativeListAccessoryStackTests` checks the iOS image lookup and bound button image.
107
- `NativeListRiskAccessoryTest` checks Android's actual icon drawing and the target
108
- horizontal pair, including vertical controls on rebind.
109
-
110
- ### Built-in icon metadata generation
111
-
112
- The closed `scripts/native-list-icons.json` manifest retains platform coverage,
113
- canonical App source paths and iOS rendering strategy. `Circle` is a local
114
- primitive. The NativeList-only legacy `BadgeVerifiedSolid` name maps to
115
- `solid/badge-recognized.svg` / canonical `BadgeRecognizedSolid`, preserving its
116
- thumbs-up artwork without adding a general alias.
117
-
118
- `scripts/generate-icons.mjs --app-root <app-root>` matches each source uniquely
119
- against image's generated catalog, validates source digests and manifest
120
- metadata, then emits exactly three small Swift/Kotlin/Web name/geometry tables.
121
- It writes no SVG, path data or xcassets; image owns the single resource pipeline.
122
- All validation precedes writes. `--check` is read-only and detects missing or
123
- ambiguous sources, invalid metadata and stale output. Stable sorting emits no
124
- machine paths or timestamps. Frozen tests compare exact registry key sets;
125
- this does not prove that every application-computed name is registered.
126
-
127
- The closed manifest contains 43 names with iOS 42, Android 41 and Web 25
128
- registry entries (including DotVerSolid). Document2Outline, WalletOutline and
129
- PlusLargeOutline are registered on all three platforms; TicketOutline also
130
- retains Web and adds native coverage. These main-line names use image-owned
131
- canonical SVGs, not duplicate NativeList paths or asset catalogs.
132
- Existing Activity ten-name and Market/Media private call sites resolve canonical
133
- names through the same DOM helper; their previous coverage does not expand.
134
- Image preserves raw path order, fill rules, fixed colors, opacity and viewBoxes.
135
- NativeList retains its layout, button bounds, actions and snapshot interfaces.
136
-
137
- Focused SDK fixture acceptance covers native attached lifecycle/rebinding,
138
- legacy iOS asset comparisons, shared alpha semantics and real Web/Electron
139
- source/lib consumers. This is not full App, balance, transaction or signed
140
- release acceptance.
141
-
142
54
  Identity trailing accessories stack vertically, except for the pairs every
143
55
  platform lays out side by side: `value` + `checkbox`, `valuePair` + `menu`,
144
56
  `valuePair` + an `icon` named `DotVerSolid` whose `actionKey` is `menu`,
@@ -149,6 +61,13 @@ platform lays out side by side: `value` + `checkbox`, `valuePair` + `menu`,
149
61
  pair is the Swap token selector's balance column and row menu; stacking it
150
62
  clipped both inside the fixed 60dp row on Android.
151
63
 
64
+ Icon names are a closed set drawn from the app's 24-unit Icon sources on every
65
+ platform (`iconPaths` on Android, `NativeListIcons.xcassets` on iOS,
66
+ `selectorIcons` on Web); an unmapped name renders an empty slot rather than a
67
+ placeholder. The set includes every name the app's NativeList builders pass,
68
+ including `DotVerSolid`, `Document2Outline`, `WalletOutline`, `PlusLargeOutline`
69
+ and `TicketOutline` (added 2026-10-30 after the OK-66072 audit found them missing
70
+ on native).
152
71
 
153
72
  A `message` row may opt into `bodyLines: 0`; its complete body wraps within its
154
73
  existing text area and determines natural height unless an explicit row or
@@ -2117,29 +2036,3 @@ A containing Web pager therefore applies insets, collapse/top commands and route
2117
2036
  restoration to the owned host, with slot content as its padding target. The
2118
2037
  ordinary no-slot viewport and explicit external-host paths keep their existing
2119
2038
  ownership; no Pager dependency or new API is required.
2120
-
2121
- ### Shared icon recoloring revision — Implemented; scoped runtime acceptance
2122
-
2123
- Android named glyph slots consume image's typed immutable shape-cache results:
2124
- compatible fixed/single/same-alpha multiple colors update per-view tint without a
2125
- request; new alpha or mixed-color raster requests preserve the last successful
2126
- same-source/geometry bitmap until completion. Name/geometry changes, invalid,
2127
- hidden/detach/recycle clear immediately and revisions reject old callbacks.
2128
- Circle remains local; Apple and checkbox rectangles and coverage are unchanged.
2129
- iOS retains its existing black template/original request and synchronous retint.
2130
- Web React and DOM use the image package's demand-loaded external per-icon symbol
2131
- URLs, with existing coverage/aliases/action labels and CSS color inheritance.
2132
-
2133
- ## Host-owned named resources — Implemented; SDK fixture runtime verified
2134
-
2135
- Image provides decoding and the static Web `#onekey-icon-assets` provider boundary;
2136
- the application owns complete named SVG resources. NativeList keeps its existing
2137
- 43-name platform coverage and three generated metadata tables, including its
2138
- legacy `BadgeVerifiedSolid` to canonical `BadgeRecognizedSolid` mapping. No list
2139
- props, naming coverage, geometry or rendering strategy changes.
2140
-
2141
- The SDK metadata generator validates against the shared 63-sample example/test
2142
- catalog without an App checkout, including raw source digests and viewBox sizes.
2143
- It emits metadata only. Production consumers must supply the complete host icon
2144
- bundle/assets and Web provider; SDK-only fixture tests prove their closed sample
2145
- coverage, while the App's independent generator verifies all 1,909 resources.
@@ -1,7 +1,7 @@
1
1
  import UIKit
2
2
 
3
3
  // OneKey patch: explicit summary actions use the source text's physical-pixel line box.
4
- final class NativeListAccessoryButton: NativeListIconButton {
4
+ final class NativeListAccessoryButton: UIButton {
5
5
  var pressedBackgroundColor: UIColor?
6
6
  var normalBackgroundColor: UIColor = .clear
7
7
  var fixedTextLineHeight: CGFloat?
@@ -197,7 +197,7 @@ final class NativeListAccessoryButton: NativeListIconButton {
197
197
  final class NativeListAccessoryStack: UIStackView {
198
198
  var fonts = NativeListFontFamilies()
199
199
  private let accessoryButtons = (0..<2).map { _ in NativeListAccessoryButton(type: .system) }
200
- private let checkboxButton = NativeListIconButton(type: .system)
200
+ private let checkboxButton = UIButton(type: .system)
201
201
  private let spinner = UIActivityIndicatorView(style: .medium)
202
202
  private var accessoryActions: [(String, NativeSelectionTarget?)] = []
203
203
  private var checkboxAction: (String, NativeSelectionTarget?)?
@@ -250,8 +250,6 @@ final class NativeListAccessoryStack: UIStackView {
250
250
  checkboxState: (NativeListItem, NativeSelectionTarget?, String) -> String,
251
251
  fonts: NativeListFontFamilies
252
252
  ) {
253
- let iconUpdate = NativeListIconUpdate(self)
254
- defer { iconUpdate.finish() }
255
253
  self.fonts = fonts
256
254
  reset()
257
255
  currentItem = item
@@ -503,7 +501,10 @@ final class NativeListAccessoryStack: UIStackView {
503
501
  state == "indeterminate"
504
502
  ? "CheckboxIndeterminateCustom"
505
503
  : "CheckboxCheckedCustom"
506
- checkboxButton.bindIcon(state == "unchecked" ? nil : glyphName)
504
+ checkboxButton.setImage(
505
+ state == "unchecked" ? nil : nativeListIcon(named: glyphName),
506
+ for: .normal
507
+ )
507
508
  checkboxButton.tintColor = checkboxIconColor
508
509
  // A disabled ListItem already applies 0.5 to its complete content. Avoid
509
510
  // multiplying that opacity on the nested control a second time.
@@ -665,7 +666,16 @@ final class NativeListAccessoryStack: UIStackView {
665
666
  button.tintColor = tintColor
666
667
  let isDecorativeRefresh =
667
668
  data.string("name") == "RefreshCcwOutline" && data.string("actionKey").isEmpty
668
- button.bindIcon(data.string("name"), size: isDecorativeRefresh ? CGSize(width: 16, height: 16) : nil)
669
+ let image = isDecorativeRefresh
670
+ ? nativeListIcon(named: data.string("name"), size: CGSize(width: 16, height: 16))
671
+ : nativeListIcon(named: data.string("name"))
672
+ if let image {
673
+ button.setImage(image, for: .normal)
674
+ button.setImage(
675
+ image.withTintColor(tintColor, renderingMode: .alwaysOriginal),
676
+ for: .disabled
677
+ )
678
+ }
669
679
  let isDrillIn = data.string("kind") == "chevron"
670
680
  let isTertiary = data.string("buttonStyle") == "tertiary"
671
681
  if data.string("kind") == "icon" && isTertiary {
@@ -12,7 +12,7 @@ final class NativeListDataRowCell: NativeListRendererCell {
12
12
  }
13
13
 
14
14
  private let visual = NativeListLeadingVisual()
15
- private let favorite = NativeListIconImageView()
15
+ private let favorite = UIImageView()
16
16
  private let accessories = NativeListAccessoryStack()
17
17
  private let trailingAccessories = NativeListAccessoryStack()
18
18
  private let columns = UIStackView()
@@ -51,9 +51,6 @@ final class NativeListDataRowCell: NativeListRendererCell {
51
51
  _ item: NativeListItem, theme: [String: Any]?, layout: String,
52
52
  checkboxState: (NativeListItem, NativeSelectionTarget?, String) -> String
53
53
  ) {
54
- let iconUpdate = NativeListIconUpdate(self)
55
- defer { iconUpdate.finish() }
56
-
57
54
  let data = item.data
58
55
  let style = data.dictionary("style") ?? [:]
59
56
  let image = style.dictionary("image") ?? [:]
@@ -67,7 +64,8 @@ final class NativeListDataRowCell: NativeListRendererCell {
67
64
  let vp = CGFloat(style.double("verticalPadding", default: layout == "table" ? 10 : 8))
68
65
  contentInsets = UIEdgeInsets(top: vp, left: hp, bottom: vp, right: hp)
69
66
  favorite.isHidden = !data.bool("favorite") && !data.bool("favoriteActive")
70
- favorite.bindIcon(data.bool("favoriteActive") ? "StarSolid" : "StarOutline")
67
+ favorite.image = nativeListIcon(
68
+ named: data.bool("favoriteActive") ? "StarSolid" : "StarOutline")
71
69
  favorite.tintColor = nativeListColor(
72
70
  theme, data.bool("favoriteActive") ? "icon" : "iconSubdued",
73
71
  data.bool("favoriteActive") ? "#646464" : "#8D8D8D")
@@ -168,18 +166,13 @@ final class NativeListDataRowCell: NativeListRendererCell {
168
166
  NSLayoutConstraint.activate(columnWidthConstraints)
169
167
  columnWeights = normalizedWeights
170
168
  }
171
-
172
169
  }
173
170
  override func bindSelectionContent(
174
171
  _ item: NativeListItem,
175
172
  checkboxState: (NativeListItem, NativeSelectionTarget?, String) -> String
176
173
  ) {
177
- let iconUpdate = NativeListIconUpdate(self)
178
- defer { iconUpdate.finish() }
179
-
180
174
  accessories.updateSelection(item, checkboxState: checkboxState)
181
175
  trailingAccessories.updateSelection(item, checkboxState: checkboxState)
182
-
183
176
  }
184
177
  override func recycleContent() {
185
178
  visual.recycle()
@@ -192,8 +185,8 @@ final class NativeListDataRowCell: NativeListRendererCell {
192
185
  private final class NativeListTableColumnView: UIStackView {
193
186
  private let primaryLine = UIStackView()
194
187
  private let primaryLabel = NativeListTextLabel()
195
- private let titleIconView = NativeListIconImageView()
196
- private let secondaryTitleIconView = NativeListIconImageView()
188
+ private let titleIconView = UIImageView()
189
+ private let secondaryTitleIconView = UIImageView()
197
190
  private let badgesStack = UIStackView()
198
191
  private let secondaryLine = UIStackView()
199
192
  private let secondaryLeadingLabel = NativeListTextLabel()
@@ -287,7 +280,7 @@ private final class NativeListTableColumnView: UIStackView {
287
280
  for (index, descriptor) in descriptors.enumerated() {
288
281
  guard let descriptor else { continue }
289
282
  let icon = index == 0 ? titleIconView : secondaryTitleIconView
290
- icon.bindIcon(descriptor.string("name"))
283
+ icon.image = nativeListIcon(named: descriptor.string("name"))
291
284
  icon.tintColor = UIColor(
292
285
  nativeListHex: descriptor.string("tintColor",
293
286
  default: theme?["iconSubdued"] as? String ?? "#8D8D8D"),
@@ -310,8 +303,6 @@ private final class NativeListTableColumnView: UIStackView {
310
303
  theme: [String: Any]?,
311
304
  fonts: NativeListFontFamilies
312
305
  ) {
313
- let iconUpdate = NativeListIconUpdate(self)
314
- defer { iconUpdate.finish() }
315
306
  reset()
316
307
  let textAlignment: NSTextAlignment
317
308
  switch column.string("alignment") {
@@ -1,7 +1,8 @@
1
1
  import CoreText
2
- import OneKeyImage
3
2
  import UIKit
4
3
 
4
+ private final class NativeListResourceToken {}
5
+
5
6
  enum NativeListFontWeight {
6
7
  case regular
7
8
  case medium
@@ -18,6 +19,19 @@ enum NativeListFontWeight {
18
19
  }
19
20
  }
20
21
 
22
+ private enum NativeListResources {
23
+ static let bundle: Bundle = {
24
+ let owners = [Bundle(for: NativeListResourceToken.self), .main]
25
+ for owner in owners {
26
+ if let url = owner.url(forResource: "NativeListResources", withExtension: "bundle"),
27
+ let bundle = Bundle(url: url) {
28
+ return bundle
29
+ }
30
+ }
31
+ return Bundle(for: NativeListResourceToken.self)
32
+ }()
33
+ }
34
+
21
35
  struct NativeListFontFamilies: Equatable {
22
36
  let names: [String: String]
23
37
  init(names: [String: String] = [:]) { self.names = names }
@@ -70,19 +84,76 @@ func nativeListTabularFont(
70
84
  descriptor: font.fontDescriptor.addingAttributes([.featureSettings: settings]), size: size)
71
85
  }
72
86
 
73
- func nativeListIconMetadata(named name: String) -> NativeListIconMetadata? {
87
+ func nativeListIcon(named name: String) -> UIImage? {
88
+ // OneKey patch: the connection indicator is a solid circle at its requested size.
74
89
  if name == "Circle" {
75
- return NativeListIconMetadata(name: "Circle", size: CGSize(width: 24, height: 24), original: false)
90
+ return UIGraphicsImageRenderer(size: CGSize(width: 24, height: 24)).image { _ in
91
+ UIColor.black.setFill()
92
+ UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 24, height: 24)).fill()
93
+ }.withRenderingMode(.alwaysTemplate)
76
94
  }
77
- if let generated = NativeListGeneratedIcons.icons[name] {
78
- return generated
95
+ let assetName: String
96
+ switch name {
97
+ // OneKey patch: official selector icon geometry.
98
+ case "AccountErrorCustom": assetName = "onekey_selector_account_error_custom"
99
+ // OneKey patch: official selector icon geometry.
100
+ case "CrossedSmallSolid": assetName = "onekey_selector_crossed_small_solid"
101
+ // OneKey patch: official selector icon geometry.
102
+ case "AllNetworksSolid": assetName = "onekey_selector_all_networks_solid"
103
+ // OneKey patch: official selector icon geometry.
104
+ case "BotIllus": assetName = "onekey_selector_bot_illus"
105
+ // OneKey patch: official selector icon geometry.
106
+ case "AppleBrand": assetName = "onekey_selector_apple_brand"
107
+ // OneKey patch: official selector icon geometry.
108
+ case "GoogleIllus": assetName = "onekey_selector_google_illus"
109
+ // OneKey patch: official selector icon geometry.
110
+ case "LockSolid": assetName = "onekey_selector_lock_solid"
111
+ // OneKey patch: official selector icon geometry.
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"
116
+ case "ArrowBottomOutline": assetName = "onekey_arrow_bottom"
117
+ case "ArrowTopOutline": assetName = "onekey_arrow_top"
118
+ case "ChartTrendingUpOutline": assetName = "onekey_chart_trending_up"
119
+ case "SwapHorOutline": assetName = "onekey_swap_hor"
120
+ case "ShieldExclamationOutline": assetName = "onekey_shield_exclamation"
121
+ case "InfoCircleOutline": assetName = "onekey_info_circle"
122
+ case "SpeakerPromoteOutline": assetName = "onekey_speaker_promote"
123
+ case "PlusCircleOutline": assetName = "onekey_plus_circle"
124
+ case "PlusSmallOutline": assetName = "onekey_plus_small"
125
+ case "DotHorOutline": assetName = "onekey_dot_hor"
126
+ case "PencilOutline": assetName = "onekey_pencil"
127
+ case "MinusCircleSolid": assetName = "onekey_minus_circle_solid"
128
+ case "MinusCircleOutline": assetName = "onekey_minus_circle"
129
+ case "ChevronRightSmallOutline": assetName = "onekey_chevron_right_small"
130
+ case "DragOutline": assetName = "onekey_drag"
131
+ case "StarOutline": assetName = "onekey_star"
132
+ case "StarSolid": assetName = "onekey_star_solid"
133
+ case "BadgeVerifiedSolid": assetName = "onekey_badge_verified_solid"
134
+ case "ChevronGrabberVerOutline": assetName = "onekey_chevron_grabber_ver"
135
+ case "ChevronBottomOutline": assetName = "onekey_chevron_bottom"
136
+ case "ChevronTopOutline": assetName = "onekey_chevron_top"
137
+ case "CheckboxCheckedCustom": assetName = "onekey_checkbox_checked"
138
+ case "CheckboxIndeterminateCustom": assetName = "onekey_checkbox_indeterminate"
139
+ case "ErrorSolid": assetName = "onekey_error_solid"
140
+ case "QuestionmarkSolid": assetName = "onekey_questionmark_solid"
141
+ case "ImageSquareWavesOutline": assetName = "onekey_image_square_waves"
142
+ // Asset-list icons the app passes by name (OK-66072 audit): unmapped names rendered nothing.
143
+ case "DotVerSolid": assetName = "onekey_dot_ver_solid"
144
+ case "Document2Outline": assetName = "onekey_document2"
145
+ case "WalletOutline": assetName = "onekey_wallet"
146
+ case "PlusLargeOutline": assetName = "onekey_plus_large"
147
+ case "TicketOutline": assetName = "onekey_ticket"
148
+ default: return nil
79
149
  }
80
- guard let meta = OneKeyNamedSVG.shared.iconMetadata(forName: name) else {
81
- return nil
82
- }
83
- return NativeListIconMetadata(
84
- name: name,
85
- size: CGSize(width: meta.width, height: meta.height),
86
- original: meta.recolorMode == .fixed || meta.recolorMode == .raster
87
- )
150
+ return UIImage(named: assetName, in: NativeListResources.bundle, compatibleWith: nil)?
151
+ .withRenderingMode(["GoogleIllus", "BotIllus", "AccountErrorCustom"].contains(name) ? .alwaysOriginal : .alwaysTemplate)
152
+ }
153
+
154
+ func nativeListIcon(named name: String, size: CGSize) -> UIImage? {
155
+ guard let image = nativeListIcon(named: name) else { return nil }
156
+ return UIGraphicsImageRenderer(size: size).image { _ in
157
+ image.draw(in: CGRect(origin: .zero, size: size))
158
+ }.withRenderingMode(.alwaysTemplate)
88
159
  }
@@ -109,7 +109,7 @@ final class NativeListIdentityCell: NativeListRendererCell {
109
109
  private let mainStack = UIStackView()
110
110
  private let titleRowStack = UIStackView()
111
111
  private let titleLabel = NativeListTextLabel()
112
- private let titleIconView = NativeListIconImageView()
112
+ private let titleIconView = UIImageView()
113
113
  private var titleImageSlot: NativeListImageSlot?
114
114
  private var titleImageConstraints: [NSLayoutConstraint] = []
115
115
  // Absorbs the title row's slack so the title keeps its intrinsic width and the
@@ -120,7 +120,7 @@ final class NativeListIdentityCell: NativeListRendererCell {
120
120
  private let tertiaryLabel = NativeListTextLabel()
121
121
  private let badgeLabel = NativeListInsetLabel()
122
122
  private let trailingStack = NativeListAccessoryStack(frame: .zero)
123
- private let leadingActionButton = NativeListIconButton(type: .system)
123
+ private let leadingActionButton = UIButton(type: .system)
124
124
  private var leadingWidth: NSLayoutConstraint!
125
125
  private var leadingHeight: NSLayoutConstraint!
126
126
  private var leftInset: CGFloat = 12
@@ -208,9 +208,6 @@ final class NativeListIdentityCell: NativeListRendererCell {
208
208
  _ item: NativeListItem, theme: [String: Any]?, layout: String,
209
209
  checkboxState: (NativeListItem, NativeSelectionTarget?, String) -> String
210
210
  ) {
211
- let iconUpdate = NativeListIconUpdate(self)
212
- defer { iconUpdate.finish() }
213
-
214
211
  selectorTypographyRestorers.reversed().forEach { $0() }
215
212
  selectorTypographyRestorers = []
216
213
  currentItem = item
@@ -301,7 +298,7 @@ final class NativeListIdentityCell: NativeListRendererCell {
301
298
  bindIdentity(item, theme: theme, selected: item.data.bool("selected"), checkboxState)
302
299
  let style = item.data.dictionary("style") ?? [:]
303
300
  if let titleIcon = item.data.dictionary("titleIcon") {
304
- titleIconView.bindIcon(titleIcon.string("name"))
301
+ titleIconView.image = nativeListIcon(named: titleIcon.string("name"))
305
302
  titleIconView.tintColor = UIColor(
306
303
  nativeListHex: titleIcon.string("tintColor",
307
304
  default: theme?["iconSubdued"] as? String ?? "#8D8D8D"),
@@ -410,7 +407,6 @@ final class NativeListIdentityCell: NativeListRendererCell {
410
407
  }
411
408
  settleTitleRowFillerSpacing()
412
409
  applySelectorTypography(item)
413
-
414
410
  }
415
411
 
416
412
  /// The filler is the title row's last arranged view; the stack's default
@@ -426,9 +422,6 @@ final class NativeListIdentityCell: NativeListRendererCell {
426
422
  _ item: NativeListItem,
427
423
  checkboxState: (NativeListItem, NativeSelectionTarget?, String) -> String
428
424
  ) {
429
- let iconUpdate = NativeListIconUpdate(self)
430
- defer { iconUpdate.finish() }
431
-
432
425
  currentItem = item
433
426
  trailingStack.updateSelection(item, checkboxState: checkboxState)
434
427
  if item.data.string("presentation") == "walletSidebar" {
@@ -446,7 +439,6 @@ final class NativeListIdentityCell: NativeListRendererCell {
446
439
  NativeListTextStyles.applyStyledText(titleLabel, style, fonts: fonts)
447
440
  }
448
441
  }
449
-
450
442
  }
451
443
  override func layoutSubviews() {
452
444
  super.layoutSubviews()
@@ -618,7 +610,13 @@ final class NativeListIdentityCell: NativeListRendererCell {
618
610
  fallback: .darkGray
619
611
  )
620
612
  leadingActionButton.tintColor = tintColor
621
- leadingActionButton.bindIcon(leadingAction.string("name"))
613
+ if let image = nativeListIcon(named: leadingAction.string("name")) {
614
+ leadingActionButton.setImage(image, for: .normal)
615
+ leadingActionButton.setImage(
616
+ image.withTintColor(tintColor, renderingMode: .alwaysOriginal),
617
+ for: .disabled
618
+ )
619
+ }
622
620
  leadingActionButton.isEnabled = !leadingAction.bool("disabled")
623
621
  leadingActionButton.alpha = leadingActionButton.isEnabled ? 1 : 0.4
624
622
  leadingActionKey = leadingAction.string("actionKey")
@@ -14,16 +14,16 @@ final class NativeListLeadingVisual: UIView {
14
14
  var overlayTextFontSize: CGFloat = 10
15
15
  var overlayTextLineHeight: CGFloat?
16
16
  var overlayTextHorizontalInset: CGFloat?
17
- private let icon = NativeListIconImageView()
17
+ private let icon = UIImageView()
18
18
  private let unread = UIView()
19
19
  private let networkBackdrop = UIView()
20
20
  // Ring under the secondary token of an Activity pair (SPEC "Activity leading pair").
21
21
  private let pairBackdrop = UIView()
22
- private let corner = NativeListIconImageView()
22
+ private let corner = UIImageView()
23
23
  private let cornerBackdrop = UIView()
24
24
  private var slots: [NativeListImageSlot] = []
25
25
  private var overlaySlots: [NativeListImageSlot] = []
26
- private var overlayFallbackIcons: [NativeListIconImageView] = []
26
+ private var overlayFallbackIcons: [UIImageView] = []
27
27
  private var overlays: [(UIView, [String: Any])] = []
28
28
  private let dashedBorder = CAShapeLayer()
29
29
  private var visual: [String: Any] = [:]
@@ -54,8 +54,6 @@ final class NativeListLeadingVisual: UIView {
54
54
  isUnread: Bool, secondaryVisual: [String: Any]? = nil,
55
55
  fonts: NativeListFontFamilies
56
56
  ) {
57
- let iconUpdate = NativeListIconUpdate(self)
58
- defer { iconUpdate.finish() }
59
57
  self.fonts = fonts
60
58
  fallback.font = nativeListFont(ofSize: 13, weight: .bold, fonts: fonts)
61
59
  self.visual = visual
@@ -113,7 +111,7 @@ final class NativeListLeadingVisual: UIView {
113
111
  fallback.text = String(visual.string("fallbackText").prefix(2))
114
112
  fallback.textColor = UIColor(
115
113
  nativeListHex: visual.string("fallbackTextColor", default: "#8D8D8D"), fallback: .gray)
116
- icon.bindIcon(fallbackData?.string("name"))
114
+ icon.image = fallbackData.map { nativeListIcon(named: $0.string("name")) } ?? nil
117
115
  icon.tintColor = UIColor(
118
116
  nativeListHex: fallbackData?.string("tintColor", default: "#646464") ?? "#646464",
119
117
  fallback: .darkGray)
@@ -177,7 +175,7 @@ final class NativeListLeadingVisual: UIView {
177
175
  let badge = visual.dictionary("cornerIcon")
178
176
  corner.isHidden = badge == nil
179
177
  cornerBackdrop.isHidden = badge == nil
180
- corner.bindIcon(badge?.string("name"))
178
+ corner.image = badge.flatMap { nativeListIcon(named: $0.string("name")) }
181
179
  corner.tintColor = UIColor(
182
180
  nativeListHex: badge?.string("tintColor", default: "#646464") ?? "#646464",
183
181
  fallback: .darkGray)
@@ -189,12 +187,12 @@ final class NativeListLeadingVisual: UIView {
189
187
  overlays.removeAll(keepingCapacity: true)
190
188
  let descriptors = Array(visual.dictionaries("overlays").prefix(2))
191
189
  while overlaySlots.count < descriptors.count { overlaySlots.append(NativeListImageSlot()) }
192
- while overlayFallbackIcons.count < descriptors.count { overlayFallbackIcons.append(NativeListIconImageView()) }
190
+ while overlayFallbackIcons.count < descriptors.count { overlayFallbackIcons.append(UIImageView()) }
193
191
  for (index, data) in descriptors.enumerated() {
194
192
  let frame = index < previousOverlays.count ? previousOverlays[index].0 : UIView()
195
193
  let fallbackData = data.dictionary("fallbackIcon")
196
194
  let fallbackGlyph = overlayFallbackIcons[index]
197
- fallbackGlyph.bindIcon(fallbackData?.string("name"))
195
+ fallbackGlyph.image = fallbackData.flatMap { nativeListIcon(named: $0.string("name")) }
198
196
  fallbackGlyph.tintColor = UIColor(
199
197
  nativeListHex: fallbackData?.string("tintColor", default: "#646464") ?? "#646464",
200
198
  fallback: .darkGray)
@@ -245,8 +243,8 @@ final class NativeListLeadingVisual: UIView {
245
243
  child = label
246
244
  } else {
247
245
  overlaySlots[index].recycle()
248
- let glyph = frame.subviews.first as? NativeListIconImageView ?? NativeListIconImageView()
249
- glyph.bindIcon(data.string("name"))
246
+ let glyph = frame.subviews.first as? UIImageView ?? UIImageView()
247
+ glyph.image = nativeListIcon(named: data.string("name"))
250
248
  glyph.contentMode = .scaleAspectFit
251
249
  glyph.tintColor = UIColor(
252
250
  nativeListHex: data.string("tintColor", default: "#646464"), fallback: .darkGray)
@@ -35,7 +35,7 @@ final class NativeListMarketCell: NativeListRendererCell {
35
35
  private let marketBadgeButtons = (0..<3).map { _ in NativeListAccessoryButton(type: .system) }
36
36
  private let badgeSlots = (0..<3).map { _ in NativeListImageSlot() }
37
37
  private var marketBadgeImages: [UIView] { badgeSlots.map { $0.view } }
38
- private let leadingActionButton = NativeListIconButton(type: .system)
38
+ private let leadingActionButton = UIButton(type: .system)
39
39
  private var leadingWidth: NSLayoutConstraint!
40
40
  private var leadingHeight: NSLayoutConstraint!
41
41
  private var selectorConstraints: [NSLayoutConstraint] = []
@@ -99,9 +99,6 @@ final class NativeListMarketCell: NativeListRendererCell {
99
99
  _ item: NativeListItem, theme: [String: Any]?, layout: String,
100
100
  checkboxState: (NativeListItem, NativeSelectionTarget?, String) -> String
101
101
  ) {
102
- let iconUpdate = NativeListIconUpdate(self)
103
- defer { iconUpdate.finish() }
104
-
105
102
  NSLayoutConstraint.deactivate(selectorConstraints + accessorySizeConstraints)
106
103
  selectorConstraints = []
107
104
  accessorySizeConstraints = []
@@ -169,7 +166,6 @@ final class NativeListMarketCell: NativeListRendererCell {
169
166
  ? .top
170
167
  : style?.dictionary("container")?.string("contentVerticalAlignment") == "bottom"
171
168
  ? .bottom : .center
172
-
173
169
  }
174
170
  private func resetButton(_ button: NativeListAccessoryButton) {
175
171
  button.setTitle(nil, for: .normal)
@@ -502,7 +498,13 @@ final class NativeListMarketCell: NativeListRendererCell {
502
498
  fallback: .darkGray
503
499
  )
504
500
  leadingActionButton.tintColor = tintColor
505
- leadingActionButton.bindIcon(leadingAction.string("name"))
501
+ if let image = nativeListIcon(named: leadingAction.string("name")) {
502
+ leadingActionButton.setImage(image, for: .normal)
503
+ leadingActionButton.setImage(
504
+ image.withTintColor(tintColor, renderingMode: .alwaysOriginal),
505
+ for: .disabled
506
+ )
507
+ }
506
508
  leadingActionButton.isEnabled = !leadingAction.bool("disabled")
507
509
  leadingActionButton.alpha = leadingActionButton.isEnabled ? 1 : 0.4
508
510
  leadingActionButton.accessibilityIdentifier = leadingAction["testID"] as? String
@@ -625,7 +627,11 @@ final class NativeListMarketCell: NativeListRendererCell {
625
627
  button.titleEdgeInsets = .zero
626
628
  button.imageView?.contentMode = .scaleAspectFit
627
629
  if hasBuiltInIcon {
628
- button.bindIcon("BadgeVerifiedSolid", size: CGSize(width: iconSize, height: iconSize))
630
+ button.setImage(
631
+ nativeListIcon(
632
+ named: "BadgeVerifiedSolid", size: CGSize(width: iconSize, height: iconSize)),
633
+ for: .normal
634
+ )
629
635
  }
630
636
  // OneKey patch: match source badge metrics at physical-pixel precision.
631
637
  // let height = button.heightAnchor.constraint(equalToConstant: 18)
@@ -11,7 +11,7 @@ final class NativeListMediaTileCell: NativeListRendererCell {
11
11
  private let picture = UIView()
12
12
  private let image = NativeListMediaPreviewSlot()
13
13
  private let network = NativeListImageSlot()
14
- private let errorIcon = NativeListIconImageView()
14
+ private let errorIcon = UIImageView()
15
15
  private let title = NativeListTextLabel()
16
16
  private let subtitle = NativeListTextLabel()
17
17
  private let badge = NativeListTextLabel()
@@ -87,9 +87,6 @@ final class NativeListMediaTileCell: NativeListRendererCell {
87
87
  _ item: NativeListItem, theme: [String: Any]?, layout: String,
88
88
  checkboxState: (NativeListItem, NativeSelectionTarget?, String) -> String
89
89
  ) {
90
- let iconUpdate = NativeListIconUpdate(self)
91
- defer { iconUpdate.finish() }
92
-
93
90
  let style = item.data.dictionary("style") ?? [:]
94
91
  imageStyle = style.dictionary("image") ?? [:]
95
92
  let hp = CGFloat(style.double("horizontalPadding", default: 10))
@@ -125,7 +122,7 @@ final class NativeListMediaTileCell: NativeListRendererCell {
125
122
  let state = item.data.string("imageState")
126
123
  let placeholder = theme?.string("strongBackground", default: "#0000000F") ?? "#0000000F"
127
124
  errorIcon.isHidden = state != "error"
128
- errorIcon.bindIcon("ImageSquareWavesOutline")
125
+ errorIcon.image = nativeListIcon(named: "ImageSquareWavesOutline")
129
126
  errorIcon.tintColor = UIColor(nativeListHex: "#00000044", fallback: .lightGray)
130
127
  let media = item.data.dictionary("media")
131
128
  if state != "empty", state != "error", let source = media?.dictionary("source") ?? item.data.dictionary("image") {
@@ -167,7 +164,6 @@ final class NativeListMediaTileCell: NativeListRendererCell {
167
164
  close.setTitle("×", for: .normal)
168
165
  close.titleLabel?.font = nativeListFont(ofSize: 16, weight: .medium, fonts: fonts)
169
166
  close.setTitleColor(nativeListColor(theme, "primaryText", "#202020"), for: .normal)
170
-
171
167
  }
172
168
  override func layoutSubviews() {
173
169
  let width = CGFloat(