diff --git a/Tusker/Caching/ImageCache.swift b/Tusker/Caching/ImageCache.swift index f34ea58f..faf82b36 100644 --- a/Tusker/Caching/ImageCache.swift +++ b/Tusker/Caching/ImageCache.swift @@ -78,6 +78,14 @@ class ImageCache { } } + func get(_ url: URL, loadOriginal: Bool = false) async -> (Data?, UIImage?) { + return await withCheckedContinuation { continuation in + _ = get(url, loadOriginal: loadOriginal) { data, image in + continuation.resume(returning: (data, image)) + } + } + } + func fetchIfNotCached(_ url: URL) { // if caching is disabled, don't bother fetching since nothing will be done with the result guard !ImageCache.disableCaching else { return } diff --git a/Tusker/Views/Notifications/ActionNotificationGroupTableViewCell.swift b/Tusker/Views/Notifications/ActionNotificationGroupTableViewCell.swift index a7695d9e..b819b360 100644 --- a/Tusker/Views/Notifications/ActionNotificationGroupTableViewCell.swift +++ b/Tusker/Views/Notifications/ActionNotificationGroupTableViewCell.swift @@ -25,7 +25,6 @@ class ActionNotificationGroupTableViewCell: UITableViewCell { var group: NotificationGroup! var statusID: String! - private var avatarRequests = [String: ImageCache.Request]() private var updateTimestampWorkItem: DispatchWorkItem? private var isGrayscale = false @@ -47,7 +46,9 @@ class ActionNotificationGroupTableViewCell: UITableViewCell { } if isGrayscale != Preferences.shared.grayscaleImages { - updateGrayscaleableUI() + Task { + await updateGrayscaleableUI() + } } } @@ -78,29 +79,11 @@ class ActionNotificationGroupTableViewCell: UITableViewCell { actionAvatarStackView.arrangedSubviews.forEach { $0.removeFromSuperview() } var imageViews = [UIImageView]() - for account in people { + for _ in people { let imageView = UIImageView() imageView.translatesAutoresizingMaskIntoConstraints = false imageView.layer.masksToBounds = true imageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadiusFraction * 30 - if let avatarURL = account.avatar { - avatarRequests[account.id] = ImageCache.avatars.get(avatarURL) { [weak self] (_, image) in - guard let self = self else { return } - guard let image = image, - self.group.id == group.id, - let transformedImage = ImageGrayscalifier.convertIfNecessary(url: avatarURL, image: image) else { - DispatchQueue.main.async { - self.avatarRequests.removeValue(forKey: account.id) - } - return - } - - DispatchQueue.main.async { - self.avatarRequests.removeValue(forKey: account.id) - imageView.image = transformedImage - } - } - } actionAvatarStackView.addArrangedSubview(imageView) imageViews.append(imageView) @@ -114,6 +97,10 @@ class ActionNotificationGroupTableViewCell: UITableViewCell { } } NSLayoutConstraint.activate(imageViews.map { $0.widthAnchor.constraint(equalTo: $0.heightAnchor) }) + + Task { + await updateGrayscaleableUI() + } updateTimestamp() actionLabel.setEmojis(pairs: people.map { ($0.displayOrUserName, $0.emojis) }, identifier: group.id) @@ -122,33 +109,26 @@ class ActionNotificationGroupTableViewCell: UITableViewCell { statusContentLabel.text = try! doc.text() } - private func updateGrayscaleableUI() { + @MainActor + private func updateGrayscaleableUI() async { let people = group.notifications.compactMap { mastodonController.persistentContainer.account(for: $0.account.id) } let groupID = group.id for (index, account) in people.enumerated() { guard actionAvatarStackView.arrangedSubviews.count > index, - let imageView = actionAvatarStackView.arrangedSubviews[index] as? UIImageView else { + let imageView = actionAvatarStackView.arrangedSubviews[index] as? UIImageView, + let avatarURL = account.avatar else { continue } - if let avatarURL = account.avatar { - avatarRequests[account.id] = ImageCache.avatars.get(avatarURL) { [weak self] (_, image) in - guard let self = self else { return } - guard let image = image, - self.group.id == groupID, - let transformedImage = ImageGrayscalifier.convertIfNecessary(url: avatarURL, image: image) else { - DispatchQueue.main.async { - self.avatarRequests.removeValue(forKey: account.id) - } - return - } - - DispatchQueue.main.async { - self.avatarRequests.removeValue(forKey: account.id) - imageView.image = transformedImage - } + Task { + let (_, image) = await ImageCache.avatars.get(avatarURL) + guard let image = image, + self.group.id == groupID, + let transformedImage = ImageGrayscalifier.convertIfNecessary(url: avatarURL, image: image) else { + return } + imageView.image = transformedImage } } } @@ -217,7 +197,6 @@ class ActionNotificationGroupTableViewCell: UITableViewCell { override func prepareForReuse() { super.prepareForReuse() - avatarRequests.values.forEach { $0.cancel() } updateTimestampWorkItem?.cancel() updateTimestampWorkItem = nil }