@onekeyfe/react-native-skeleton 1.1.11 → 1.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java/com/margelo/nitro/skeleton/Skeleton.kt +66 -6
- package/ios/Skeleton.swift +147 -41
- package/lib/nitrogen/generated/android/c++/JHybridSkeletonSpec.cpp +1 -1
- package/lib/nitrogen/generated/android/c++/JHybridSkeletonSpec.hpp +1 -1
- package/lib/nitrogen/generated/android/c++/views/JHybridSkeletonStateUpdater.cpp +1 -1
- package/lib/nitrogen/generated/android/c++/views/JHybridSkeletonStateUpdater.hpp +1 -1
- package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/skeleton/HybridSkeletonSpec.kt +1 -1
- package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/skeleton/skeletonOnLoad.kt +1 -1
- package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/skeleton/views/HybridSkeletonManager.kt +1 -1
- package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/skeleton/views/HybridSkeletonStateUpdater.kt +1 -1
- package/lib/nitrogen/generated/android/skeleton+autolinking.cmake +1 -1
- package/lib/nitrogen/generated/android/skeleton+autolinking.gradle +1 -1
- package/lib/nitrogen/generated/android/skeletonOnLoad.cpp +1 -1
- package/lib/nitrogen/generated/android/skeletonOnLoad.hpp +1 -1
- package/lib/nitrogen/generated/ios/Skeleton+autolinking.rb +1 -1
- package/lib/nitrogen/generated/ios/Skeleton-Swift-Cxx-Bridge.cpp +1 -1
- package/lib/nitrogen/generated/ios/Skeleton-Swift-Cxx-Bridge.hpp +1 -1
- package/lib/nitrogen/generated/ios/Skeleton-Swift-Cxx-Umbrella.hpp +1 -1
- package/lib/nitrogen/generated/ios/SkeletonAutolinking.mm +1 -1
- package/lib/nitrogen/generated/ios/SkeletonAutolinking.swift +1 -1
- package/lib/nitrogen/generated/ios/c++/HybridSkeletonSpecSwift.cpp +1 -1
- package/lib/nitrogen/generated/ios/c++/HybridSkeletonSpecSwift.hpp +1 -1
- package/lib/nitrogen/generated/ios/c++/views/HybridSkeletonComponent.mm +1 -1
- package/lib/nitrogen/generated/ios/swift/HybridSkeletonSpec.swift +1 -1
- package/lib/nitrogen/generated/ios/swift/HybridSkeletonSpec_cxx.swift +1 -1
- package/lib/nitrogen/generated/shared/c++/HybridSkeletonSpec.cpp +1 -1
- package/lib/nitrogen/generated/shared/c++/HybridSkeletonSpec.hpp +1 -1
- package/lib/nitrogen/generated/shared/c++/views/HybridSkeletonComponent.cpp +1 -1
- package/lib/nitrogen/generated/shared/c++/views/HybridSkeletonComponent.hpp +1 -1
- package/nitrogen/generated/android/c++/JHybridSkeletonSpec.cpp +1 -1
- package/nitrogen/generated/android/c++/JHybridSkeletonSpec.hpp +1 -1
- package/nitrogen/generated/android/c++/views/JHybridSkeletonStateUpdater.cpp +1 -1
- package/nitrogen/generated/android/c++/views/JHybridSkeletonStateUpdater.hpp +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/skeleton/HybridSkeletonSpec.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/skeleton/skeletonOnLoad.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/skeleton/views/HybridSkeletonManager.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/skeleton/views/HybridSkeletonStateUpdater.kt +1 -1
- package/nitrogen/generated/android/skeleton+autolinking.cmake +1 -1
- package/nitrogen/generated/android/skeleton+autolinking.gradle +1 -1
- package/nitrogen/generated/android/skeletonOnLoad.cpp +1 -1
- package/nitrogen/generated/android/skeletonOnLoad.hpp +1 -1
- package/nitrogen/generated/ios/Skeleton+autolinking.rb +1 -1
- package/nitrogen/generated/ios/Skeleton-Swift-Cxx-Bridge.cpp +1 -1
- package/nitrogen/generated/ios/Skeleton-Swift-Cxx-Bridge.hpp +1 -1
- package/nitrogen/generated/ios/Skeleton-Swift-Cxx-Umbrella.hpp +1 -1
- package/nitrogen/generated/ios/SkeletonAutolinking.mm +1 -1
- package/nitrogen/generated/ios/SkeletonAutolinking.swift +1 -1
- package/nitrogen/generated/ios/c++/HybridSkeletonSpecSwift.cpp +1 -1
- package/nitrogen/generated/ios/c++/HybridSkeletonSpecSwift.hpp +1 -1
- package/nitrogen/generated/ios/c++/views/HybridSkeletonComponent.mm +1 -1
- package/nitrogen/generated/ios/swift/HybridSkeletonSpec.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridSkeletonSpec_cxx.swift +1 -1
- package/nitrogen/generated/shared/c++/HybridSkeletonSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridSkeletonSpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/views/HybridSkeletonComponent.cpp +1 -1
- package/nitrogen/generated/shared/c++/views/HybridSkeletonComponent.hpp +1 -1
- package/package.json +1 -1
|
@@ -30,6 +30,12 @@ class HybridSkeleton(val context: ThemedReactContext) : HybridSkeletonSpec() {
|
|
|
30
30
|
private var customGradientColors: IntArray? = null
|
|
31
31
|
private var animationSpeed: Long = 3000L
|
|
32
32
|
|
|
33
|
+
// Memory safety flags
|
|
34
|
+
private var isDisposed: Boolean = false
|
|
35
|
+
private var retryCount: Int = 0
|
|
36
|
+
private val maxRetryCount: Int = 10
|
|
37
|
+
private var pendingStartRunnable: Runnable? = null
|
|
38
|
+
|
|
33
39
|
// View with shimmer effect
|
|
34
40
|
override val view: View = object : View(context) {
|
|
35
41
|
override fun onDraw(canvas: Canvas) {
|
|
@@ -59,6 +65,7 @@ class HybridSkeleton(val context: ThemedReactContext) : HybridSkeletonSpec() {
|
|
|
59
65
|
override var shimmerSpeed: Double?
|
|
60
66
|
get() = animationSpeed.toDouble() / 1000.0
|
|
61
67
|
set(value) {
|
|
68
|
+
if (isDisposed) return
|
|
62
69
|
animationSpeed = ((value ?: 3.0) * 1000).toLong()
|
|
63
70
|
restartShimmer()
|
|
64
71
|
}
|
|
@@ -66,6 +73,7 @@ class HybridSkeleton(val context: ThemedReactContext) : HybridSkeletonSpec() {
|
|
|
66
73
|
override var shimmerGradientColors: Array<String>?
|
|
67
74
|
get() = customGradientColors?.map { String.format("#%06X", 0xFFFFFF and it) }?.toTypedArray()
|
|
68
75
|
set(value) {
|
|
76
|
+
if (isDisposed) return
|
|
69
77
|
if (value != null) {
|
|
70
78
|
customGradientColors = value.map { hexStringToColor(it) }.toIntArray()
|
|
71
79
|
restartShimmer()
|
|
@@ -83,10 +91,35 @@ class HybridSkeleton(val context: ThemedReactContext) : HybridSkeletonSpec() {
|
|
|
83
91
|
}
|
|
84
92
|
|
|
85
93
|
private fun startShimmer() {
|
|
94
|
+
if (isDisposed) return
|
|
95
|
+
|
|
86
96
|
stopShimmer()
|
|
97
|
+
retryCount = 0 // Reset retry count
|
|
98
|
+
startShimmerInternal()
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private fun startShimmerInternal() {
|
|
102
|
+
if (isDisposed) return
|
|
87
103
|
|
|
88
104
|
if (view.width == 0 || view.height == 0) {
|
|
89
|
-
|
|
105
|
+
// Check if we have exceeded max retry count
|
|
106
|
+
if (retryCount >= maxRetryCount) {
|
|
107
|
+
android.util.Log.w("HybridSkeleton", "Max retry count reached. View bounds are still empty.")
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
retryCount++
|
|
112
|
+
// Clean up previous pending runnable
|
|
113
|
+
pendingStartRunnable?.let { view.removeCallbacks(it) }
|
|
114
|
+
|
|
115
|
+
// Create new runnable and schedule
|
|
116
|
+
val runnable = Runnable {
|
|
117
|
+
if (!isDisposed) {
|
|
118
|
+
startShimmerInternal()
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
pendingStartRunnable = runnable
|
|
122
|
+
view.postDelayed(runnable, 100)
|
|
90
123
|
return
|
|
91
124
|
}
|
|
92
125
|
|
|
@@ -97,26 +130,42 @@ class HybridSkeleton(val context: ThemedReactContext) : HybridSkeletonSpec() {
|
|
|
97
130
|
repeatCount = ValueAnimator.INFINITE
|
|
98
131
|
interpolator = LinearInterpolator()
|
|
99
132
|
addUpdateListener { animation ->
|
|
100
|
-
|
|
101
|
-
|
|
133
|
+
if (!isDisposed) {
|
|
134
|
+
translateX = animation.animatedValue as Float
|
|
135
|
+
view.invalidate()
|
|
136
|
+
}
|
|
102
137
|
}
|
|
103
138
|
start()
|
|
104
139
|
}
|
|
105
140
|
}
|
|
106
141
|
|
|
107
142
|
private fun stopShimmer() {
|
|
108
|
-
|
|
143
|
+
// Clean up pending runnable
|
|
144
|
+
pendingStartRunnable?.let {
|
|
145
|
+
view.removeCallbacks(it)
|
|
146
|
+
pendingStartRunnable = null
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Clean up animator and its listeners
|
|
150
|
+
shimmerAnimator?.apply {
|
|
151
|
+
removeAllUpdateListeners()
|
|
152
|
+
cancel()
|
|
153
|
+
}
|
|
109
154
|
shimmerAnimator = null
|
|
110
155
|
}
|
|
111
156
|
|
|
112
157
|
override fun afterUpdate() {
|
|
113
158
|
super.afterUpdate()
|
|
114
|
-
|
|
159
|
+
if (!isDisposed) {
|
|
160
|
+
restartShimmer()
|
|
161
|
+
}
|
|
115
162
|
}
|
|
116
163
|
|
|
117
164
|
private fun restartShimmer() {
|
|
165
|
+
if (isDisposed) return
|
|
118
166
|
stopShimmer()
|
|
119
|
-
|
|
167
|
+
retryCount = 0 // Reset retry count on restart
|
|
168
|
+
startShimmerInternal()
|
|
120
169
|
}
|
|
121
170
|
|
|
122
171
|
private fun hexStringToColor(hexColor: String): Int {
|
|
@@ -132,4 +181,15 @@ class HybridSkeleton(val context: ThemedReactContext) : HybridSkeletonSpec() {
|
|
|
132
181
|
DEFAULT_GRADIENT_COLORS[0]
|
|
133
182
|
}
|
|
134
183
|
}
|
|
184
|
+
|
|
185
|
+
override fun dispose() {
|
|
186
|
+
// Mark as disposed to prevent any new operations
|
|
187
|
+
isDisposed = true
|
|
188
|
+
|
|
189
|
+
// Stop all animations and clean up
|
|
190
|
+
stopShimmer()
|
|
191
|
+
|
|
192
|
+
// Clear view references to prevent memory leaks
|
|
193
|
+
view.invalidate()
|
|
194
|
+
}
|
|
135
195
|
}
|
package/ios/Skeleton.swift
CHANGED
|
@@ -5,80 +5,161 @@ import UIKit
|
|
|
5
5
|
let DEFAULT_GRADIENT_COLORS: [UIColor] = [UIColor(red: 210.0/255.0, green: 210.0/255.0, blue: 210.0/255.0, alpha: 1.0), UIColor(red: 235.0/255.0, green: 235.0/255.0, blue: 235.0/255.0, alpha: 1.0)]
|
|
6
6
|
|
|
7
7
|
class HybridSkeleton : HybridSkeletonSpec {
|
|
8
|
-
|
|
9
|
-
// Shimmer
|
|
8
|
+
|
|
9
|
+
// Shimmer layers
|
|
10
10
|
private var shimmerLayer: CAGradientLayer?
|
|
11
|
+
private var skeletonLayer: CALayer?
|
|
11
12
|
private var customGradientColors: [UIColor]?
|
|
12
|
-
|
|
13
|
+
private var isActive: Bool = true
|
|
14
|
+
private var retryCount: Int = 0
|
|
15
|
+
private let maxRetryCount: Int = 10
|
|
16
|
+
private var viewObserver: NSKeyValueObservation?
|
|
17
|
+
|
|
13
18
|
var shimmerGradientColors: [String]? {
|
|
14
19
|
didSet {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
guard isActive else { return }
|
|
21
|
+
DispatchQueue.main.async { [weak self] in
|
|
22
|
+
guard let self = self, self.isActive else { return }
|
|
23
|
+
self.customGradientColors = shimmerGradientColors?.map { self.hexStringToUIColor(hexColor: $0) }
|
|
24
|
+
self.restartShimmer()
|
|
20
25
|
}
|
|
21
26
|
}
|
|
22
27
|
}
|
|
23
|
-
|
|
28
|
+
|
|
24
29
|
// UIView
|
|
25
30
|
var view: UIView = UIView()
|
|
26
31
|
|
|
27
32
|
var shimmerSpeed: Double? {
|
|
28
33
|
didSet {
|
|
29
|
-
|
|
34
|
+
guard isActive else { return }
|
|
35
|
+
DispatchQueue.main.async { [weak self] in
|
|
36
|
+
guard let self = self, self.isActive else { return }
|
|
37
|
+
self.restartShimmer()
|
|
38
|
+
}
|
|
30
39
|
}
|
|
31
40
|
}
|
|
32
|
-
|
|
41
|
+
|
|
33
42
|
override init() {
|
|
34
43
|
super.init()
|
|
35
44
|
setupView()
|
|
36
45
|
}
|
|
37
|
-
|
|
46
|
+
|
|
47
|
+
deinit {
|
|
48
|
+
// Mark as inactive to prevent any new operations
|
|
49
|
+
isActive = false
|
|
50
|
+
|
|
51
|
+
// Clean up observer
|
|
52
|
+
viewObserver?.invalidate()
|
|
53
|
+
viewObserver = nil
|
|
54
|
+
|
|
55
|
+
// Cleanup must happen on main thread, but avoid deadlock
|
|
56
|
+
// Use async if not on main thread to prevent blocking
|
|
57
|
+
if Thread.isMainThread {
|
|
58
|
+
stopShimmer()
|
|
59
|
+
// Clear view reference and ensure no dangling animations
|
|
60
|
+
view.layer.removeAllAnimations()
|
|
61
|
+
view.layer.sublayers?.removeAll()
|
|
62
|
+
view.layer.mask = nil
|
|
63
|
+
} else {
|
|
64
|
+
// Use async to avoid potential deadlock with sync
|
|
65
|
+
// All CALayer operations must happen on main thread
|
|
66
|
+
let shimmer = self.shimmerLayer
|
|
67
|
+
let skeleton = self.skeletonLayer
|
|
68
|
+
DispatchQueue.main.async { [weak view = self.view] in
|
|
69
|
+
guard let view = view else { return }
|
|
70
|
+
// Stop shimmer animations
|
|
71
|
+
shimmer?.removeAllAnimations()
|
|
72
|
+
shimmer?.removeFromSuperlayer()
|
|
73
|
+
|
|
74
|
+
// Clear mask reference
|
|
75
|
+
if view.layer.mask === skeleton {
|
|
76
|
+
view.layer.mask = nil
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Clean up remaining animations and sublayers
|
|
80
|
+
view.layer.removeAllAnimations()
|
|
81
|
+
view.layer.sublayers?.removeAll()
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
38
86
|
private func setupView() {
|
|
39
87
|
view.clipsToBounds = true
|
|
40
|
-
|
|
88
|
+
|
|
89
|
+
// Observe view hierarchy changes for cleanup
|
|
90
|
+
viewObserver = view.observe(\.superview, options: [.new]) { [weak self] view, change in
|
|
91
|
+
guard let self = self else { return }
|
|
92
|
+
if change.newValue == nil {
|
|
93
|
+
// View was removed from hierarchy, clean up
|
|
94
|
+
DispatchQueue.main.async { [weak self] in
|
|
95
|
+
self?.stopShimmer()
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
41
100
|
// Start animation when view is ready
|
|
42
|
-
DispatchQueue.main.async {
|
|
101
|
+
DispatchQueue.main.async { [weak self] in
|
|
102
|
+
guard let self = self, self.isActive else { return }
|
|
43
103
|
self.startShimmer()
|
|
44
104
|
}
|
|
45
105
|
}
|
|
46
|
-
|
|
106
|
+
|
|
47
107
|
func startShimmer() {
|
|
108
|
+
retryCount = 0 // Reset retry count when starting new shimmer
|
|
109
|
+
startShimmerInternal()
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private func startShimmerInternal() {
|
|
113
|
+
guard isActive else { return }
|
|
114
|
+
|
|
48
115
|
stopShimmer()
|
|
49
|
-
|
|
116
|
+
|
|
50
117
|
guard !view.bounds.isEmpty else {
|
|
118
|
+
// Check if we have exceeded max retry count
|
|
119
|
+
guard retryCount < maxRetryCount else {
|
|
120
|
+
print("⚠️ Skeleton shimmer: Max retry count reached. View bounds are still empty.")
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
retryCount += 1
|
|
51
125
|
// Retry after a short delay if bounds are not ready
|
|
52
|
-
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
|
53
|
-
self.
|
|
126
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
|
|
127
|
+
guard let self = self, self.isActive else { return }
|
|
128
|
+
self.startShimmerInternal()
|
|
54
129
|
}
|
|
55
130
|
return
|
|
56
131
|
}
|
|
57
|
-
|
|
132
|
+
|
|
58
133
|
let colors: [UIColor] = customGradientColors ?? DEFAULT_GRADIENT_COLORS
|
|
59
134
|
let backgroundColor = colors[0].cgColor
|
|
60
135
|
let highlightColor = colors[1].cgColor
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
136
|
+
|
|
137
|
+
// Create skeleton layer for masking
|
|
138
|
+
let newSkeletonLayer = CALayer()
|
|
139
|
+
newSkeletonLayer.backgroundColor = backgroundColor
|
|
140
|
+
newSkeletonLayer.name = "SkeletonLayer"
|
|
141
|
+
newSkeletonLayer.anchorPoint = .zero
|
|
142
|
+
newSkeletonLayer.frame = view.bounds
|
|
143
|
+
|
|
144
|
+
// Create gradient layer for animation
|
|
68
145
|
let gradientLayer = CAGradientLayer()
|
|
69
146
|
gradientLayer.colors = [backgroundColor, highlightColor, backgroundColor]
|
|
70
147
|
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
|
|
71
148
|
gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
|
|
72
149
|
gradientLayer.frame = view.bounds
|
|
73
150
|
gradientLayer.name = "ShimmerLayer"
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
view.layer.
|
|
151
|
+
|
|
152
|
+
// Set mask and add gradient layer (don't add skeleton layer as sublayer)
|
|
153
|
+
view.layer.mask = newSkeletonLayer
|
|
77
154
|
view.layer.addSublayer(gradientLayer)
|
|
78
155
|
view.clipsToBounds = true
|
|
79
|
-
|
|
156
|
+
view.backgroundColor = UIColor(cgColor: backgroundColor)
|
|
157
|
+
|
|
158
|
+
// Store references
|
|
159
|
+
skeletonLayer = newSkeletonLayer
|
|
80
160
|
shimmerLayer = gradientLayer
|
|
81
|
-
|
|
161
|
+
|
|
162
|
+
// Create animation
|
|
82
163
|
let width = view.bounds.width
|
|
83
164
|
let animation = CABasicAnimation(keyPath: "transform.translation.x")
|
|
84
165
|
animation.duration = shimmerSpeed ?? 3
|
|
@@ -87,32 +168,57 @@ class HybridSkeleton : HybridSkeletonSpec {
|
|
|
87
168
|
animation.repeatCount = .infinity
|
|
88
169
|
animation.autoreverses = false
|
|
89
170
|
animation.fillMode = CAMediaTimingFillMode.forwards
|
|
90
|
-
|
|
171
|
+
animation.isRemovedOnCompletion = false // Keep animation when completed
|
|
172
|
+
|
|
173
|
+
// Use weak self pattern for potential future animation delegates/completion handlers
|
|
91
174
|
gradientLayer.add(animation, forKey: "shimmerAnimation")
|
|
92
175
|
}
|
|
93
|
-
|
|
176
|
+
|
|
94
177
|
func stopShimmer() {
|
|
95
|
-
|
|
178
|
+
// Remove animation from shimmer layer
|
|
179
|
+
shimmerLayer?.removeAllAnimations() // Remove all animations, more comprehensive
|
|
96
180
|
shimmerLayer?.removeFromSuperlayer()
|
|
181
|
+
|
|
182
|
+
// Clear mask reference before setting to nil
|
|
183
|
+
if view.layer.mask === skeletonLayer {
|
|
184
|
+
view.layer.mask = nil
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Clean up all sublayers that might be shimmer layers
|
|
188
|
+
view.layer.sublayers?.forEach { layer in
|
|
189
|
+
if layer.name == "ShimmerLayer" {
|
|
190
|
+
layer.removeAllAnimations()
|
|
191
|
+
layer.removeFromSuperlayer()
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Nil out references
|
|
97
196
|
shimmerLayer = nil
|
|
197
|
+
skeletonLayer = nil
|
|
98
198
|
}
|
|
99
|
-
|
|
199
|
+
|
|
100
200
|
func afterUpdate() {
|
|
101
|
-
|
|
201
|
+
guard isActive else { return }
|
|
202
|
+
DispatchQueue.main.async { [weak self] in
|
|
203
|
+
guard let self = self, self.isActive else { return }
|
|
204
|
+
self.restartShimmer()
|
|
205
|
+
}
|
|
102
206
|
}
|
|
103
|
-
|
|
207
|
+
|
|
104
208
|
func restartShimmer() {
|
|
209
|
+
guard isActive else { return }
|
|
105
210
|
stopShimmer()
|
|
106
|
-
|
|
211
|
+
retryCount = 0 // Reset retry count on restart
|
|
212
|
+
startShimmerInternal()
|
|
107
213
|
}
|
|
108
|
-
|
|
214
|
+
|
|
109
215
|
func hexStringToUIColor(hexColor: String) -> UIColor {
|
|
110
216
|
var hexSanitized = hexColor.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
111
|
-
|
|
217
|
+
|
|
112
218
|
if hexSanitized.hasPrefix("#") {
|
|
113
219
|
hexSanitized.remove(at: hexSanitized.startIndex)
|
|
114
220
|
}
|
|
115
|
-
|
|
221
|
+
|
|
116
222
|
var color: UInt32 = 0
|
|
117
223
|
let stringScanner = Scanner(string: hexSanitized)
|
|
118
224
|
stringScanner.scanHexInt32(&color)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// JHybridSkeletonSpec.cpp
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
#include "JHybridSkeletonSpec.hpp"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// JHybridSkeletonStateUpdater.cpp
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
#include "JHybridSkeletonStateUpdater.hpp"
|
package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/skeleton/HybridSkeletonSpec.kt
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// HybridSkeletonSpec.kt
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
package com.margelo.nitro.skeleton
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// skeletonOnLoad.kt
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
package com.margelo.nitro.skeleton
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// HybridSkeletonManager.kt
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
package com.margelo.nitro.skeleton.views
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// HybridSkeletonStateUpdater.kt
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
package com.margelo.nitro.skeleton.views
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# skeleton+autolinking.cmake
|
|
3
3
|
# This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
# https://github.com/mrousavy/nitro
|
|
5
|
-
# Copyright ©
|
|
5
|
+
# Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
#
|
|
7
7
|
|
|
8
8
|
# This is a CMake file that adds all files generated by Nitrogen
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// skeleton+autolinking.gradle
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
/// This is a Gradle file that adds all files generated by Nitrogen
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// skeletonOnLoad.cpp
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
#ifndef BUILDING_SKELETON_WITH_GENERATED_CMAKE_PROJECT
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# Skeleton+autolinking.rb
|
|
3
3
|
# This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
# https://github.com/mrousavy/nitro
|
|
5
|
-
# Copyright ©
|
|
5
|
+
# Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
#
|
|
7
7
|
|
|
8
8
|
# This is a Ruby script that adds all files generated by Nitrogen
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// Skeleton-Swift-Cxx-Bridge.cpp
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
#include "Skeleton-Swift-Cxx-Bridge.hpp"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// SkeletonAutolinking.mm
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
#import <Foundation/Foundation.h>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// SkeletonAutolinking.swift
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
public final class SkeletonAutolinking {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// HybridSkeletonSpecSwift.cpp
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
#include "HybridSkeletonSpecSwift.hpp"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// HybridSkeletonComponent.mm
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
#import "HybridSkeletonComponent.hpp"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// HybridSkeletonSpec.cpp
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
#include "HybridSkeletonSpec.hpp"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// HybridSkeletonComponent.cpp
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
#include "HybridSkeletonComponent.hpp"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// JHybridSkeletonSpec.cpp
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
#include "JHybridSkeletonSpec.hpp"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// JHybridSkeletonStateUpdater.cpp
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
#include "JHybridSkeletonStateUpdater.hpp"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// HybridSkeletonSpec.kt
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
package com.margelo.nitro.skeleton
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// skeletonOnLoad.kt
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
package com.margelo.nitro.skeleton
|
package/nitrogen/generated/android/kotlin/com/margelo/nitro/skeleton/views/HybridSkeletonManager.kt
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// HybridSkeletonManager.kt
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
package com.margelo.nitro.skeleton.views
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// HybridSkeletonStateUpdater.kt
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
package com.margelo.nitro.skeleton.views
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# skeleton+autolinking.cmake
|
|
3
3
|
# This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
# https://github.com/mrousavy/nitro
|
|
5
|
-
# Copyright ©
|
|
5
|
+
# Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
#
|
|
7
7
|
|
|
8
8
|
# This is a CMake file that adds all files generated by Nitrogen
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// skeleton+autolinking.gradle
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
/// This is a Gradle file that adds all files generated by Nitrogen
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// skeletonOnLoad.cpp
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
#ifndef BUILDING_SKELETON_WITH_GENERATED_CMAKE_PROJECT
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# Skeleton+autolinking.rb
|
|
3
3
|
# This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
# https://github.com/mrousavy/nitro
|
|
5
|
-
# Copyright ©
|
|
5
|
+
# Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
#
|
|
7
7
|
|
|
8
8
|
# This is a Ruby script that adds all files generated by Nitrogen
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// Skeleton-Swift-Cxx-Bridge.cpp
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
#include "Skeleton-Swift-Cxx-Bridge.hpp"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// SkeletonAutolinking.mm
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
#import <Foundation/Foundation.h>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// SkeletonAutolinking.swift
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
public final class SkeletonAutolinking {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// HybridSkeletonSpecSwift.cpp
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
#include "HybridSkeletonSpecSwift.hpp"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// HybridSkeletonComponent.mm
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
#import "HybridSkeletonComponent.hpp"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// HybridSkeletonSpec.cpp
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
#include "HybridSkeletonSpec.hpp"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// HybridSkeletonComponent.cpp
|
|
3
3
|
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
4
|
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright ©
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
#include "HybridSkeletonComponent.hpp"
|