Change TrendingLinkCardCollectionViewCell to use CachedImageView

This commit is contained in:
Shadowfacts 2023-01-22 18:07:16 -05:00
parent 3262fe002b
commit 2958d2b1ac
3 changed files with 45 additions and 48 deletions

View File

@ -8,14 +8,13 @@
import UIKit import UIKit
import Pachyderm import Pachyderm
import WebURLFoundationExtras
class TrendingLinkCardCollectionViewCell: UICollectionViewCell { class TrendingLinkCardCollectionViewCell: UICollectionViewCell {
private var card: Card? private var card: Card?
private var isGrayscale = false
private var thumbnailRequest: ImageCache.Request?
@IBOutlet weak var thumbnailView: UIImageView! @IBOutlet weak var thumbnailView: CachedImageView!
@IBOutlet weak var titleLabel: UILabel! @IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var descriptionLabel: UILabel! @IBOutlet weak var descriptionLabel: UILabel!
@IBOutlet weak var providerLabel: UILabel! @IBOutlet weak var providerLabel: UILabel!
@ -27,14 +26,14 @@ class TrendingLinkCardCollectionViewCell: UICollectionViewCell {
override func awakeFromNib() { override func awakeFromNib() {
super.awakeFromNib() super.awakeFromNib()
thumbnailView.cache = .attachments
layer.shadowOpacity = 0.2 layer.shadowOpacity = 0.2
layer.shadowRadius = 8 layer.shadowRadius = 8
layer.shadowOffset = .zero layer.shadowOffset = .zero
layer.masksToBounds = false layer.masksToBounds = false
updateLayerColors() updateLayerColors()
NotificationCenter.default.addObserver(self, selector: #selector(updateUIForPreferences), name: .preferencesChanged, object: nil)
addGestureRecognizer(UIHoverGestureRecognizer(target: self, action: #selector(hoverRecognized))) addGestureRecognizer(UIHoverGestureRecognizer(target: self, action: #selector(hoverRecognized)))
} }
@ -48,8 +47,7 @@ class TrendingLinkCardCollectionViewCell: UICollectionViewCell {
self.card = card self.card = card
self.thumbnailView.image = nil self.thumbnailView.image = nil
updateGrayscaleableUI(card: card) thumbnailView.update(for: card.image.flatMap { URL($0) }, blurhash: card.blurhash)
updateUIForPreferences()
let title = card.title.trimmingCharacters(in: .whitespacesAndNewlines) let title = card.title.trimmingCharacters(in: .whitespacesAndNewlines)
titleLabel.text = title titleLabel.text = title
@ -77,33 +75,6 @@ class TrendingLinkCardCollectionViewCell: UICollectionViewCell {
historyView.isHidden = card.history == nil || card.history!.count < 2 historyView.isHidden = card.history == nil || card.history!.count < 2
} }
@objc private func updateUIForPreferences() {
if isGrayscale != Preferences.shared.grayscaleImages,
let card {
updateGrayscaleableUI(card: card)
}
}
private func updateGrayscaleableUI(card: Card) {
isGrayscale = Preferences.shared.grayscaleImages
if let imageURL = card.image,
let url = URL(imageURL) {
thumbnailRequest = ImageCache.attachments.get(url, completion: { _, image in
guard let image,
let transformedImage = ImageGrayscalifier.convertIfNecessary(url: url, image: image) else {
return
}
DispatchQueue.main.async {
self.thumbnailView.image = transformedImage
}
})
if thumbnailRequest != nil {
loadBlurHash(card: card)
}
}
}
private func loadBlurHash(card: Card) { private func loadBlurHash(card: Card) {
guard let hash = card.blurhash else { guard let hash = card.blurhash else {
return return

View File

@ -18,7 +18,7 @@
<rect key="frame" x="0.0" y="0.0" width="300" height="406"/> <rect key="frame" x="0.0" y="0.0" width="300" height="406"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="h3b-Mf-lD6"> <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="h3b-Mf-lD6" customClass="CachedImageView" customModule="Tusker" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="300" height="225"/> <rect key="frame" x="0.0" y="0.0" width="300" height="225"/>
<constraints> <constraints>
<constraint firstAttribute="width" secondItem="h3b-Mf-lD6" secondAttribute="height" multiplier="4:3" id="QDY-8a-LYC"/> <constraint firstAttribute="width" secondItem="h3b-Mf-lD6" secondAttribute="height" multiplier="4:3" id="QDY-8a-LYC"/>
@ -56,9 +56,9 @@
</constraints> </constraints>
</view> </view>
<visualEffectView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="cWo-9n-z42"> <visualEffectView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="cWo-9n-z42">
<rect key="frame" x="0.0" y="196.33333333333334" width="300" height="28.666666666666657"/> <rect key="frame" x="0.0" y="196.66666666666666" width="300" height="28.333333333333343"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="ktv-3s-cp9"> <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="ktv-3s-cp9">
<rect key="frame" x="0.0" y="0.0" width="300" height="29"/> <rect key="frame" x="0.0" y="0.0" width="300" height="28"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsLetterSpacingToFitWidth="YES" showsExpansionTextWhenTruncated="YES" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ho3-cU-IGi"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsLetterSpacingToFitWidth="YES" showsExpansionTextWhenTruncated="YES" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ho3-cU-IGi">

View File

@ -10,26 +10,32 @@ import UIKit
class CachedImageView: UIImageView { class CachedImageView: UIImageView {
private let cache: ImageCache var cache: ImageCache!
private var url: URL? private var url: URL?
private var isGrayscale = false private var isGrayscale = false
private var fetchTask: Task<Void, Error>? private var fetchTask: Task<Void, Error>?
private var blurHashTask: DispatchWorkItem?
init(cache: ImageCache) { init(cache: ImageCache) {
self.cache = cache self.cache = cache
super.init(frame: .zero) super.init(frame: .zero)
commonInit()
NotificationCenter.default.addObserver(self, selector: #selector(preferencesChanged), name: .preferencesChanged, object: nil)
} }
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented") super.init(coder: coder)
commonInit()
} }
func update(for url: URL?) { private func commonInit() {
if url != self.url { NotificationCenter.default.addObserver(self, selector: #selector(preferencesChanged), name: .preferencesChanged, object: nil)
}
func update(for url: URL?, blurhash: String? = nil) {
if url != self.url || (url != nil && self.image == nil) {
self.url = url self.url = url
self.image = nil
updateBlurhash(blurhash, for: url)
updateImage() updateImage()
} }
} }
@ -40,13 +46,32 @@ class CachedImageView: UIImageView {
} }
} }
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() { private func updateImage() {
fetchTask?.cancel() fetchTask?.cancel()
guard let url else {
return
}
fetchTask = Task(priority: .high) { fetchTask = Task(priority: .high) {
self.image = nil
guard let url else {
return
}
let (_, image) = await cache.get(url) let (_, image) = await cache.get(url)
guard let image else { guard let image else {
return return
@ -59,6 +84,7 @@ class CachedImageView: UIImageView {
try Task.checkCancellation() try Task.checkCancellation()
self.image = transformedImage self.image = transformedImage
self.isGrayscale = Preferences.shared.grayscaleImages self.isGrayscale = Preferences.shared.grayscaleImages
self.blurHashTask?.cancel()
} }
} }