Skip to content

Commit

Permalink
Merge pull request #1961 from onevcat/feature/progressive-update-call…
Browse files Browse the repository at this point in the history
…back

Feature/progressive update callback
  • Loading branch information
onevcat authored Jul 4, 2022
2 parents ccc1fac + acf7927 commit d237a93
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 81 deletions.
12 changes: 2 additions & 10 deletions Sources/Extensions/CPListItem+Kingfisher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -155,20 +155,12 @@ extension KingfisherWrapper where Base: CPListItem {
options.onDataReceived = (options.onDataReceived ?? []) + [ImageLoadingProgressSideEffect(block)]
}

if let provider = ImageProgressiveProvider(options, refresh: { image in
self.base.setImage(image)
}) {
options.onDataReceived = (options.onDataReceived ?? []) + [provider]
}

options.onDataReceived?.forEach {
$0.onShouldApply = { issuedIdentifier == self.taskIdentifier }
}

let task = KingfisherManager.shared.retrieveImage(
with: source,
options: options,
downloadTaskUpdated: { mutatingSelf.imageTask = $0 },
progressiveImageSetter: { self.base.setImage($0) },
referenceTaskIdentifierChecker: { issuedIdentifier == self.taskIdentifier },
completionHandler: { result in
CallbackQueue.mainCurrentOrAsync.execute {
guard issuedIdentifier == self.taskIdentifier else {
Expand Down
12 changes: 2 additions & 10 deletions Sources/Extensions/ImageView+Kingfisher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -312,20 +312,12 @@ extension KingfisherWrapper where Base: KFCrossPlatformImageView {
options.onDataReceived = (options.onDataReceived ?? []) + [ImageLoadingProgressSideEffect(block)]
}

if let provider = ImageProgressiveProvider(options, refresh: { image in
self.base.image = image
}) {
options.onDataReceived = (options.onDataReceived ?? []) + [provider]
}

options.onDataReceived?.forEach {
$0.onShouldApply = { issuedIdentifier == self.taskIdentifier }
}

let task = KingfisherManager.shared.retrieveImage(
with: source,
options: options,
downloadTaskUpdated: { mutatingSelf.imageTask = $0 },
progressiveImageSetter: { self.base.image = $0 },
referenceTaskIdentifierChecker: { issuedIdentifier == self.taskIdentifier },
completionHandler: { result in
CallbackQueue.mainCurrentOrAsync.execute {
maybeIndicator?.stopAnimatingView()
Expand Down
12 changes: 2 additions & 10 deletions Sources/Extensions/NSButton+Kingfisher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,20 +125,12 @@ extension KingfisherWrapper where Base: NSButton {
options.onDataReceived = (options.onDataReceived ?? []) + [ImageLoadingProgressSideEffect(block)]
}

if let provider = ImageProgressiveProvider(options, refresh: { image in
self.base.image = image
}) {
options.onDataReceived = (options.onDataReceived ?? []) + [provider]
}

options.onDataReceived?.forEach {
$0.onShouldApply = { issuedIdentifier == self.taskIdentifier }
}

let task = KingfisherManager.shared.retrieveImage(
with: source,
options: options,
downloadTaskUpdated: { mutatingSelf.imageTask = $0 },
progressiveImageSetter: { self.base.image = $0 },
referenceTaskIdentifierChecker: { issuedIdentifier == self.taskIdentifier },
completionHandler: { result in
CallbackQueue.mainCurrentOrAsync.execute {
guard issuedIdentifier == self.taskIdentifier else {
Expand Down
12 changes: 2 additions & 10 deletions Sources/Extensions/NSTextAttachment+Kingfisher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -190,19 +190,11 @@ extension KingfisherWrapper where Base: NSTextAttachment {
options.onDataReceived = (options.onDataReceived ?? []) + [ImageLoadingProgressSideEffect(block)]
}

if let provider = ImageProgressiveProvider(options, refresh: { image in
self.base.image = image
}) {
options.onDataReceived = (options.onDataReceived ?? []) + [provider]
}

options.onDataReceived?.forEach {
$0.onShouldApply = { issuedIdentifier == self.taskIdentifier }
}

let task = KingfisherManager.shared.retrieveImage(
with: source,
options: options,
progressiveImageSetter: { self.base.image = $0 },
referenceTaskIdentifierChecker: { issuedIdentifier == self.taskIdentifier },
completionHandler: { result in
CallbackQueue.mainCurrentOrAsync.execute {
guard issuedIdentifier == self.taskIdentifier else {
Expand Down
12 changes: 2 additions & 10 deletions Sources/Extensions/TVMonogramView+Kingfisher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,20 +97,12 @@ extension KingfisherWrapper where Base: TVMonogramView {
options.onDataReceived = (options.onDataReceived ?? []) + [ImageLoadingProgressSideEffect(block)]
}

if let provider = ImageProgressiveProvider(options, refresh: { image in
self.base.image = image
}) {
options.onDataReceived = (options.onDataReceived ?? []) + [provider]
}

options.onDataReceived?.forEach {
$0.onShouldApply = { issuedIdentifier == self.taskIdentifier }
}

let task = KingfisherManager.shared.retrieveImage(
with: source,
options: options,
downloadTaskUpdated: { mutatingSelf.imageTask = $0 },
progressiveImageSetter: { self.base.image = $0 },
referenceTaskIdentifierChecker: { issuedIdentifier == self.taskIdentifier },
completionHandler: { result in
CallbackQueue.mainCurrentOrAsync.execute {
guard issuedIdentifier == self.taskIdentifier else {
Expand Down
24 changes: 4 additions & 20 deletions Sources/Extensions/UIButton+Kingfisher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -133,20 +133,12 @@ extension KingfisherWrapper where Base: UIButton {
options.onDataReceived = (options.onDataReceived ?? []) + [ImageLoadingProgressSideEffect(block)]
}

if let provider = ImageProgressiveProvider(options, refresh: { image in
self.base.setImage(image, for: state)
}) {
options.onDataReceived = (options.onDataReceived ?? []) + [provider]
}

options.onDataReceived?.forEach {
$0.onShouldApply = { issuedIdentifier == self.taskIdentifier(for: state) }
}

let task = KingfisherManager.shared.retrieveImage(
with: source,
options: options,
downloadTaskUpdated: { mutatingSelf.imageTask = $0 },
progressiveImageSetter: { self.base.setImage($0, for: state) },
referenceTaskIdentifierChecker: { issuedIdentifier == self.taskIdentifier(for: state) },
completionHandler: { result in
CallbackQueue.mainCurrentOrAsync.execute {
guard issuedIdentifier == self.taskIdentifier(for: state) else {
Expand Down Expand Up @@ -294,20 +286,12 @@ extension KingfisherWrapper where Base: UIButton {
options.onDataReceived = (options.onDataReceived ?? []) + [ImageLoadingProgressSideEffect(block)]
}

if let provider = ImageProgressiveProvider(options, refresh: { image in
self.base.setBackgroundImage(image, for: state)
}) {
options.onDataReceived = (options.onDataReceived ?? []) + [provider]
}

options.onDataReceived?.forEach {
$0.onShouldApply = { issuedIdentifier == self.backgroundTaskIdentifier(for: state) }
}

let task = KingfisherManager.shared.retrieveImage(
with: source,
options: options,
downloadTaskUpdated: { mutatingSelf.backgroundImageTask = $0 },
progressiveImageSetter: { self.base.setBackgroundImage($0, for: state) },
referenceTaskIdentifierChecker: { issuedIdentifier == self.backgroundTaskIdentifier(for: state) },
completionHandler: { result in
CallbackQueue.mainCurrentOrAsync.execute {
guard issuedIdentifier == self.backgroundTaskIdentifier(for: state) else {
Expand Down
12 changes: 2 additions & 10 deletions Sources/Extensions/WKInterfaceImage+Kingfisher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -127,20 +127,12 @@ extension KingfisherWrapper where Base: WKInterfaceImage {
options.onDataReceived = (options.onDataReceived ?? []) + [ImageLoadingProgressSideEffect(block)]
}

if let provider = ImageProgressiveProvider(options, refresh: { image in
self.base.setImage(image)
}) {
options.onDataReceived = (options.onDataReceived ?? []) + [provider]
}

options.onDataReceived?.forEach {
$0.onShouldApply = { issuedIdentifier == self.taskIdentifier }
}

let task = KingfisherManager.shared.retrieveImage(
with: source,
options: options,
downloadTaskUpdated: { mutatingSelf.imageTask = $0 },
progressiveImageSetter: { self.base.setImage($0) },
referenceTaskIdentifierChecker: { issuedIdentifier == self.taskIdentifier },
completionHandler: { result in
CallbackQueue.mainCurrentOrAsync.execute {
guard issuedIdentifier == self.taskIdentifier else {
Expand Down
2 changes: 1 addition & 1 deletion Sources/General/KF.swift
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ extension KF.Builder {
/// progressive JPEG data and display it in a progressive way.
/// - Parameter progressive: The progressive settings which is used while loading.
/// - Returns: A `KF.Builder` with changes applied.
public func progressiveJPEG(_ progressive: ImageProgressive? = .default) -> Self {
public func progressiveJPEG(_ progressive: ImageProgressive? = .init()) -> Self {
options.progressiveJPEG = progressive
return self
}
Expand Down
26 changes: 26 additions & 0 deletions Sources/General/KingfisherManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -213,15 +213,41 @@ public class KingfisherManager {
with: source,
options: info,
downloadTaskUpdated: downloadTaskUpdated,
progressiveImageSetter: nil,
completionHandler: completionHandler)
}

func retrieveImage(
with source: Source,
options: KingfisherParsedOptionsInfo,
downloadTaskUpdated: DownloadTaskUpdatedBlock? = nil,
progressiveImageSetter: ((KFCrossPlatformImage?) -> Void)? = nil,
referenceTaskIdentifierChecker: (() -> Bool)? = nil,
completionHandler: ((Result<RetrieveImageResult, KingfisherError>) -> Void)?) -> DownloadTask?
{
var options = options
if let provider = ImageProgressiveProvider(options, refresh: { image in
guard let setter = progressiveImageSetter else {
return
}
guard let strategy = options.progressiveJPEG?.onImageUpdated(image) else {
setter(image)
return
}
switch strategy {
case .default: setter(image)
case .keepCurrent: break
case .replace(let newImage): setter(newImage)
}
}) {
options.onDataReceived = (options.onDataReceived ?? []) + [provider]
}
if let checker = referenceTaskIdentifierChecker {
options.onDataReceived?.forEach {
$0.onShouldApply = checker
}
}

let retrievingContext = RetrievingContext(options: options, originalSource: source)
var retryContext: RetryContext?

Expand Down
29 changes: 29 additions & 0 deletions Sources/Image/ImageProgressive.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,21 @@ private let sharedProcessingQueue: CallbackQueue =

public struct ImageProgressive {

/// The updating strategy when an intermediate progressive image is generated and about to be set to the hosting view.
///
/// - default: Use the progressive image as it is. It is the standard behavior when handling the progressive image.
/// - keepCurrent: Discard this progressive image and keep the current displayed one.
/// - replace: Replace the image to a new one. If the progressive loading is initialized by a view extension in
/// Kingfisher, the replacing image will be used to update the view.
public enum UpdatingStrategy {
case `default`
case keepCurrent
case replace(KFCrossPlatformImage?)
}

/// A default `ImageProgressive` could be used across. It blurs the progressive loading with the fastest
/// scan enabled and scan interval as 0.
@available(*, deprecated, message: "Getting a default `ImageProgressive` is deprecated due to its syntax symatic is not clear. Use `ImageProgressive.init` instead.", renamed: "init()")
public static let `default` = ImageProgressive(
isBlur: true,
isFastestScan: true,
Expand All @@ -47,6 +60,22 @@ public struct ImageProgressive {
/// Minimum time interval for each scan
let scanInterval: TimeInterval

/// Called when an intermediate image is prepared and about to be set to the image view. The return value of this
/// delegate will be used to update the hosting view, if any. Otherwise, if there is no hosting view (a.k.a the
/// image retrieving is not happening from a view extension method), the returned `UpdatingStrategy` is ignored.
public let onImageUpdated = Delegate<KFCrossPlatformImage, UpdatingStrategy>()

/// Creates an `ImageProgressive` value with default sets. It blurs the progressive loading with the fastest
/// scan enabled and scan interval as 0.
public init() {
self.init(isBlur: true, isFastestScan: true, scanInterval: 0)
}

/// Creates an `ImageProgressive` value the given values.
/// - Parameters:
/// - isBlur: Whether to enable blur effect processing.
/// - isFastestScan: Whether to enable the fastest scan.
/// - scanInterval: Minimum time interval for each scan.
public init(isBlur: Bool,
isFastestScan: Bool,
scanInterval: TimeInterval
Expand Down

0 comments on commit d237a93

Please sign in to comment.