@momo-kits/native-kits 0.162.1-debug → 0.162.1-gif.1-debug

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 (26) hide show
  1. package/compose/build.gradle.kts +5 -1
  2. package/compose/build.gradle.kts.backup +63 -59
  3. package/compose/src/androidMain/kotlin/vn/momo/kits/fpsmonitor/FPSGraphView.kt +250 -0
  4. package/compose/src/androidMain/kotlin/vn/momo/kits/fpsmonitor/FPSMonitor.kt +249 -0
  5. package/compose/src/androidMain/kotlin/vn/momo/kits/fpsmonitor/FPSOverlayView.kt +99 -0
  6. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +33 -17
  7. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +4 -0
  8. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +1 -1
  9. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +28 -16
  10. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +46 -10
  11. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +4 -2
  12. package/gradle/libs.versions.toml +5 -0
  13. package/gradle.properties +1 -1
  14. package/ios/FPSMonitor/FPSMonitor.swift +562 -0
  15. package/package.json +1 -1
  16. package/publish.sh +2 -2
  17. package/example/ios/Example.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
  18. package/example/ios/Example.xcworkspace/xcuserdata/huynhdung.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  19. package/example/ios/Example.xcworkspace/xcuserdata/huynhdung.xcuserdatad/xcschemes/xcschememanagement.plist +0 -5
  20. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/MoMoUIKits.xcscheme +0 -58
  21. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/Pods-Example.xcscheme +0 -58
  22. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/SDWebImage.xcscheme +0 -58
  23. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/SDWebImageSwiftUI.xcscheme +0 -58
  24. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/SkeletonUI.xcscheme +0 -58
  25. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/xcschememanagement.plist +0 -46
  26. package/local.properties +0 -8
@@ -0,0 +1,562 @@
1
+ import UIKit
2
+ import QuartzCore
3
+ import Darwin
4
+
5
+ @objc(FPSMonitor)
6
+ public final class FPSMonitor: NSObject {
7
+ public static let shared = FPSMonitor()
8
+
9
+ public var onFPSLow: ((CGFloat) -> Void)?
10
+ public var onRamOverload: ((CGFloat) -> Void)?
11
+
12
+ @objc public private(set) var latestFPS: CGFloat = 0
13
+ @objc public private(set) var latestCPUPercent: CGFloat = 0
14
+ @objc public private(set) var latestGPUms: CGFloat = 0
15
+ @objc public private(set) var latestMemoryMB: CGFloat = 0
16
+
17
+ @objc public var ramThreshold: CGFloat
18
+ @objc public var fpsThreshold: CGFloat = 30
19
+ @objc public var updateInterval: TimeInterval = 0.2
20
+
21
+ private var overlayWindow: FPSOverlayWindow?
22
+ private var graphView: FPSGraphView?
23
+ private var displayLink: CADisplayLink?
24
+ private var lastTimestamp: CFTimeInterval = 0
25
+ private var frameCount = 0
26
+ private var lastFPSAlertTime: CFTimeInterval = 0
27
+ private var uiVisible = false
28
+
29
+ private override init() {
30
+ #if targetEnvironment(simulator)
31
+ ramThreshold = 1500
32
+ #else
33
+ ramThreshold = 500
34
+ #endif
35
+ super.init()
36
+
37
+ NotificationCenter.default.addObserver(
38
+ self,
39
+ selector: #selector(appDidBecomeActive),
40
+ name: UIApplication.didBecomeActiveNotification,
41
+ object: nil
42
+ )
43
+ NotificationCenter.default.addObserver(
44
+ self,
45
+ selector: #selector(appWillResignActive),
46
+ name: UIApplication.willResignActiveNotification,
47
+ object: nil
48
+ )
49
+ }
50
+
51
+ @objc(shared)
52
+ public class func sharedObjC() -> FPSMonitor {
53
+ shared
54
+ }
55
+
56
+ deinit {
57
+ NotificationCenter.default.removeObserver(self)
58
+ }
59
+
60
+ @objc public func startOverlay() {
61
+ runOnMain {
62
+ guard self.displayLink == nil else { return }
63
+ self.lastTimestamp = 0
64
+ self.frameCount = 0
65
+ self.uiVisible = false
66
+
67
+ let link = CADisplayLink(target: self, selector: #selector(self.tick(_:)))
68
+ link.add(to: .main, forMode: .common)
69
+ link.isPaused = false
70
+ self.displayLink = link
71
+ }
72
+ }
73
+
74
+ @objc public func stop() {
75
+ runOnMain {
76
+ self.displayLink?.invalidate()
77
+ self.displayLink = nil
78
+
79
+ self.graphView?.removeFromSuperview()
80
+ self.graphView?.isHidden = true
81
+ self.graphView = nil
82
+
83
+ self.overlayWindow?.isHidden = true
84
+ self.overlayWindow?.rootViewController = nil
85
+ self.overlayWindow = nil
86
+
87
+ self.lastTimestamp = 0
88
+ self.frameCount = 0
89
+ self.uiVisible = false
90
+ }
91
+ }
92
+
93
+ @objc public func showUI() {
94
+ runOnMain {
95
+ if self.overlayWindow == nil {
96
+ let window = FPSOverlayWindow(frame: UIScreen.main.bounds)
97
+ window.windowLevel = .statusBar + 99
98
+ window.backgroundColor = .clear
99
+ let windowScenes = UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }
100
+ window.windowScene = windowScenes.first { $0.activationState == .foregroundActive } ?? windowScenes.first
101
+
102
+ let rootViewController = UIViewController()
103
+ rootViewController.view.backgroundColor = .clear
104
+ window.rootViewController = rootViewController
105
+
106
+ let graphView = self.graphView ?? FPSGraphView()
107
+ graphView.backgroundColor = .clear
108
+ window.draggableView = graphView
109
+ rootViewController.view.addSubview(graphView)
110
+
111
+ self.graphView = graphView
112
+ self.overlayWindow = window
113
+ }
114
+
115
+ if self.graphView == nil {
116
+ self.graphView = FPSGraphView(frame: CGRect(x: 10, y: 50, width: 150, height: 80))
117
+ self.overlayWindow?.draggableView = self.graphView
118
+ self.overlayWindow?.rootViewController?.view.addSubview(self.graphView!)
119
+ }
120
+
121
+ self.graphView?.frame = CGRect(x: 10, y: 50, width: 150, height: 80)
122
+ self.graphView?.isHidden = false
123
+ self.overlayWindow?.isHidden = false
124
+ self.uiVisible = true
125
+ }
126
+ }
127
+
128
+ @objc public func hideUI() {
129
+ runOnMain {
130
+ self.graphView?.isHidden = true
131
+ self.graphView?.frame = .zero
132
+ self.overlayWindow?.isHidden = true
133
+ self.uiVisible = false
134
+ }
135
+ }
136
+
137
+ @objc public func metricsSnapshot() -> [String: String] {
138
+ [
139
+ "fps": String(format: "%.2f", latestFPS),
140
+ "usedCPU": String(format: "%.2f", latestCPUPercent),
141
+ "usedGPU": String(format: "%.2f", latestGPUms),
142
+ "usedMemoryMB": String(format: "%.0f", latestMemoryMB),
143
+ ]
144
+ }
145
+
146
+ @objc private func appDidBecomeActive() {
147
+ displayLink?.isPaused = false
148
+ }
149
+
150
+ @objc private func appWillResignActive() {
151
+ displayLink?.isPaused = true
152
+ }
153
+
154
+ @objc private func tick(_ link: CADisplayLink) {
155
+ if lastTimestamp == 0 {
156
+ lastTimestamp = link.timestamp
157
+ return
158
+ }
159
+
160
+ frameCount += 1
161
+ let delta = link.timestamp - lastTimestamp
162
+ guard delta >= updateInterval else { return }
163
+
164
+ let fps = frameCount > 0 && delta > 0 ? CGFloat(Double(frameCount) / delta) : 0
165
+ let frameTime = frameCount > 0 ? delta / Double(frameCount) : 0
166
+ let baseGpuRatio: CGFloat = 0.4
167
+ let fpsVariation = (60 - min(fps, 60)) / 60
168
+ let gpuRatio = baseGpuRatio + fpsVariation * 0.3
169
+ let gpuTimePerFrameMs = CGFloat(frameTime) * gpuRatio * 1000
170
+
171
+ let cpuPercent = currentCPUPercent()
172
+ let memoryMB = currentMemoryMB()
173
+
174
+ if let onRamOverload, memoryMB > ramThreshold {
175
+ ramThreshold += 100
176
+ onRamOverload(memoryMB)
177
+ }
178
+
179
+ latestFPS = fps
180
+ latestCPUPercent = cpuPercent
181
+ latestGPUms = gpuTimePerFrameMs
182
+ latestMemoryMB = memoryMB
183
+
184
+ let now = CFAbsoluteTimeGetCurrent()
185
+ if let onFPSLow, fps < fpsThreshold, now - lastFPSAlertTime >= 0.2 {
186
+ onFPSLow(fps)
187
+ lastFPSAlertTime = now
188
+ }
189
+
190
+ if uiVisible, let graphView {
191
+ let bounds = UIScreen.main.bounds.size
192
+ let scale = UIScreen.main.scale
193
+ let resolution = CGSize(width: bounds.width * scale, height: bounds.height * scale)
194
+ let frameTimeMs = fps > 0 ? 1000 / fps : 0
195
+ let cpuTimeMs = frameTimeMs * min(max(cpuPercent, 0), 100) / 100
196
+
197
+ graphView.update(
198
+ resolution: resolution,
199
+ cpuTime: cpuTimeMs,
200
+ gpuTime: gpuTimePerFrameMs,
201
+ memory: memoryMB
202
+ )
203
+ graphView.addFPS(fps)
204
+ graphView.addCPUTime(cpuTimeMs)
205
+ graphView.addGPUTime(gpuTimePerFrameMs)
206
+ }
207
+
208
+ lastTimestamp = link.timestamp
209
+ frameCount = 0
210
+ }
211
+
212
+ private func currentMemoryMB() -> CGFloat {
213
+ var info = task_vm_info_data_t()
214
+ var count = mach_msg_type_number_t(MemoryLayout<task_vm_info_data_t>.size / MemoryLayout<natural_t>.size)
215
+
216
+ let result = withUnsafeMutablePointer(to: &info) {
217
+ $0.withMemoryRebound(to: integer_t.self, capacity: Int(count)) {
218
+ task_info(mach_task_self_, task_flavor_t(TASK_VM_INFO), $0, &count)
219
+ }
220
+ }
221
+
222
+ guard result == KERN_SUCCESS else { return 0 }
223
+ return CGFloat(info.phys_footprint) / (1024 * 1024)
224
+ }
225
+
226
+ private func currentCPUPercent() -> CGFloat {
227
+ var threadList: thread_act_array_t?
228
+ var threadCount = mach_msg_type_number_t()
229
+
230
+ guard task_threads(mach_task_self_, &threadList, &threadCount) == KERN_SUCCESS,
231
+ let threads = threadList else {
232
+ return 0
233
+ }
234
+
235
+ defer {
236
+ let byteCount = vm_size_t(Int(threadCount) * MemoryLayout<thread_t>.stride)
237
+ vm_deallocate(mach_task_self_, vm_address_t(UInt(bitPattern: threads)), byteCount)
238
+ }
239
+
240
+ var cpuUsage: Float = 0
241
+ for index in 0..<Int(threadCount) {
242
+ var info = thread_basic_info()
243
+ var infoCount = mach_msg_type_number_t(THREAD_INFO_MAX)
244
+ let result = withUnsafeMutablePointer(to: &info) {
245
+ $0.withMemoryRebound(to: integer_t.self, capacity: Int(infoCount)) {
246
+ thread_info(threads[index], thread_flavor_t(THREAD_BASIC_INFO), $0, &infoCount)
247
+ }
248
+ }
249
+
250
+ if result == KERN_SUCCESS, (info.flags & TH_FLAGS_IDLE) == 0 {
251
+ cpuUsage += Float(info.cpu_usage) / Float(TH_USAGE_SCALE) * 100
252
+ }
253
+ }
254
+
255
+ let cores = max(ProcessInfo.processInfo.activeProcessorCount, 1)
256
+ return CGFloat(cpuUsage / Float(cores))
257
+ }
258
+
259
+ private func runOnMain(_ block: @escaping () -> Void) {
260
+ if Thread.isMainThread {
261
+ block()
262
+ } else {
263
+ DispatchQueue.main.async(execute: block)
264
+ }
265
+ }
266
+ }
267
+
268
+ private final class FPSOverlayWindow: UIWindow {
269
+ weak var draggableView: UIView?
270
+
271
+ override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
272
+ guard let draggableView else { return nil }
273
+ let pointInDragView = draggableView.convert(point, from: self)
274
+ guard draggableView.point(inside: pointInDragView, with: event) else { return nil }
275
+ return super.hitTest(point, with: event)
276
+ }
277
+ }
278
+
279
+ private final class FPSGraphView: UIView {
280
+ private var fpsValues: [CGFloat] = []
281
+ private var cpuTimeValues: [CGFloat] = []
282
+ private var gpuTimeValues: [CGFloat] = []
283
+ private let maxPoints = 100
284
+ private let pointSpacing: CGFloat = 2
285
+
286
+ private var currentResolution: CGSize = .zero
287
+ private var currentCPUTime: CGFloat = 0
288
+ private var currentGPUTime: CGFloat = 0
289
+ private var currentMemory: CGFloat = 0
290
+
291
+ private var isCollapsed = false
292
+ private var fullFrame: CGRect = .zero
293
+
294
+ override init(frame: CGRect = CGRect(x: 0, y: 100, width: 150, height: 80)) {
295
+ super.init(frame: frame)
296
+ isOpaque = false
297
+ layer.cornerRadius = 8
298
+ clipsToBounds = true
299
+ fullFrame = frame
300
+ addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:))))
301
+ addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(toggleCollapse)))
302
+ }
303
+
304
+ required init?(coder: NSCoder) {
305
+ super.init(coder: coder)
306
+ }
307
+
308
+ func addFPS(_ fps: CGFloat) {
309
+ append(fps, to: &fpsValues)
310
+ setNeedsDisplay()
311
+ }
312
+
313
+ func addCPUTime(_ cpuTime: CGFloat) {
314
+ append(cpuTime, to: &cpuTimeValues)
315
+ setNeedsDisplay()
316
+ }
317
+
318
+ func addGPUTime(_ gpuTime: CGFloat) {
319
+ append(gpuTime, to: &gpuTimeValues)
320
+ setNeedsDisplay()
321
+ }
322
+
323
+ func update(resolution: CGSize, cpuTime: CGFloat, gpuTime: CGFloat, memory: CGFloat) {
324
+ currentResolution = resolution
325
+ currentCPUTime = cpuTime
326
+ currentGPUTime = gpuTime
327
+ currentMemory = memory
328
+ updateFrameIfNeeded()
329
+ setNeedsDisplay()
330
+ }
331
+
332
+ @objc private func toggleCollapse() {
333
+ if isCollapsed {
334
+ UIView.animate(withDuration: 0.25, animations: {
335
+ self.frame = self.fullFrame
336
+ }, completion: { _ in
337
+ self.isCollapsed = false
338
+ self.setNeedsDisplay()
339
+ })
340
+ } else {
341
+ fullFrame = frame
342
+ isCollapsed = true
343
+ UIView.animate(withDuration: 0.25, animations: {
344
+ self.frame.size = CGSize(width: 44, height: 24)
345
+ }, completion: { _ in
346
+ self.setNeedsDisplay()
347
+ })
348
+ }
349
+ }
350
+
351
+ @objc private func handlePan(_ gesture: UIPanGestureRecognizer) {
352
+ guard let superview else { return }
353
+ let translation = gesture.translation(in: superview)
354
+ var newCenter = CGPoint(x: center.x + translation.x, y: center.y + translation.y)
355
+ let halfWidth = bounds.width / 2
356
+ let halfHeight = bounds.height / 2
357
+ let screen = UIScreen.main.bounds.size
358
+ newCenter.x = max(halfWidth, min(newCenter.x, screen.width - halfWidth))
359
+ newCenter.y = max(halfHeight, min(newCenter.y, screen.height - halfHeight))
360
+ center = newCenter
361
+ gesture.setTranslation(.zero, in: superview)
362
+ }
363
+
364
+ override func draw(_ rect: CGRect) {
365
+ if isCollapsed {
366
+ drawCollapsed(rect)
367
+ return
368
+ }
369
+ drawExpanded(rect)
370
+ }
371
+
372
+ private func drawCollapsed(_ rect: CGRect) {
373
+ guard let context = UIGraphicsGetCurrentContext() else { return }
374
+ context.clear(rect)
375
+ context.setFillColor(UIColor(white: 0, alpha: 0.6).cgColor)
376
+ context.fill(rect)
377
+
378
+ let text = String(format: "%.0f", fpsValues.last ?? 0)
379
+ let attributes: [NSAttributedString.Key: Any] = [
380
+ .font: UIFont.monospacedDigitSystemFont(ofSize: 12, weight: .medium),
381
+ .foregroundColor: UIColor.white,
382
+ ]
383
+ let size = text.size(withAttributes: attributes)
384
+ text.draw(
385
+ at: CGPoint(x: (rect.width - size.width) / 2, y: (rect.height - size.height) / 2),
386
+ withAttributes: attributes
387
+ )
388
+ }
389
+
390
+ private func drawExpanded(_ rect: CGRect) {
391
+ guard let context = UIGraphicsGetCurrentContext() else { return }
392
+ context.clear(rect)
393
+ context.setFillColor(UIColor(white: 0, alpha: 0.6).cgColor)
394
+ context.fill(rect)
395
+
396
+ let margin: CGFloat = 8
397
+ let labelAttrs = attributes(color: .white)
398
+ let fpsColor = UIColor(red: 0, green: 1, blue: 0, alpha: 1)
399
+ let cpuColor = UIColor(red: 1, green: 0.65, blue: 0, alpha: 1)
400
+ let gpuColor = UIColor(red: 0, green: 0.75, blue: 1, alpha: 1)
401
+ let memColor = UIColor(red: 1, green: 0.41, blue: 0.71, alpha: 1)
402
+
403
+ var y = margin
404
+ let deviceName = UIDevice.current.name
405
+ let resolution = String(format: "[%.0fx%.0f]", currentResolution.width, currentResolution.height)
406
+ drawSplit(left: deviceName, right: resolution, y: y, color: .white, rect: rect)
407
+ y += textHeight(labelAttrs) + 2
408
+
409
+ let scale = String(format: "%.1fx", UIScreen.main.scale)
410
+ let refreshRate = "\(UIScreen.main.maximumFramesPerSecond)Hz"
411
+ drawSplit(left: scale, right: refreshRate, y: y, color: .white, rect: rect)
412
+ y += textHeight(labelAttrs) + 6
413
+
414
+ let cpuMinMax = minMax(cpuTimeValues, fallback: currentCPUTime)
415
+ let gpuMinMax = minMax(gpuTimeValues, fallback: currentGPUTime)
416
+ let fpsMinMax = minMax(fpsValues, fallback: fpsValues.last ?? 0)
417
+
418
+ drawSplit(
419
+ left: String(format: "Pre: %.2fms", currentCPUTime),
420
+ right: String(format: "[%.2f %.2f]", cpuMinMax.min, cpuMinMax.max),
421
+ y: y,
422
+ color: cpuColor,
423
+ rect: rect
424
+ )
425
+ y += textHeight(labelAttrs) + 2
426
+
427
+ drawSplit(
428
+ left: String(format: "GPU: %.2fms", currentGPUTime),
429
+ right: String(format: "[%.2f %.2f]", gpuMinMax.min, gpuMinMax.max),
430
+ y: y,
431
+ color: gpuColor,
432
+ rect: rect
433
+ )
434
+ y += textHeight(labelAttrs) + 2
435
+
436
+ drawText(String(format: "Mem: %.1fMB", currentMemory), at: CGPoint(x: margin, y: y), color: memColor)
437
+ y += textHeight(labelAttrs) + 2
438
+
439
+ drawSplit(
440
+ left: String(format: "FPS: %.2f", fpsValues.last ?? 0),
441
+ right: String(format: "[%.2f %.2f]", fpsMinMax.min, fpsMinMax.max),
442
+ y: y,
443
+ color: fpsColor,
444
+ rect: rect
445
+ )
446
+ y += textHeight(labelAttrs) + 6
447
+
448
+ let graphTop = y
449
+ let graphHeight = rect.height - graphTop - margin
450
+ guard graphHeight > 12 else { return }
451
+
452
+ drawGrid(context: context, x: margin, y: graphTop, width: rect.width - margin * 2, height: graphHeight)
453
+ drawLine(context: context, values: fpsValues, x: margin + 2, y: graphTop, width: rect.width - margin * 2 - 4, height: graphHeight, maxScale: 60, color: fpsColor)
454
+ drawLine(context: context, values: cpuTimeValues, x: margin + 2, y: graphTop, width: rect.width - margin * 2 - 4, height: graphHeight, maxScale: 50, color: cpuColor)
455
+ }
456
+
457
+ private func updateFrameIfNeeded() {
458
+ guard !isCollapsed else { return }
459
+ let attrs = attributes(color: .white)
460
+ let lines = [
461
+ "\(UIDevice.current.name) [\(Int(currentResolution.width))x\(Int(currentResolution.height))]",
462
+ String(format: "%.1fx %dHz", UIScreen.main.scale, UIScreen.main.maximumFramesPerSecond),
463
+ "Pre: 99.99ms [99.99 99.99]",
464
+ "GPU: 99.99ms [99.99 99.99]",
465
+ "Mem: 999.9MB",
466
+ "FPS: 99.99 [99.99 99.99]",
467
+ ]
468
+ let width = lines.map { $0.size(withAttributes: attrs).width }.max() ?? 150
469
+ let finalWidth = max(150, width + 16)
470
+ let finalHeight = max(80, textHeight(attrs) * CGFloat(lines.count) + 26)
471
+
472
+ if abs(frame.width - finalWidth) > 1 || abs(frame.height - finalHeight) > 1 {
473
+ frame.size = CGSize(width: finalWidth, height: finalHeight)
474
+ fullFrame = frame
475
+ }
476
+ }
477
+
478
+ private func append(_ value: CGFloat, to values: inout [CGFloat]) {
479
+ if values.count >= maxPoints {
480
+ values.removeFirst()
481
+ }
482
+ values.append(value)
483
+ }
484
+
485
+ private func drawSplit(left: String, right: String, y: CGFloat, color: UIColor, rect: CGRect) {
486
+ let margin: CGFloat = 8
487
+ let rightSize = right.size(withAttributes: attributes(color: color))
488
+ drawText(left, at: CGPoint(x: margin, y: y), color: color)
489
+ drawText(right, at: CGPoint(x: rect.width - margin - rightSize.width, y: y), color: color)
490
+ }
491
+
492
+ private func drawText(_ text: String, at point: CGPoint, color: UIColor) {
493
+ text.draw(at: point, withAttributes: attributes(color: color))
494
+ }
495
+
496
+ private func drawGrid(context: CGContext, x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat) {
497
+ context.setStrokeColor(UIColor(white: 1, alpha: 0.1).cgColor)
498
+ context.setLineWidth(0.5)
499
+ for index in 1...3 {
500
+ let gridY = y + CGFloat(index) * (height / 4)
501
+ context.move(to: CGPoint(x: x, y: gridY))
502
+ context.addLine(to: CGPoint(x: x + width, y: gridY))
503
+ }
504
+ var gridX = x + 20
505
+ while gridX < x + width {
506
+ context.move(to: CGPoint(x: gridX, y: y))
507
+ context.addLine(to: CGPoint(x: gridX, y: y + height))
508
+ gridX += 20
509
+ }
510
+ context.strokePath()
511
+ }
512
+
513
+ private func drawLine(
514
+ context: CGContext,
515
+ values: [CGFloat],
516
+ x: CGFloat,
517
+ y: CGFloat,
518
+ width: CGFloat,
519
+ height: CGFloat,
520
+ maxScale: CGFloat,
521
+ color: UIColor
522
+ ) {
523
+ guard values.count > 1 else { return }
524
+ context.setStrokeColor(color.cgColor)
525
+ context.setLineWidth(1)
526
+
527
+ let visibleValues = Array(values.suffix(Int(width / pointSpacing)))
528
+ for index in 1..<visibleValues.count {
529
+ let previous = point(for: visibleValues[index - 1], index: index - 1, x: x, y: y, height: height, maxScale: maxScale)
530
+ let current = point(for: visibleValues[index], index: index, x: x, y: y, height: height, maxScale: maxScale)
531
+ context.move(to: previous)
532
+ context.addLine(to: current)
533
+ context.strokePath()
534
+ }
535
+ }
536
+
537
+ private func point(for value: CGFloat, index: Int, x: CGFloat, y: CGFloat, height: CGFloat, maxScale: CGFloat) -> CGPoint {
538
+ let normalized = max(0, min(value / maxScale, 1))
539
+ return CGPoint(
540
+ x: x + CGFloat(index) * pointSpacing,
541
+ y: y + height * (1 - normalized)
542
+ )
543
+ }
544
+
545
+ private func minMax(_ values: [CGFloat], fallback: CGFloat) -> (min: CGFloat, max: CGFloat) {
546
+ guard let minValue = values.min(), let maxValue = values.max() else {
547
+ return (fallback, fallback)
548
+ }
549
+ return (minValue, maxValue)
550
+ }
551
+
552
+ private func attributes(color: UIColor) -> [NSAttributedString.Key: Any] {
553
+ [
554
+ .font: UIFont.monospacedDigitSystemFont(ofSize: 10, weight: .regular),
555
+ .foregroundColor: color,
556
+ ]
557
+ }
558
+
559
+ private func textHeight(_ attributes: [NSAttributedString.Key: Any]) -> CGFloat {
560
+ "FPS".size(withAttributes: attributes).height
561
+ }
562
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/native-kits",
3
- "version": "0.162.1-debug",
3
+ "version": "0.162.1-gif.1-debug",
4
4
  "private": false,
5
5
  "dependencies": {},
6
6
  "devDependencies": {},
package/publish.sh CHANGED
@@ -456,7 +456,7 @@ case "$PHASE" in
456
456
  ;;
457
457
  "maven")
458
458
  echo "Running PHASE 2 only: Publish to Maven"
459
- # phase_publish_maven
459
+ phase_publish_maven
460
460
  ;;
461
461
  "npm")
462
462
  echo "Running PHASE 3 only: Publish to NPM"
@@ -465,7 +465,7 @@ case "$PHASE" in
465
465
  "all")
466
466
  echo "Running ALL PHASES"
467
467
  phase_check_version
468
- # phase_publish_maven
468
+ phase_publish_maven
469
469
  phase_publish_npm
470
470
  echo ""
471
471
  echo "🎉 ALL PHASES COMPLETED SUCCESSFULLY!"
@@ -1,14 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
- <plist version="1.0">
4
- <dict>
5
- <key>SchemeUserState</key>
6
- <dict>
7
- <key>Example.xcscheme_^#shared#^_</key>
8
- <dict>
9
- <key>orderHint</key>
10
- <integer>0</integer>
11
- </dict>
12
- </dict>
13
- </dict>
14
- </plist>
@@ -1,5 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
- <plist version="1.0">
4
- <dict />
5
- </plist>
@@ -1,58 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <Scheme
3
- LastUpgradeVersion = "1600"
4
- version = "1.3">
5
- <BuildAction
6
- parallelizeBuildables = "YES"
7
- buildImplicitDependencies = "YES">
8
- <BuildActionEntries>
9
- <BuildActionEntry
10
- buildForTesting = "YES"
11
- buildForRunning = "YES"
12
- buildForProfiling = "YES"
13
- buildForArchiving = "YES"
14
- buildForAnalyzing = "YES">
15
- <BuildableReference
16
- BuildableIdentifier = "primary"
17
- BlueprintIdentifier = "3B6FB503A75BF5BC1FA6F30BC06B9D28"
18
- BuildableName = "MoMoUIKits.framework"
19
- BlueprintName = "MoMoUIKits"
20
- ReferencedContainer = "container:Pods.xcodeproj">
21
- </BuildableReference>
22
- </BuildActionEntry>
23
- </BuildActionEntries>
24
- </BuildAction>
25
- <TestAction
26
- buildConfiguration = "Debug"
27
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29
- shouldUseLaunchSchemeArgsEnv = "YES">
30
- <Testables>
31
- </Testables>
32
- </TestAction>
33
- <LaunchAction
34
- buildConfiguration = "Debug"
35
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
36
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
37
- launchStyle = "0"
38
- useCustomWorkingDirectory = "NO"
39
- ignoresPersistentStateOnLaunch = "NO"
40
- debugDocumentVersioning = "YES"
41
- debugServiceExtension = "internal"
42
- allowLocationSimulation = "YES">
43
- </LaunchAction>
44
- <ProfileAction
45
- buildConfiguration = "Release"
46
- shouldUseLaunchSchemeArgsEnv = "YES"
47
- savedToolIdentifier = ""
48
- useCustomWorkingDirectory = "NO"
49
- debugDocumentVersioning = "YES">
50
- </ProfileAction>
51
- <AnalyzeAction
52
- buildConfiguration = "Debug">
53
- </AnalyzeAction>
54
- <ArchiveAction
55
- buildConfiguration = "Release"
56
- revealArchiveInOrganizer = "YES">
57
- </ArchiveAction>
58
- </Scheme>