@onekeyfe/react-native-image 3.0.100 → 3.0.102
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/README.md
CHANGED
|
@@ -56,6 +56,12 @@ large lists conservative, and `autoplay={true}` on other native platforms. Pass
|
|
|
56
56
|
`autoplay` explicitly whenever a screen needs the same behavior on both
|
|
57
57
|
platforms.
|
|
58
58
|
|
|
59
|
+
Animated-image canvas limits are intentionally platform-specific. Android caps
|
|
60
|
+
the unavoidable decoded ARGB canvas at 4,194,304 pixels (16 MiB), while iOS
|
|
61
|
+
allows metadata dimensions up to 16,000,000 pixels and separately caps its
|
|
62
|
+
decoded animation frame buffer at 16 MiB. These limits reflect the native
|
|
63
|
+
decoders' different allocation behavior.
|
|
64
|
+
|
|
59
65
|
`recyclingKey` is available for recycled list cells. Changing it clears stale
|
|
60
66
|
content before the next source is displayed.
|
|
61
67
|
|
|
@@ -38,6 +38,7 @@ private class OneKeyImageHostView(context: ThemedReactContext) : ImageView(conte
|
|
|
38
38
|
syncPlayback()
|
|
39
39
|
}
|
|
40
40
|
var onReadyForRequest: (() -> Unit)? = null
|
|
41
|
+
var onAttachmentChanged: ((Boolean) -> Unit)? = null
|
|
41
42
|
|
|
42
43
|
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
|
43
44
|
super.onSizeChanged(w, h, oldw, oldh)
|
|
@@ -58,11 +59,13 @@ private class OneKeyImageHostView(context: ThemedReactContext) : ImageView(conte
|
|
|
58
59
|
override fun onAttachedToWindow() {
|
|
59
60
|
super.onAttachedToWindow()
|
|
60
61
|
syncPlayback()
|
|
62
|
+
onAttachmentChanged?.invoke(true)
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
override fun onDetachedFromWindow() {
|
|
64
66
|
super.onDetachedFromWindow()
|
|
65
67
|
syncPlayback()
|
|
68
|
+
onAttachmentChanged?.invoke(false)
|
|
66
69
|
}
|
|
67
70
|
|
|
68
71
|
override fun onVisibilityAggregated(isVisible: Boolean) {
|
|
@@ -120,6 +123,11 @@ class HybridOneKeyImage(private val context: ThemedReactContext) :
|
|
|
120
123
|
private enum class DisplayState { LOADING, IMAGE, ERROR, FALLBACK }
|
|
121
124
|
|
|
122
125
|
private val hostView = OneKeyImageHostView(context)
|
|
126
|
+
// Keep requests independent of ScreenStack Fragment teardown while React
|
|
127
|
+
// retains the view.
|
|
128
|
+
private val requestManager by lazy(LazyThreadSafetyMode.NONE) {
|
|
129
|
+
Glide.with(context.applicationContext)
|
|
130
|
+
}
|
|
123
131
|
private var loadRunnable: Runnable? = null
|
|
124
132
|
private var currentTarget: CustomViewTarget<OneKeyImageHostView, Drawable>? = null
|
|
125
133
|
private var generation = 0L
|
|
@@ -129,6 +137,7 @@ class HybridOneKeyImage(private val context: ThemedReactContext) :
|
|
|
129
137
|
private var requestActive = false
|
|
130
138
|
private var displayState = DisplayState.LOADING
|
|
131
139
|
private var displayRunnable: Runnable? = null
|
|
140
|
+
private var pendingDisplayGeneration: Long? = null
|
|
132
141
|
private var fallbackRunnable: Runnable? = null
|
|
133
142
|
|
|
134
143
|
override val view: View = hostView
|
|
@@ -202,6 +211,14 @@ class HybridOneKeyImage(private val context: ThemedReactContext) :
|
|
|
202
211
|
OneKeyImageGlideRegistry.ensureRegistered(context)
|
|
203
212
|
hostView.updateSkeletonStyle()
|
|
204
213
|
hostView.onReadyForRequest = { scheduleLoad() }
|
|
214
|
+
hostView.onAttachmentChanged = { attached ->
|
|
215
|
+
if (attached) {
|
|
216
|
+
schedulePendingDisplayIfNeeded()
|
|
217
|
+
} else {
|
|
218
|
+
displayRunnable?.let(hostView::removeCallbacks)
|
|
219
|
+
displayRunnable = null
|
|
220
|
+
}
|
|
221
|
+
}
|
|
205
222
|
applyContentFit()
|
|
206
223
|
applyVariant()
|
|
207
224
|
}
|
|
@@ -229,6 +246,7 @@ class HybridOneKeyImage(private val context: ThemedReactContext) :
|
|
|
229
246
|
resetForReuse()
|
|
230
247
|
disposed = true
|
|
231
248
|
hostView.onReadyForRequest = null
|
|
249
|
+
hostView.onAttachmentChanged = null
|
|
232
250
|
super.onDropView()
|
|
233
251
|
}
|
|
234
252
|
|
|
@@ -236,6 +254,7 @@ class HybridOneKeyImage(private val context: ThemedReactContext) :
|
|
|
236
254
|
disposed = true
|
|
237
255
|
cancelCurrent(invalidateGeneration = true)
|
|
238
256
|
hostView.onReadyForRequest = null
|
|
257
|
+
hostView.onAttachmentChanged = null
|
|
239
258
|
super.dispose()
|
|
240
259
|
}
|
|
241
260
|
|
|
@@ -432,7 +451,7 @@ class HybridOneKeyImage(private val context: ThemedReactContext) :
|
|
|
432
451
|
}
|
|
433
452
|
}
|
|
434
453
|
currentTarget = target
|
|
435
|
-
|
|
454
|
+
requestManager
|
|
436
455
|
.asDrawable()
|
|
437
456
|
.load(OneKeyImageModel.build(requestUrl, headersJson))
|
|
438
457
|
.apply(requestOptions(policy))
|
|
@@ -495,6 +514,7 @@ class HybridOneKeyImage(private val context: ThemedReactContext) :
|
|
|
495
514
|
loadRunnable = null
|
|
496
515
|
displayRunnable?.let(hostView::removeCallbacks)
|
|
497
516
|
displayRunnable = null
|
|
517
|
+
pendingDisplayGeneration = null
|
|
498
518
|
fallbackRunnable?.let(hostView::removeCallbacks)
|
|
499
519
|
fallbackRunnable = null
|
|
500
520
|
clearCurrentTarget()
|
|
@@ -508,18 +528,30 @@ class HybridOneKeyImage(private val context: ThemedReactContext) :
|
|
|
508
528
|
// Clear the field first so onResourceCleared from our own cancellation
|
|
509
529
|
// cannot erase state belonging to the next generation/request.
|
|
510
530
|
currentTarget = null
|
|
511
|
-
|
|
531
|
+
requestManager.clear(target)
|
|
512
532
|
}
|
|
513
533
|
|
|
514
534
|
private fun scheduleOnDisplay(requestGeneration: Long) {
|
|
535
|
+
pendingDisplayGeneration = requestGeneration
|
|
536
|
+
schedulePendingDisplayIfNeeded()
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
private fun schedulePendingDisplayIfNeeded() {
|
|
540
|
+
val requestGeneration = pendingDisplayGeneration ?: return
|
|
515
541
|
displayRunnable?.let(hostView::removeCallbacks)
|
|
542
|
+
displayRunnable = null
|
|
543
|
+
if (!hostView.isAttachedToWindow) return
|
|
516
544
|
val runnable = Runnable {
|
|
517
545
|
displayRunnable = null
|
|
518
546
|
if (
|
|
547
|
+
pendingDisplayGeneration == requestGeneration &&
|
|
519
548
|
requestGeneration == generation &&
|
|
520
549
|
!disposed &&
|
|
521
|
-
displayState == DisplayState.IMAGE
|
|
550
|
+
displayState == DisplayState.IMAGE &&
|
|
551
|
+
hostView.drawable != null &&
|
|
552
|
+
hostView.isAttachedToWindow
|
|
522
553
|
) {
|
|
554
|
+
pendingDisplayGeneration = null
|
|
523
555
|
onDisplay?.invoke()
|
|
524
556
|
}
|
|
525
557
|
}
|
package/lib/module/index.js
CHANGED
|
@@ -21,7 +21,7 @@ function unwrap(value) {
|
|
|
21
21
|
function normalizeSource(source) {
|
|
22
22
|
if (source == null) return undefined;
|
|
23
23
|
const resolved = Image.resolveAssetSource(source);
|
|
24
|
-
if (resolved?.uri) {
|
|
24
|
+
if (resolved?.uri?.trim()) {
|
|
25
25
|
const original = typeof source === 'object' && !Array.isArray(source) ? source : undefined;
|
|
26
26
|
return {
|
|
27
27
|
uri: resolved.uri,
|
|
@@ -203,7 +203,10 @@ export function OneKeyImage({
|
|
|
203
203
|
}
|
|
204
204
|
export const OneKeyImageCache = {
|
|
205
205
|
preload(sources) {
|
|
206
|
-
|
|
206
|
+
const hasInvalidSource = sources.some(source => !source.uri?.trim());
|
|
207
|
+
const validSources = sources.filter(source => Boolean(source.uri?.trim()));
|
|
208
|
+
if (validSources.length === 0) return Promise.resolve(false);
|
|
209
|
+
return nativeCache.preload(validSources.map(source => ({
|
|
207
210
|
uri: source.uri,
|
|
208
211
|
headersJson: source.headers ? JSON.stringify(source.headers) : undefined,
|
|
209
212
|
cachePolicy: source.cachePolicy ?? OneKeyImageCachePolicy.MEMORY_DISK,
|
|
@@ -212,7 +215,7 @@ export const OneKeyImageCache = {
|
|
|
212
215
|
pixelRatio: source.pixelRatio,
|
|
213
216
|
overscan: source.overscan,
|
|
214
217
|
optimizeTos: source.optimizeTos
|
|
215
|
-
})));
|
|
218
|
+
}))).then(success => success && !hasInvalidSource);
|
|
216
219
|
},
|
|
217
220
|
clearMemory: () => nativeCache.clearMemory(),
|
|
218
221
|
clearDisk: () => nativeCache.clearDisk(),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/react-native-image",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.102",
|
|
4
4
|
"description": "High-performance native image view for OneKey",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"typescript": "^5.9.2"
|
|
82
82
|
},
|
|
83
83
|
"peerDependencies": {
|
|
84
|
-
"@onekeyfe/react-native-skeleton": "3.0.
|
|
84
|
+
"@onekeyfe/react-native-skeleton": "3.0.102",
|
|
85
85
|
"react": "*",
|
|
86
86
|
"react-native": "*",
|
|
87
87
|
"react-native-nitro-modules": "0.37.0"
|
package/src/index.tsx
CHANGED
|
@@ -126,7 +126,7 @@ function normalizeSource(
|
|
|
126
126
|
): OneKeyImageSource | undefined {
|
|
127
127
|
if (source == null) return undefined;
|
|
128
128
|
const resolved = Image.resolveAssetSource(source as ImageSourcePropType);
|
|
129
|
-
if (resolved?.uri) {
|
|
129
|
+
if (resolved?.uri?.trim()) {
|
|
130
130
|
const original =
|
|
131
131
|
typeof source === 'object' && !Array.isArray(source)
|
|
132
132
|
? (source as OneKeyImageSource)
|
|
@@ -364,11 +364,17 @@ export function OneKeyImage({
|
|
|
364
364
|
|
|
365
365
|
export const OneKeyImageCache = {
|
|
366
366
|
preload(sources: OneKeyImagePreloadInput[]) {
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
.
|
|
371
|
-
|
|
367
|
+
const hasInvalidSource = sources.some((source) => !source.uri?.trim());
|
|
368
|
+
const validSources = sources.filter(
|
|
369
|
+
(source): source is OneKeyImagePreloadInput & { uri: string } =>
|
|
370
|
+
Boolean(source.uri?.trim())
|
|
371
|
+
);
|
|
372
|
+
if (validSources.length === 0) return Promise.resolve(false);
|
|
373
|
+
|
|
374
|
+
return nativeCache
|
|
375
|
+
.preload(
|
|
376
|
+
validSources.map((source) => ({
|
|
377
|
+
uri: source.uri,
|
|
372
378
|
headersJson: source.headers
|
|
373
379
|
? JSON.stringify(source.headers)
|
|
374
380
|
: undefined,
|
|
@@ -379,7 +385,8 @@ export const OneKeyImageCache = {
|
|
|
379
385
|
overscan: source.overscan,
|
|
380
386
|
optimizeTos: source.optimizeTos,
|
|
381
387
|
}))
|
|
382
|
-
|
|
388
|
+
)
|
|
389
|
+
.then((success) => success && !hasInvalidSource);
|
|
383
390
|
},
|
|
384
391
|
clearMemory: () => nativeCache.clearMemory(),
|
|
385
392
|
clearDisk: () => nativeCache.clearDisk(),
|