Tusker/Tusker/Views/CachedImageView.swift

98 lines
2.8 KiB
Swift

//
// CachedImageView.swift
// Tusker
//
// Created by Shadowfacts on 10/4/22.
// Copyright © 2022 Shadowfacts. All rights reserved.
//
import UIKit
class CachedImageView: UIImageView {
var cache: ImageCache!
private var url: URL?
private var isGrayscale = false
private var fetchTask: Task<Void, Error>?
private var blurHashTask: DispatchWorkItem?
override var image: UIImage? {
didSet {
fetchTask?.cancel()
}
}
init(cache: ImageCache) {
self.cache = cache
super.init(frame: .zero)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
private func commonInit() {
NotificationCenter.default.addObserver(self, selector: #selector(preferencesChanged), name: .preferencesChanged, object: nil)
}
func update(for url: URL?, blurhash: String? = nil, placeholder: UIImage? = nil) {
if url != self.url || (url != nil && self.image == nil) {
self.url = url
super.image = placeholder
updateBlurhash(blurhash, for: url)
updateImage()
}
}
@objc private func preferencesChanged() {
if isGrayscale != Preferences.shared.grayscaleImages {
updateImage()
}
}
private func updateBlurhash(_ blurhash: String?, for url: URL?) {
blurHashTask?.cancel()
if let blurhash {
let aspectRatio = self.bounds.width > 0 ? self.bounds.height / self.bounds.width : 1
blurHashTask = DispatchWorkItem {
let size = CGSize(width: 60, height: aspectRatio * 60)
let image = UIImage(blurHash: blurhash, size: size)
DispatchQueue.main.async {
if self.image == nil && self.url == url && self.blurHashTask?.isCancelled == false {
self.image = image
}
}
}
AttachmentView.queue.async(execute: blurHashTask!)
}
}
private func updateImage() {
fetchTask?.cancel()
guard let url else {
return
}
fetchTask = Task(priority: .high) {
let (_, image) = await cache.get(url)
guard let image else {
return
}
try Task.checkCancellation()
// TODO: check that this isn't on the main thread
guard let transformedImage = ImageGrayscalifier.convertIfNecessary(url: url, image: image) else {
return
}
try Task.checkCancellation()
super.image = transformedImage
self.isGrayscale = Preferences.shared.grayscaleImages
self.blurHashTask?.cancel()
}
}
}