@onekeyfe/react-native-image 3.0.157 → 3.0.158
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/ios/OneKeyImage.swift
CHANGED
|
@@ -115,6 +115,9 @@ final class HybridOneKeyImage: HybridOneKeyImageSpec, RecyclableView {
|
|
|
115
115
|
private var requestActive = false
|
|
116
116
|
private var isResetting = false
|
|
117
117
|
private var displayState = DisplayState.loading
|
|
118
|
+
/// `.loading` with the previous image kept on screen as the placeholder
|
|
119
|
+
/// (see `showLoading(preservedImage:)`).
|
|
120
|
+
private var isPreservingDisplayedImage = false
|
|
118
121
|
private var requestStartedAt: CFTimeInterval?
|
|
119
122
|
|
|
120
123
|
var view: UIView { hostView }
|
|
@@ -337,8 +340,11 @@ final class HybridOneKeyImage: HybridOneKeyImageSpec, RecyclableView {
|
|
|
337
340
|
}
|
|
338
341
|
|
|
339
342
|
let hasCustomIdentity = OneKeyImageRequestContext.headers(from: sourceHeadersJson) != nil
|
|
340
|
-
let displaySize =
|
|
341
|
-
|
|
343
|
+
let displaySize = OneKeyImageDecodeSizing.tosDisplaySize(
|
|
344
|
+
bounds: hostView.bounds.size,
|
|
345
|
+
resizeWidth: resizeWidth,
|
|
346
|
+
resizeHeight: resizeHeight
|
|
347
|
+
) ?? 0
|
|
342
348
|
let requestURL =
|
|
343
349
|
(optimizeTos ?? true)
|
|
344
350
|
? OneKeyTosURL.optimized(
|
|
@@ -439,6 +445,7 @@ final class HybridOneKeyImage: HybridOneKeyImageSpec, RecyclableView {
|
|
|
439
445
|
guard self.claimTerminal(generation) else { return }
|
|
440
446
|
self.requestActive = false
|
|
441
447
|
self.displayState = .image
|
|
448
|
+
self.isPreservingDisplayedImage = false
|
|
442
449
|
self.skeletonIndicator.stopAnimatingIndicator()
|
|
443
450
|
self.fallbackLayer.isHidden = true
|
|
444
451
|
self.hostView.backgroundColor = .clear
|
|
@@ -547,6 +554,7 @@ final class HybridOneKeyImage: HybridOneKeyImageSpec, RecyclableView {
|
|
|
547
554
|
optimizeTos = true
|
|
548
555
|
round = false
|
|
549
556
|
resizeWidth = nil
|
|
557
|
+
resizeHeight = nil
|
|
550
558
|
overscan = 1.1
|
|
551
559
|
loadingStrategy = .static
|
|
552
560
|
placeholderColor = nil
|
|
@@ -577,6 +585,9 @@ final class HybridOneKeyImage: HybridOneKeyImageSpec, RecyclableView {
|
|
|
577
585
|
guard Self.isCurrentRequestGeneration(generation, current: requestGeneration) else {
|
|
578
586
|
return
|
|
579
587
|
}
|
|
588
|
+
// Also the placeholder write path (SDWebImage hands the preserved image
|
|
589
|
+
// back through setImageBlock when the load starts), so the preservation
|
|
590
|
+
// flag is NOT touched here; it ends with the terminal callbacks.
|
|
580
591
|
hostView.image = image
|
|
581
592
|
}
|
|
582
593
|
|
|
@@ -592,11 +603,19 @@ final class HybridOneKeyImage: HybridOneKeyImageSpec, RecyclableView {
|
|
|
592
603
|
if let preservedImage {
|
|
593
604
|
// Same identity, different thumbnail key: the image already on screen
|
|
594
605
|
// stands in for the placeholder, so no blank frame and no indicator.
|
|
606
|
+
// The indicator is unmounted, not just stopped: SDWebImage restarts a
|
|
607
|
+
// mounted `sd_imageIndicator` when the load begins, and `applyVariant`
|
|
608
|
+
// must not reinstall it while this state lasts.
|
|
609
|
+
isPreservingDisplayedImage = true
|
|
595
610
|
hostView.image = preservedImage
|
|
596
611
|
skeletonIndicator.stopAnimatingIndicator()
|
|
612
|
+
if hostView.sd_imageIndicator != nil {
|
|
613
|
+
hostView.sd_imageIndicator = nil
|
|
614
|
+
}
|
|
597
615
|
hostView.backgroundColor = .clear
|
|
598
616
|
return
|
|
599
617
|
}
|
|
618
|
+
isPreservingDisplayedImage = false
|
|
600
619
|
hostView.image = nil
|
|
601
620
|
applyLoadingAppearance(letLibraryStartIndicator: letLibraryStartIndicator)
|
|
602
621
|
}
|
|
@@ -623,8 +642,11 @@ final class HybridOneKeyImage: HybridOneKeyImageSpec, RecyclableView {
|
|
|
623
642
|
let rawScreenScale: CGFloat = hostView.window?.screen.scale ?? UIScreen.main.scale
|
|
624
643
|
let screenScale = min(max(rawScreenScale, 1), 3)
|
|
625
644
|
let hasCustomIdentity = OneKeyImageRequestContext.headers(from: sourceHeadersJson) != nil
|
|
626
|
-
let displaySize =
|
|
627
|
-
|
|
645
|
+
let displaySize = OneKeyImageDecodeSizing.tosDisplaySize(
|
|
646
|
+
bounds: hostView.bounds.size,
|
|
647
|
+
resizeWidth: resizeWidth,
|
|
648
|
+
resizeHeight: resizeHeight
|
|
649
|
+
) ?? 0
|
|
628
650
|
let requestURL =
|
|
629
651
|
(optimizeTos ?? true)
|
|
630
652
|
? OneKeyTosURL.optimized(
|
|
@@ -679,6 +701,7 @@ final class HybridOneKeyImage: HybridOneKeyImageSpec, RecyclableView {
|
|
|
679
701
|
let generation = requestGeneration
|
|
680
702
|
if requestIsActive, !claimTerminal(generation) { return true }
|
|
681
703
|
displayState = .image
|
|
704
|
+
isPreservingDisplayedImage = false
|
|
682
705
|
requestActive = false
|
|
683
706
|
skeletonIndicator.stopAnimatingIndicator()
|
|
684
707
|
fallbackLayer.isHidden = true
|
|
@@ -716,6 +739,7 @@ final class HybridOneKeyImage: HybridOneKeyImageSpec, RecyclableView {
|
|
|
716
739
|
private func showTerminalState(_ state: DisplayState) {
|
|
717
740
|
displayState = state
|
|
718
741
|
requestActive = false
|
|
742
|
+
isPreservingDisplayedImage = false
|
|
719
743
|
skeletonIndicator.stopAnimatingIndicator()
|
|
720
744
|
resetImageTransition()
|
|
721
745
|
hostView.image = nil
|
|
@@ -733,6 +757,9 @@ final class HybridOneKeyImage: HybridOneKeyImageSpec, RecyclableView {
|
|
|
733
757
|
case .image:
|
|
734
758
|
break
|
|
735
759
|
case .loading:
|
|
760
|
+
// A preserved image is the placeholder; re-applying the loading look
|
|
761
|
+
// would cover it with the skeleton / placeholder color again.
|
|
762
|
+
if isPreservingDisplayedImage { break }
|
|
736
763
|
applyLoadingAppearance(letLibraryStartIndicator: false)
|
|
737
764
|
case .error, .fallback:
|
|
738
765
|
let hidesTerminalState = loadingStrategy == .none
|
|
@@ -610,6 +610,23 @@ enum OneKeyImageDecodeSizing {
|
|
|
610
610
|
}
|
|
611
611
|
}
|
|
612
612
|
|
|
613
|
+
/// The logical display size the TOS rendition is picked for. A preload picks
|
|
614
|
+
/// it from the long edge of its `resizeWidth`/`resizeHeight` hint, so a view
|
|
615
|
+
/// carrying the same hint must do the same (before AND after layout) or its
|
|
616
|
+
/// request URL, and with it the cache key, diverges from what the preload
|
|
617
|
+
/// stored. Without a hint the laid-out bounds decide; nil before layout.
|
|
618
|
+
static func tosDisplaySize(
|
|
619
|
+
bounds: CGSize,
|
|
620
|
+
resizeWidth: Double?,
|
|
621
|
+
resizeHeight: Double?
|
|
622
|
+
) -> CGFloat? {
|
|
623
|
+
if let hint = logicalViewSize(width: resizeWidth, height: resizeHeight) {
|
|
624
|
+
return max(hint.width, hint.height)
|
|
625
|
+
}
|
|
626
|
+
let edge = max(bounds.width, bounds.height)
|
|
627
|
+
return edge.isFinite && edge > 0 ? edge : nil
|
|
628
|
+
}
|
|
629
|
+
|
|
613
630
|
/// Decode-thumbnail sizes worth probing the memory cache with, most specific
|
|
614
631
|
/// first. The thumbnail size is part of the SDWebImage cache key, so a probe
|
|
615
632
|
/// only hits when it reproduces the key some earlier load stored under.
|
|
@@ -629,6 +629,55 @@ final class OneKeyImageInfrastructureTests: XCTestCase {
|
|
|
629
629
|
)
|
|
630
630
|
}
|
|
631
631
|
|
|
632
|
+
func testRecycledViewForgetsBothResizeHints() throws {
|
|
633
|
+
let image = HybridOneKeyImage()
|
|
634
|
+
image.sourceUri = "https://example.com/hinted.png"
|
|
635
|
+
image.resizeWidth = 48
|
|
636
|
+
image.resizeHeight = 64
|
|
637
|
+
image.prepareForRecycle()
|
|
638
|
+
XCTAssertNil(image.resizeWidth)
|
|
639
|
+
XCTAssertNil(image.resizeHeight)
|
|
640
|
+
XCTAssertNil(image.sourceUri)
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
func testViewAndPreloadPickTheSameTosRenditionForOneHint() throws {
|
|
644
|
+
// Preload: long edge of logicalViewSize(resizeWidth, resizeHeight).
|
|
645
|
+
// View: the same, before and after layout, so the request URL (and with it
|
|
646
|
+
// the cache key) is identical on both sides.
|
|
647
|
+
let raw = try XCTUnwrap(URL(string: "https://common.onekey-asset.com/token.png"))
|
|
648
|
+
let hint = try XCTUnwrap(OneKeyImageDecodeSizing.logicalViewSize(width: 48, height: 64))
|
|
649
|
+
let preloadDisplaySize = max(hint.width, hint.height)
|
|
650
|
+
for bounds in [CGSize.zero, CGSize(width: 48, height: 64), CGSize(width: 30, height: 30)] {
|
|
651
|
+
let viewDisplaySize = try XCTUnwrap(
|
|
652
|
+
OneKeyImageDecodeSizing.tosDisplaySize(bounds: bounds, resizeWidth: 48, resizeHeight: 64)
|
|
653
|
+
)
|
|
654
|
+
XCTAssertEqual(viewDisplaySize, preloadDisplaySize)
|
|
655
|
+
XCTAssertEqual(
|
|
656
|
+
OneKeyTosURL.optimized(
|
|
657
|
+
rawURL: raw, displaySize: viewDisplaySize, scale: 3, overscan: 1.1, hasCustomIdentity: false
|
|
658
|
+
),
|
|
659
|
+
OneKeyTosURL.optimized(
|
|
660
|
+
rawURL: raw, displaySize: preloadDisplaySize, scale: 3, overscan: 1.1, hasCustomIdentity: false
|
|
661
|
+
)
|
|
662
|
+
)
|
|
663
|
+
}
|
|
664
|
+
// Width-only hint keeps the historical behaviour (the width itself).
|
|
665
|
+
XCTAssertEqual(
|
|
666
|
+
OneKeyImageDecodeSizing.tosDisplaySize(bounds: .zero, resizeWidth: 40, resizeHeight: nil),
|
|
667
|
+
40
|
|
668
|
+
)
|
|
669
|
+
// No hint: the laid-out bounds decide; nothing before layout.
|
|
670
|
+
XCTAssertEqual(
|
|
671
|
+
OneKeyImageDecodeSizing.tosDisplaySize(
|
|
672
|
+
bounds: CGSize(width: 40, height: 64), resizeWidth: nil, resizeHeight: nil
|
|
673
|
+
),
|
|
674
|
+
64
|
|
675
|
+
)
|
|
676
|
+
XCTAssertNil(
|
|
677
|
+
OneKeyImageDecodeSizing.tosDisplaySize(bounds: .zero, resizeWidth: nil, resizeHeight: nil)
|
|
678
|
+
)
|
|
679
|
+
}
|
|
680
|
+
|
|
632
681
|
func testSupersededRequestNeverPaintsRecycledView() throws {
|
|
633
682
|
let image = HybridOneKeyImage()
|
|
634
683
|
let imageView = try XCTUnwrap(image.view as? SDAnimatedImageView)
|
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.158",
|
|
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.158",
|
|
85
85
|
"react": "*",
|
|
86
86
|
"react-native": "*",
|
|
87
87
|
"react-native-nitro-modules": "0.37.0"
|