@onekeyfe/react-native-perp-depth-bar 3.0.49 → 3.0.53

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 (52) hide show
  1. package/android/src/main/java/com/margelo/nitro/perpdepthbar/HybridPerpDepthBars.kt +98 -11
  2. package/android/src/main/java/com/margelo/nitro/perpdepthbar/HybridPerpSideRatio.kt +17 -6
  3. package/ios/ArrayBufferAlias.swift +5 -0
  4. package/ios/HybridPerpDepthBars.swift +56 -5
  5. package/ios/HybridPerpSideRatio.swift +7 -1
  6. package/ios/PerpColorParser.swift +10 -1
  7. package/lib/nitrogen/generated/android/c++/JHybridPerpDepthBarsSpec.cpp +40 -0
  8. package/lib/nitrogen/generated/android/c++/JHybridPerpDepthBarsSpec.hpp +5 -0
  9. package/lib/nitrogen/generated/android/c++/views/JHybridPerpDepthBarsStateUpdater.cpp +8 -0
  10. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/perpdepthbar/HybridPerpDepthBarsSpec.kt +16 -0
  11. package/lib/nitrogen/generated/ios/c++/HybridPerpDepthBarsSpecSwift.hpp +19 -0
  12. package/lib/nitrogen/generated/ios/c++/views/HybridPerpDepthBarsComponent.mm +10 -0
  13. package/lib/nitrogen/generated/ios/swift/HybridPerpDepthBarsSpec.swift +3 -0
  14. package/lib/nitrogen/generated/ios/swift/HybridPerpDepthBarsSpec_cxx.swift +33 -0
  15. package/lib/nitrogen/generated/shared/c++/HybridPerpDepthBarsSpec.cpp +5 -0
  16. package/lib/nitrogen/generated/shared/c++/HybridPerpDepthBarsSpec.hpp +5 -0
  17. package/lib/nitrogen/generated/shared/c++/views/HybridPerpDepthBarsComponent.cpp +24 -0
  18. package/lib/nitrogen/generated/shared/c++/views/HybridPerpDepthBarsComponent.hpp +2 -0
  19. package/lib/nitrogen/generated/shared/json/PerpDepthBarsConfig.json +2 -0
  20. package/lib/nitrogen/nitrogen/generated/android/c++/JHybridPerpDepthBarsSpec.cpp +40 -0
  21. package/lib/nitrogen/nitrogen/generated/android/c++/JHybridPerpDepthBarsSpec.hpp +5 -0
  22. package/lib/nitrogen/nitrogen/generated/android/c++/views/JHybridPerpDepthBarsStateUpdater.cpp +8 -0
  23. package/lib/nitrogen/nitrogen/generated/android/kotlin/com/margelo/nitro/perpdepthbar/HybridPerpDepthBarsSpec.kt +16 -0
  24. package/lib/nitrogen/nitrogen/generated/ios/c++/HybridPerpDepthBarsSpecSwift.hpp +19 -0
  25. package/lib/nitrogen/nitrogen/generated/ios/c++/views/HybridPerpDepthBarsComponent.mm +10 -0
  26. package/lib/nitrogen/nitrogen/generated/ios/swift/HybridPerpDepthBarsSpec.swift +3 -0
  27. package/lib/nitrogen/nitrogen/generated/ios/swift/HybridPerpDepthBarsSpec_cxx.swift +33 -0
  28. package/lib/nitrogen/nitrogen/generated/shared/c++/HybridPerpDepthBarsSpec.cpp +5 -0
  29. package/lib/nitrogen/nitrogen/generated/shared/c++/HybridPerpDepthBarsSpec.hpp +5 -0
  30. package/lib/nitrogen/nitrogen/generated/shared/c++/views/HybridPerpDepthBarsComponent.cpp +24 -0
  31. package/lib/nitrogen/nitrogen/generated/shared/c++/views/HybridPerpDepthBarsComponent.hpp +2 -0
  32. package/lib/nitrogen/nitrogen/generated/shared/json/PerpDepthBarsConfig.json +2 -0
  33. package/lib/typescript/src/PerpDepthBars.nitro.d.ts +64 -3
  34. package/lib/typescript/src/PerpDepthBars.nitro.d.ts.map +1 -1
  35. package/lib/typescript/src/PerpSideRatio.nitro.d.ts +12 -2
  36. package/lib/typescript/src/PerpSideRatio.nitro.d.ts.map +1 -1
  37. package/nitrogen/generated/android/c++/JHybridPerpDepthBarsSpec.cpp +40 -0
  38. package/nitrogen/generated/android/c++/JHybridPerpDepthBarsSpec.hpp +5 -0
  39. package/nitrogen/generated/android/c++/views/JHybridPerpDepthBarsStateUpdater.cpp +8 -0
  40. package/nitrogen/generated/android/kotlin/com/margelo/nitro/perpdepthbar/HybridPerpDepthBarsSpec.kt +16 -0
  41. package/nitrogen/generated/ios/c++/HybridPerpDepthBarsSpecSwift.hpp +19 -0
  42. package/nitrogen/generated/ios/c++/views/HybridPerpDepthBarsComponent.mm +10 -0
  43. package/nitrogen/generated/ios/swift/HybridPerpDepthBarsSpec.swift +3 -0
  44. package/nitrogen/generated/ios/swift/HybridPerpDepthBarsSpec_cxx.swift +33 -0
  45. package/nitrogen/generated/shared/c++/HybridPerpDepthBarsSpec.cpp +5 -0
  46. package/nitrogen/generated/shared/c++/HybridPerpDepthBarsSpec.hpp +5 -0
  47. package/nitrogen/generated/shared/c++/views/HybridPerpDepthBarsComponent.cpp +24 -0
  48. package/nitrogen/generated/shared/c++/views/HybridPerpDepthBarsComponent.hpp +2 -0
  49. package/nitrogen/generated/shared/json/PerpDepthBarsConfig.json +2 -0
  50. package/package.json +1 -1
  51. package/src/PerpDepthBars.nitro.ts +66 -8
  52. package/src/PerpSideRatio.nitro.ts +12 -2
@@ -36,6 +36,12 @@ class HybridPerpDepthBars(val context: ThemedReactContext) : HybridPerpDepthBars
36
36
  private var lastEpoch = Double.NaN
37
37
  private var hasDrawn = false
38
38
  private var isDisposed = false
39
+ // Set once the caller drives depth through the imperative `setDepth` path. In
40
+ // that mode the `percents` prop is intentionally left empty, so `afterUpdate`
41
+ // must NOT re-sync targets from it — doing so would wipe `current` to an empty
42
+ // array on every unrelated prop commit (e.g. high-frequency prices/sizes text
43
+ // updates), blanking the bars between `setDepth` calls (REACT-NATIVE-1JZ).
44
+ private var imperativeDepth = false
39
45
 
40
46
  private val choreographer = Choreographer.getInstance()
41
47
  private var frameScheduled = false
@@ -44,8 +50,12 @@ class HybridPerpDepthBars(val context: ThemedReactContext) : HybridPerpDepthBars
44
50
 
45
51
  override val view: View = object : View(context) {
46
52
  override fun onDraw(canvas: Canvas) {
47
- drawBars(canvas)
48
- drawTexts(canvas)
53
+ if (hasRealData()) {
54
+ drawBars(canvas)
55
+ drawTexts(canvas)
56
+ } else {
57
+ drawPlaceholder(canvas)
58
+ }
49
59
  }
50
60
 
51
61
  override fun onTouchEvent(event: MotionEvent): Boolean {
@@ -103,13 +113,32 @@ class HybridPerpDepthBars(val context: ThemedReactContext) : HybridPerpDepthBars
103
113
  }
104
114
 
105
115
  // MARK: - Text props
116
+ // The strings actually drawn each frame. Decoupled from the `prices`/`sizes`
117
+ // props so the imperative `setText` path can drive them without the prop
118
+ // setters clobbering the values on unrelated prop commits (REACT-NATIVE-1JZ).
119
+ private var displayPrices: Array<String> = emptyArray()
120
+ private var displaySizes: Array<String> = emptyArray()
121
+ // Set once the caller drives text through `setText`; the `prices`/`sizes` props
122
+ // are then ignored (they are left empty in that mode).
123
+ private var imperativeText = false
124
+
106
125
  override var prices: Array<String> = emptyArray()
107
126
  get() = field
108
- set(value) { if (!isDisposed) { field = value; view.invalidate() } }
127
+ set(value) {
128
+ if (isDisposed || imperativeText) return
129
+ field = value
130
+ displayPrices = value
131
+ view.invalidate()
132
+ }
109
133
 
110
134
  override var sizes: Array<String> = emptyArray()
111
135
  get() = field
112
- set(value) { if (!isDisposed) { field = value; view.invalidate() } }
136
+ set(value) {
137
+ if (isDisposed || imperativeText) return
138
+ field = value
139
+ displaySizes = value
140
+ view.invalidate()
141
+ }
113
142
 
114
143
  override var priceColor: String = ""
115
144
  get() = field
@@ -151,15 +180,30 @@ class HybridPerpDepthBars(val context: ThemedReactContext) : HybridPerpDepthBars
151
180
  get() = field
152
181
  set(value) { if (!isDisposed) { field = value; view.invalidate() } }
153
182
 
183
+ // Per-row placeholder drawn natively while there is no real data (see
184
+ // PerpDepthBars.nitro.ts). Replaces the RN skeleton overlay so there is no
185
+ // blank handoff frame between placeholder and real numbers.
186
+ override var placeholderText: String = ""
187
+ get() = field
188
+ set(value) { if (!isDisposed) { field = value; view.invalidate() } }
189
+
190
+ override var placeholderRows: Double = 0.0
191
+ get() = field
192
+ set(value) { if (!isDisposed) { field = value; view.invalidate() } }
193
+
154
194
  override var onRowPress: ((rowIndex: Double) -> Unit)? = null
155
195
 
196
+ /** True once any real per-row data (bars or text) has been provided. */
197
+ private fun hasRealData(): Boolean =
198
+ current.isNotEmpty() || displayPrices.isNotEmpty() || displaySizes.isNotEmpty()
199
+
156
200
  private fun handleTap(y: Float) {
157
201
  if (isDisposed) return
158
202
  val step = ((rowHeight + rowMarginTop) * density).toFloat()
159
203
  if (step <= 0f) return
160
204
  val mt = (rowMarginTop * density).toFloat()
161
205
  val i = ((y - mt) / step).toInt()
162
- val count = maxOf(percents.size, maxOf(prices.size, sizes.size))
206
+ val count = maxOf(percents.size, maxOf(displayPrices.size, displaySizes.size))
163
207
  if (i in 0 until count) onRowPress?.invoke(i.toDouble())
164
208
  }
165
209
 
@@ -170,6 +214,10 @@ class HybridPerpDepthBars(val context: ThemedReactContext) : HybridPerpDepthBars
170
214
  override fun afterUpdate() {
171
215
  super.afterUpdate()
172
216
  if (isDisposed) return
217
+ // In imperative mode the depth comes from `setDepth`; the `percents` prop is
218
+ // empty and must be ignored here, otherwise every prop commit would wipe the
219
+ // bars. Prop-path callers (never call `setDepth`) keep the original behaviour.
220
+ if (imperativeDepth) return
173
221
  syncTargets(percents)
174
222
  }
175
223
 
@@ -183,6 +231,7 @@ class HybridPerpDepthBars(val context: ThemedReactContext) : HybridPerpDepthBars
183
231
  */
184
232
  override fun setDepth(buffer: ArrayBuffer) {
185
233
  if (isDisposed) return
234
+ imperativeDepth = true
186
235
  val byteBuffer = buffer.getBuffer(false)
187
236
  val count = buffer.size / 4
188
237
  val floats = byteBuffer.order(ByteOrder.LITTLE_ENDIAN).asFloatBuffer()
@@ -190,6 +239,21 @@ class HybridPerpDepthBars(val context: ThemedReactContext) : HybridPerpDepthBars
190
239
  syncTargets(depths)
191
240
  }
192
241
 
242
+ /**
243
+ * Imperative per-row text update — companion to [setDepth] for the price/size
244
+ * layer. Bypasses the high-frequency `prices`/`sizes` prop write path (and the
245
+ * `afterUpdate`/prop-commit machinery) and just retargets the drawn strings in
246
+ * one call. Call in the SAME frame as [setDepth] so bar fill and row text come
247
+ * from the same source frame (REACT-NATIVE-1JZ).
248
+ */
249
+ override fun setText(prices: Array<String>, sizes: Array<String>) {
250
+ if (isDisposed) return
251
+ imperativeText = true
252
+ displayPrices = prices
253
+ displaySizes = sizes
254
+ view.invalidate()
255
+ }
256
+
193
257
  private fun syncTargets(depths: DoubleArray) {
194
258
  val count = depths.size
195
259
  val epochChanged = epoch != lastEpoch
@@ -287,28 +351,51 @@ class HybridPerpDepthBars(val context: ThemedReactContext) : HybridPerpDepthBars
287
351
  }
288
352
 
289
353
  private fun drawTexts(canvas: Canvas) {
290
- if (prices.isEmpty() && sizes.isEmpty()) return
354
+ if (displayPrices.isEmpty() && displaySizes.isEmpty()) return
291
355
  val w = view.width.toFloat()
292
356
  if (w <= 0f) return
293
357
  val rh = (rowHeight * density).toFloat()
294
358
  val mt = (rowMarginTop * density).toFloat()
295
359
  val pad = (textInset * density).toFloat()
296
360
  val rightX = w - pad
297
- val rows = maxOf(prices.size, sizes.size)
361
+ val rows = maxOf(displayPrices.size, displaySizes.size)
298
362
  for (i in 0 until rows) {
299
363
  val rowTop = mt + i * (rh + mt)
300
364
  // Vertically center single-line text within the row.
301
- if (i < prices.size && prices[i].isNotEmpty()) {
365
+ if (i < displayPrices.size && displayPrices[i].isNotEmpty()) {
302
366
  val baseline = rowTop + rh / 2f - (pricePaint.descent() + pricePaint.ascent()) / 2f
303
- canvas.drawText(prices[i], pad, baseline, pricePaint)
367
+ canvas.drawText(displayPrices[i], pad, baseline, pricePaint)
304
368
  }
305
- if (i < sizes.size && sizes[i].isNotEmpty()) {
369
+ if (i < displaySizes.size && displaySizes[i].isNotEmpty()) {
306
370
  val baseline = rowTop + rh / 2f - (sizePaint.descent() + sizePaint.ascent()) / 2f
307
- canvas.drawText(sizes[i], rightX, baseline, sizePaint)
371
+ canvas.drawText(displaySizes[i], rightX, baseline, sizePaint)
308
372
  }
309
373
  }
310
374
  }
311
375
 
376
+ /**
377
+ * Draws `placeholderRows` rows of `placeholderText` (price left / size right,
378
+ * no bar) while there is no real data. Mirrors `drawTexts` geometry so the
379
+ * swap to real numbers is seamless.
380
+ */
381
+ private fun drawPlaceholder(canvas: Canvas) {
382
+ val rows = placeholderRows.toInt()
383
+ if (placeholderText.isEmpty() || rows <= 0) return
384
+ val w = view.width.toFloat()
385
+ if (w <= 0f) return
386
+ val rh = (rowHeight * density).toFloat()
387
+ val mt = (rowMarginTop * density).toFloat()
388
+ val pad = (textInset * density).toFloat()
389
+ val rightX = w - pad
390
+ for (i in 0 until rows) {
391
+ val rowTop = mt + i * (rh + mt)
392
+ val priceBaseline = rowTop + rh / 2f - (pricePaint.descent() + pricePaint.ascent()) / 2f
393
+ canvas.drawText(placeholderText, pad, priceBaseline, pricePaint)
394
+ val sizeBaseline = rowTop + rh / 2f - (sizePaint.descent() + sizePaint.ascent()) / 2f
395
+ canvas.drawText(placeholderText, rightX, sizeBaseline, sizePaint)
396
+ }
397
+ }
398
+
312
399
  private fun clampFrac(percent: Double): Double =
313
400
  (percent.coerceIn(0.0, 100.0)) / 100.0
314
401
 
@@ -29,6 +29,11 @@ class HybridPerpSideRatio(val context: ThemedReactContext) : HybridPerpSideRatio
29
29
  private var targetSplit = 0.5
30
30
  private var hasDrawn = false
31
31
  private var isDisposed = false
32
+ // Set once the caller drives the ratio through `setRatio`. The
33
+ // `bidPercentage`/`askPercentage` props are then ignored in `afterUpdate`,
34
+ // otherwise every prop commit would reset the split back to the (static)
35
+ // initial prop values (REACT-NATIVE-1JZ).
36
+ private var imperativeRatio = false
32
37
 
33
38
  private val choreographer = Choreographer.getInstance()
34
39
  private var frameScheduled = false
@@ -98,17 +103,23 @@ class HybridPerpSideRatio(val context: ThemedReactContext) : HybridPerpSideRatio
98
103
  */
99
104
  override fun setRatio(bidPercentage: Double, askPercentage: Double) {
100
105
  if (isDisposed) return
101
- this.bidPercentage = bidPercentage
102
- this.askPercentage = askPercentage
103
- // Note: the prop path goes through the framework's beforeUpdate()/afterUpdate()
104
- // pair; beforeUpdate() is an empty base-class hook, so calling afterUpdate()
105
- // directly here is equivalent. If beforeUpdate() ever gains behavior, mirror it.
106
- afterUpdate()
106
+ imperativeRatio = true
107
+ // Apply the args directly — do NOT route through the `bidPercentage`/
108
+ // `askPercentage` prop fields, which a later prop commit could overwrite with
109
+ // the static initial values.
110
+ applyRatio(bidPercentage, askPercentage)
107
111
  }
108
112
 
109
113
  override fun afterUpdate() {
110
114
  super.afterUpdate()
111
115
  if (isDisposed) return
116
+ // In imperative mode the ratio comes from `setRatio`; ignore the (static)
117
+ // props so a prop commit can't reset the bar to the initial values.
118
+ if (imperativeRatio) return
119
+ applyRatio(bidPercentage, askPercentage)
120
+ }
121
+
122
+ private fun applyRatio(bidPercentage: Double, askPercentage: Double) {
112
123
  val bid = maxOf(bidPercentage, 1.0)
113
124
  val ask = maxOf(askPercentage, 1.0)
114
125
  val split = bid / (bid + ask)
@@ -0,0 +1,5 @@
1
+ import NitroModules
2
+
3
+ // Keep Nitrogen's generated Swift API resolvable when the imported NitroModules
4
+ // typealias is not visible as an unqualified symbol in dependent pods.
5
+ public typealias ArrayBuffer = margelo.nitro.ArrayBufferHolder
@@ -1,4 +1,5 @@
1
1
  import Foundation
2
+ import NitroModules
2
3
  import UIKit
3
4
 
4
5
  /// Renders an entire column of order-book depth bars for one side (asks/bids).
@@ -61,6 +62,12 @@ final class HybridPerpDepthBars: HybridPerpDepthBarsSpec {
61
62
  var sizeFontSize: Double = 11 { didSet { scheduleLayout() } }
62
63
  var textInset: Double = 0 { didSet { scheduleLayout() } }
63
64
 
65
+ // Per-row placeholder drawn natively while there is no real data (see
66
+ // PerpDepthBars.nitro.ts). Replaces the RN skeleton overlay so there is no
67
+ // blank handoff frame between placeholder and real numbers.
68
+ var placeholderText: String = "" { didSet { scheduleLayout() } }
69
+ var placeholderRows: Double = 0 { didSet { scheduleLayout() } }
70
+
64
71
  var priceColor: String = "" {
65
72
  didSet {
66
73
  cachedPriceColor = PerpColorParser.parse(priceColor).cgColor
@@ -122,6 +129,16 @@ final class HybridPerpDepthBars: HybridPerpDepthBarsSpec {
122
129
  percents = depths
123
130
  }
124
131
 
132
+ /// Imperatively update the per-row price/size text — companion to `setDepth`
133
+ /// for the text layer. Bypasses the high-frequency `prices`/`sizes` prop write
134
+ /// path; assigning them feeds through the identical `didSet` → `scheduleLayout`
135
+ /// → `performLayout` path the prop setters use (REACT-NATIVE-1JZ). Call in the
136
+ /// SAME frame as `setDepth` so bar fill and row text share one source frame.
137
+ func setText(prices: [String], sizes: [String]) throws {
138
+ self.prices = prices
139
+ self.sizes = sizes
140
+ }
141
+
125
142
  private func handleTap(atY y: CGFloat) {
126
143
  let step = CGFloat(rowHeight + rowMarginTop)
127
144
  guard step > 0 else { return }
@@ -133,7 +150,13 @@ final class HybridPerpDepthBars: HybridPerpDepthBarsSpec {
133
150
  }
134
151
 
135
152
  private func scheduleLayout() {
136
- view.setNeedsLayout()
153
+ // Imperative setDepth/setText run on the JS thread (off-main); `setNeedsLayout`
154
+ // must be issued on the main thread.
155
+ if Thread.isMainThread {
156
+ view.setNeedsLayout()
157
+ } else {
158
+ DispatchQueue.main.async { [weak self] in self?.view.setNeedsLayout() }
159
+ }
137
160
  }
138
161
 
139
162
  // MARK: - Layout + retarget
@@ -141,7 +164,13 @@ final class HybridPerpDepthBars: HybridPerpDepthBarsSpec {
141
164
  let bounds = view.bounds
142
165
  guard bounds.width > 0 else { return }
143
166
 
144
- let count = percents.count
167
+ // When there is no real data, draw `placeholderRows` rows of placeholder
168
+ // text (no bar fill) instead of nothing — the native view owns the empty
169
+ // state, so there is no RN overlay to remove and no blank handoff frame.
170
+ let dataCount = percents.count
171
+ let placeholderMode =
172
+ dataCount == 0 && !placeholderText.isEmpty && Int(placeholderRows) > 0
173
+ let count = placeholderMode ? Int(placeholderRows) : dataCount
145
174
  syncLayerCount(count)
146
175
  syncTextLayerCount(count)
147
176
 
@@ -169,8 +198,11 @@ final class HybridPerpDepthBars: HybridPerpDepthBarsSpec {
169
198
  }
170
199
  CATransaction.commit()
171
200
 
201
+ // Placeholder rows have no bar fill (all-zero targets); real rows use data.
172
202
  var newTargets = [CGFloat](repeating: 0, count: count)
173
- for i in 0..<count { newTargets[i] = clampScale(percents[i]) }
203
+ if !placeholderMode {
204
+ for i in 0..<count { newTargets[i] = clampScale(percents[i]) }
205
+ }
174
206
 
175
207
  if snap {
176
208
  stopDisplayLink()
@@ -205,7 +237,8 @@ final class HybridPerpDepthBars: HybridPerpDepthBarsSpec {
205
237
  width: max(half - pad, 0), height: priceLine)
206
238
  priceLayer.fontSize = CGFloat(priceFontSize)
207
239
  priceLayer.foregroundColor = cachedPriceColor
208
- priceLayer.string = i < prices.count ? prices[i] : ""
240
+ priceLayer.string =
241
+ placeholderMode ? placeholderText : (i < prices.count ? prices[i] : "")
209
242
 
210
243
  let sizeLayer = sizeLayers[i]
211
244
  sizeLayer.frame = CGRect(
@@ -213,7 +246,8 @@ final class HybridPerpDepthBars: HybridPerpDepthBarsSpec {
213
246
  width: max(half - pad, 0), height: sizeLine)
214
247
  sizeLayer.fontSize = CGFloat(sizeFontSize)
215
248
  sizeLayer.foregroundColor = cachedSizeColor
216
- sizeLayer.string = i < sizes.count ? sizes[i] : ""
249
+ sizeLayer.string =
250
+ placeholderMode ? placeholderText : (i < sizes.count ? sizes[i] : "")
217
251
  }
218
252
  CATransaction.commit()
219
253
 
@@ -295,6 +329,23 @@ final class HybridPerpDepthBars: HybridPerpDepthBarsSpec {
295
329
  l.alignmentMode = alignment
296
330
  l.truncationMode = .none
297
331
  l.isWrapped = false
332
+ // Disable ALL implicit Core Animation actions on this text layer. CATextLayer
333
+ // crossfades its `contents` whenever `string`/`foregroundColor` changes; even
334
+ // inside `CATransaction.setDisableActions(true)` the fade can leak through, so
335
+ // pin the relevant keys to NSNull() to guarantee instant per-row text switches
336
+ // (PM: no fade/gradient when the order-book text updates). The bar fill keeps
337
+ // its own explicit display-link easing — only text is made instant here.
338
+ let noAction = NSNull()
339
+ l.actions = [
340
+ "contents": noAction,
341
+ "string": noAction,
342
+ "foregroundColor": noAction,
343
+ "fontSize": noAction,
344
+ "bounds": noAction,
345
+ "position": noAction,
346
+ "hidden": noAction,
347
+ "opacity": noAction,
348
+ ]
298
349
  return l
299
350
  }
300
351
 
@@ -71,7 +71,13 @@ final class HybridPerpSideRatio: HybridPerpSideRatioSpec {
71
71
  }
72
72
 
73
73
  private func scheduleLayout() {
74
- view.setNeedsLayout()
74
+ // Imperative setRatio runs on the JS thread (off-main); `setNeedsLayout` must
75
+ // be issued on the main thread.
76
+ if Thread.isMainThread {
77
+ view.setNeedsLayout()
78
+ } else {
79
+ DispatchQueue.main.async { [weak self] in self?.view.setNeedsLayout() }
80
+ }
75
81
  }
76
82
 
77
83
  private func performLayout() {
@@ -100,7 +100,16 @@ final class PerpLayoutView: UIView {
100
100
 
101
101
  override func layoutSubviews() {
102
102
  super.layoutSubviews()
103
- onLayout?()
103
+ guard let onLayout else { return }
104
+ // Fabric (New Architecture) can drive layout off the main thread. The
105
+ // `onLayout` callback mutates CALayer/CATextLayer state, which UIKit requires
106
+ // on the main thread — doing it off-main asserts ("Unsupported layout off the
107
+ // main thread") and can leave the view blank. Hop to main when needed.
108
+ if Thread.isMainThread {
109
+ onLayout()
110
+ } else {
111
+ DispatchQueue.main.async { onLayout() }
112
+ }
104
113
  }
105
114
 
106
115
  override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
@@ -229,6 +229,24 @@ namespace margelo::nitro::perpdepthbar {
229
229
  static const auto method = javaClassStatic()->getMethod<void(double /* textInset */)>("setTextInset");
230
230
  method(_javaPart, textInset);
231
231
  }
232
+ std::string JHybridPerpDepthBarsSpec::getPlaceholderText() {
233
+ static const auto method = javaClassStatic()->getMethod<jni::local_ref<jni::JString>()>("getPlaceholderText");
234
+ auto __result = method(_javaPart);
235
+ return __result->toStdString();
236
+ }
237
+ void JHybridPerpDepthBarsSpec::setPlaceholderText(const std::string& placeholderText) {
238
+ static const auto method = javaClassStatic()->getMethod<void(jni::alias_ref<jni::JString> /* placeholderText */)>("setPlaceholderText");
239
+ method(_javaPart, jni::make_jstring(placeholderText));
240
+ }
241
+ double JHybridPerpDepthBarsSpec::getPlaceholderRows() {
242
+ static const auto method = javaClassStatic()->getMethod<double()>("getPlaceholderRows");
243
+ auto __result = method(_javaPart);
244
+ return __result;
245
+ }
246
+ void JHybridPerpDepthBarsSpec::setPlaceholderRows(double placeholderRows) {
247
+ static const auto method = javaClassStatic()->getMethod<void(double /* placeholderRows */)>("setPlaceholderRows");
248
+ method(_javaPart, placeholderRows);
249
+ }
232
250
  std::optional<std::function<void(double /* rowIndex */)>> JHybridPerpDepthBarsSpec::getOnRowPress() {
233
251
  static const auto method = javaClassStatic()->getMethod<jni::local_ref<JFunc_void_double::javaobject>()>("getOnRowPress_cxx");
234
252
  auto __result = method(_javaPart);
@@ -252,5 +270,27 @@ namespace margelo::nitro::perpdepthbar {
252
270
  static const auto method = javaClassStatic()->getMethod<void(jni::alias_ref<JArrayBuffer::javaobject> /* buffer */)>("setDepth");
253
271
  method(_javaPart, JArrayBuffer::wrap(buffer));
254
272
  }
273
+ void JHybridPerpDepthBarsSpec::setText(const std::vector<std::string>& prices, const std::vector<std::string>& sizes) {
274
+ static const auto method = javaClassStatic()->getMethod<void(jni::alias_ref<jni::JArrayClass<jni::JString>> /* prices */, jni::alias_ref<jni::JArrayClass<jni::JString>> /* sizes */)>("setText");
275
+ method(_javaPart, [&]() {
276
+ size_t __size = prices.size();
277
+ jni::local_ref<jni::JArrayClass<jni::JString>> __array = jni::JArrayClass<jni::JString>::newArray(__size);
278
+ for (size_t __i = 0; __i < __size; __i++) {
279
+ const auto& __element = prices[__i];
280
+ auto __elementJni = jni::make_jstring(__element);
281
+ __array->setElement(__i, *__elementJni);
282
+ }
283
+ return __array;
284
+ }(), [&]() {
285
+ size_t __size = sizes.size();
286
+ jni::local_ref<jni::JArrayClass<jni::JString>> __array = jni::JArrayClass<jni::JString>::newArray(__size);
287
+ for (size_t __i = 0; __i < __size; __i++) {
288
+ const auto& __element = sizes[__i];
289
+ auto __elementJni = jni::make_jstring(__element);
290
+ __array->setElement(__i, *__elementJni);
291
+ }
292
+ return __array;
293
+ }());
294
+ }
255
295
 
256
296
  } // namespace margelo::nitro::perpdepthbar
@@ -80,12 +80,17 @@ namespace margelo::nitro::perpdepthbar {
80
80
  void setSizeFontSize(double sizeFontSize) override;
81
81
  double getTextInset() override;
82
82
  void setTextInset(double textInset) override;
83
+ std::string getPlaceholderText() override;
84
+ void setPlaceholderText(const std::string& placeholderText) override;
85
+ double getPlaceholderRows() override;
86
+ void setPlaceholderRows(double placeholderRows) override;
83
87
  std::optional<std::function<void(double /* rowIndex */)>> getOnRowPress() override;
84
88
  void setOnRowPress(const std::optional<std::function<void(double /* rowIndex */)>>& onRowPress) override;
85
89
 
86
90
  public:
87
91
  // Methods
88
92
  void setDepth(const std::shared_ptr<ArrayBuffer>& buffer) override;
93
+ void setText(const std::vector<std::string>& prices, const std::vector<std::string>& sizes) override;
89
94
 
90
95
  private:
91
96
  friend HybridBase;
@@ -96,6 +96,14 @@ void JHybridPerpDepthBarsStateUpdater::updateViewProps(jni::alias_ref<jni::JClas
96
96
  view->setTextInset(props.textInset.value);
97
97
  // TODO: Set isDirty = false
98
98
  }
99
+ if (props.placeholderText.isDirty) {
100
+ view->setPlaceholderText(props.placeholderText.value);
101
+ // TODO: Set isDirty = false
102
+ }
103
+ if (props.placeholderRows.isDirty) {
104
+ view->setPlaceholderRows(props.placeholderRows.value);
105
+ // TODO: Set isDirty = false
106
+ }
99
107
  if (props.onRowPress.isDirty) {
100
108
  view->setOnRowPress(props.onRowPress.value);
101
109
  // TODO: Set isDirty = false
@@ -133,6 +133,18 @@ abstract class HybridPerpDepthBarsSpec: HybridView() {
133
133
  @set:Keep
134
134
  abstract var textInset: Double
135
135
 
136
+ @get:DoNotStrip
137
+ @get:Keep
138
+ @set:DoNotStrip
139
+ @set:Keep
140
+ abstract var placeholderText: String
141
+
142
+ @get:DoNotStrip
143
+ @get:Keep
144
+ @set:DoNotStrip
145
+ @set:Keep
146
+ abstract var placeholderRows: Double
147
+
136
148
  abstract var onRowPress: ((rowIndex: Double) -> Unit)?
137
149
 
138
150
  private var onRowPress_cxx: Func_void_double?
@@ -151,6 +163,10 @@ abstract class HybridPerpDepthBarsSpec: HybridView() {
151
163
  @DoNotStrip
152
164
  @Keep
153
165
  abstract fun setDepth(buffer: ArrayBuffer): Unit
166
+
167
+ @DoNotStrip
168
+ @Keep
169
+ abstract fun setText(prices: Array<String>, sizes: Array<String>): Unit
154
170
 
155
171
  private external fun initHybrid(): HybridData
156
172
 
@@ -159,6 +159,19 @@ namespace margelo::nitro::perpdepthbar {
159
159
  inline void setTextInset(double textInset) noexcept override {
160
160
  _swiftPart.setTextInset(std::forward<decltype(textInset)>(textInset));
161
161
  }
162
+ inline std::string getPlaceholderText() noexcept override {
163
+ auto __result = _swiftPart.getPlaceholderText();
164
+ return __result;
165
+ }
166
+ inline void setPlaceholderText(const std::string& placeholderText) noexcept override {
167
+ _swiftPart.setPlaceholderText(placeholderText);
168
+ }
169
+ inline double getPlaceholderRows() noexcept override {
170
+ return _swiftPart.getPlaceholderRows();
171
+ }
172
+ inline void setPlaceholderRows(double placeholderRows) noexcept override {
173
+ _swiftPart.setPlaceholderRows(std::forward<decltype(placeholderRows)>(placeholderRows));
174
+ }
162
175
  inline std::optional<std::function<void(double /* rowIndex */)>> getOnRowPress() noexcept override {
163
176
  auto __result = _swiftPart.getOnRowPress();
164
177
  return __result;
@@ -175,6 +188,12 @@ namespace margelo::nitro::perpdepthbar {
175
188
  std::rethrow_exception(__result.error());
176
189
  }
177
190
  }
191
+ inline void setText(const std::vector<std::string>& prices, const std::vector<std::string>& sizes) override {
192
+ auto __result = _swiftPart.setText(prices, sizes);
193
+ if (__result.hasError()) [[unlikely]] {
194
+ std::rethrow_exception(__result.error());
195
+ }
196
+ }
178
197
 
179
198
  private:
180
199
  PerpDepthBar::HybridPerpDepthBarsSpec_cxx _swiftPart;
@@ -146,6 +146,16 @@ using namespace margelo::nitro::perpdepthbar::views;
146
146
  swiftPart.setTextInset(newViewProps.textInset.value);
147
147
  newViewProps.textInset.isDirty = false;
148
148
  }
149
+ // placeholderText: string
150
+ if (newViewProps.placeholderText.isDirty) {
151
+ swiftPart.setPlaceholderText(newViewProps.placeholderText.value);
152
+ newViewProps.placeholderText.isDirty = false;
153
+ }
154
+ // placeholderRows: number
155
+ if (newViewProps.placeholderRows.isDirty) {
156
+ swiftPart.setPlaceholderRows(newViewProps.placeholderRows.value);
157
+ newViewProps.placeholderRows.isDirty = false;
158
+ }
149
159
  // onRowPress: optional
150
160
  if (newViewProps.onRowPress.isDirty) {
151
161
  swiftPart.setOnRowPress(newViewProps.onRowPress.value);
@@ -26,10 +26,13 @@ public protocol HybridPerpDepthBarsSpec_protocol: HybridObject, HybridView {
26
26
  var priceFontSize: Double { get set }
27
27
  var sizeFontSize: Double { get set }
28
28
  var textInset: Double { get set }
29
+ var placeholderText: String { get set }
30
+ var placeholderRows: Double { get set }
29
31
  var onRowPress: ((_ rowIndex: Double) -> Void)? { get set }
30
32
 
31
33
  // Methods
32
34
  func setDepth(buffer: ArrayBuffer) throws -> Void
35
+ func setText(prices: [String], sizes: [String]) throws -> Void
33
36
  }
34
37
 
35
38
  public extension HybridPerpDepthBarsSpec_protocol {
@@ -297,6 +297,28 @@ open class HybridPerpDepthBarsSpec_cxx {
297
297
  }
298
298
  }
299
299
 
300
+ public final var placeholderText: std.string {
301
+ @inline(__always)
302
+ get {
303
+ return std.string(self.__implementation.placeholderText)
304
+ }
305
+ @inline(__always)
306
+ set {
307
+ self.__implementation.placeholderText = String(newValue)
308
+ }
309
+ }
310
+
311
+ public final var placeholderRows: Double {
312
+ @inline(__always)
313
+ get {
314
+ return self.__implementation.placeholderRows
315
+ }
316
+ @inline(__always)
317
+ set {
318
+ self.__implementation.placeholderRows = newValue
319
+ }
320
+ }
321
+
300
322
  public final var onRowPress: bridge.std__optional_std__function_void_double____rowIndex______ {
301
323
  @inline(__always)
302
324
  get {
@@ -341,6 +363,17 @@ open class HybridPerpDepthBarsSpec_cxx {
341
363
  }
342
364
  }
343
365
 
366
+ @inline(__always)
367
+ public final func setText(prices: bridge.std__vector_std__string_, sizes: bridge.std__vector_std__string_) -> bridge.Result_void_ {
368
+ do {
369
+ try self.__implementation.setText(prices: prices.map({ __item in String(__item) }), sizes: sizes.map({ __item in String(__item) }))
370
+ return bridge.create_Result_void_()
371
+ } catch (let __error) {
372
+ let __exceptionPtr = __error.toCpp()
373
+ return bridge.create_Result_void_(__exceptionPtr)
374
+ }
375
+ }
376
+
344
377
  public final func getView() -> UnsafeMutableRawPointer {
345
378
  return Unmanaged.passRetained(__implementation.view).toOpaque()
346
379
  }
@@ -44,9 +44,14 @@ namespace margelo::nitro::perpdepthbar {
44
44
  prototype.registerHybridSetter("sizeFontSize", &HybridPerpDepthBarsSpec::setSizeFontSize);
45
45
  prototype.registerHybridGetter("textInset", &HybridPerpDepthBarsSpec::getTextInset);
46
46
  prototype.registerHybridSetter("textInset", &HybridPerpDepthBarsSpec::setTextInset);
47
+ prototype.registerHybridGetter("placeholderText", &HybridPerpDepthBarsSpec::getPlaceholderText);
48
+ prototype.registerHybridSetter("placeholderText", &HybridPerpDepthBarsSpec::setPlaceholderText);
49
+ prototype.registerHybridGetter("placeholderRows", &HybridPerpDepthBarsSpec::getPlaceholderRows);
50
+ prototype.registerHybridSetter("placeholderRows", &HybridPerpDepthBarsSpec::setPlaceholderRows);
47
51
  prototype.registerHybridGetter("onRowPress", &HybridPerpDepthBarsSpec::getOnRowPress);
48
52
  prototype.registerHybridSetter("onRowPress", &HybridPerpDepthBarsSpec::setOnRowPress);
49
53
  prototype.registerHybridMethod("setDepth", &HybridPerpDepthBarsSpec::setDepth);
54
+ prototype.registerHybridMethod("setText", &HybridPerpDepthBarsSpec::setText);
50
55
  });
51
56
  }
52
57
 
@@ -78,12 +78,17 @@ namespace margelo::nitro::perpdepthbar {
78
78
  virtual void setSizeFontSize(double sizeFontSize) = 0;
79
79
  virtual double getTextInset() = 0;
80
80
  virtual void setTextInset(double textInset) = 0;
81
+ virtual std::string getPlaceholderText() = 0;
82
+ virtual void setPlaceholderText(const std::string& placeholderText) = 0;
83
+ virtual double getPlaceholderRows() = 0;
84
+ virtual void setPlaceholderRows(double placeholderRows) = 0;
81
85
  virtual std::optional<std::function<void(double /* rowIndex */)>> getOnRowPress() = 0;
82
86
  virtual void setOnRowPress(const std::optional<std::function<void(double /* rowIndex */)>>& onRowPress) = 0;
83
87
 
84
88
  public:
85
89
  // Methods
86
90
  virtual void setDepth(const std::shared_ptr<ArrayBuffer>& buffer) = 0;
91
+ virtual void setText(const std::vector<std::string>& prices, const std::vector<std::string>& sizes) = 0;
87
92
 
88
93
  protected:
89
94
  // Hybrid Setup