Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 61 additions & 4 deletions Sources/AsyncMultiplexImage/AsyncMultiplexImageView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,34 @@ import UIKit

open class AsyncMultiplexImageView: UIView {

public protocol OffloadStrategy {
func offloads(using state: borrowing State) -> Bool
}

public struct OffloadInvisibleStrategy: OffloadStrategy {

public init() {

}

public func offloads(using state: borrowing State) -> Bool {
state.isInDisplay == false
}
}

public struct State: ~Copyable {

/// Whether the app is in background state
public var isInBackground: Bool = false

/// Whether the view is in view hierarchy
public var isInDisplay: Bool = false
}

// MARK: - Properties

public let downloader: any AsyncMultiplexImageDownloader
public let offloadStrategy: any OffloadStrategy

private let viewModel: _AsyncMultiplexImageViewModel = .init()

Expand All @@ -16,15 +41,22 @@ open class AsyncMultiplexImageView: UIView {

private let imageView: UIImageView = .init()

private var state: State = .init() {
didSet {
onUpdateState(state: state)
}
}

// MARK: - Initializers

public init(
downloader: any AsyncMultiplexImageDownloader,
clearsContentBeforeDownload: Bool = true,
unloadsImageOnBackground: Bool = false
offloadStrategy: any OffloadStrategy = OffloadInvisibleStrategy(),
clearsContentBeforeDownload: Bool = true
) {

self.downloader = downloader
self.offloadStrategy = offloadStrategy
self.clearsContentBeforeDownload = clearsContentBeforeDownload

super.init(frame: .null)
Expand Down Expand Up @@ -68,6 +100,15 @@ open class AsyncMultiplexImageView: UIView {

// MARK: - Functions

private func onUpdateState(state: borrowing State) {
let offloads = offloadStrategy.offloads(using: state)

if offloads {
viewModel.cancelCurrentTask()
unloadImage()
}
}

open override func layoutSubviews() {
super.layoutSubviews()

Expand All @@ -77,14 +118,19 @@ open class AsyncMultiplexImageView: UIView {
}
}

open override func willMove(toWindow newWindow: UIWindow?) {
super.willMove(toWindow: newWindow)
state.isInDisplay = newWindow != nil
}

@objc
private func didEnterBackground() {
unloadImage()
state.isInBackground = true
}

@objc
private func willEnterForeground() {
startDownload()
state.isInBackground = false
}

public func setMultiplexImage(_ image: MultiplexImage) {
Expand All @@ -98,6 +144,12 @@ open class AsyncMultiplexImageView: UIView {
imageView.image = image
}

public func clearImage() {
currentUsingImage = nil
imageView.image = nil
viewModel.cancelCurrentTask()
}

private func startDownload() {

guard let image = currentUsingImage else {
Expand Down Expand Up @@ -140,6 +192,11 @@ open class AsyncMultiplexImageView: UIView {
if capturedImage == self.currentUsingImage {

await MainActor.run {

guard Task.isCancelled == false else {
return
}

CATransaction.begin()
let transition = CATransition()
transition.duration = 0.13
Expand Down