forked from zelo72/mastodon-ios
88 lines
3.0 KiB
Swift
88 lines
3.0 KiB
Swift
//
|
|
// FLAnimatedImageView.swift
|
|
// Mastodon
|
|
//
|
|
// Created by MainasuK Cirno on 2021-7-21.
|
|
//
|
|
|
|
import Foundation
|
|
import Combine
|
|
import Alamofire
|
|
import AlamofireImage
|
|
import FLAnimatedImage
|
|
import UIKit
|
|
|
|
private enum FLAnimatedImageViewAssociatedKeys {
|
|
static var activeAvatarRequestURL = "FLAnimatedImageViewAssociatedKeys.activeAvatarRequestURL"
|
|
static var avatarRequestCancellable = "FLAnimatedImageViewAssociatedKeys.avatarRequestCancellable"
|
|
}
|
|
|
|
extension FLAnimatedImageView {
|
|
|
|
var activeAvatarRequestURL: URL? {
|
|
get {
|
|
objc_getAssociatedObject(self, &FLAnimatedImageViewAssociatedKeys.activeAvatarRequestURL) as? URL
|
|
}
|
|
set {
|
|
objc_setAssociatedObject(self, &FLAnimatedImageViewAssociatedKeys.activeAvatarRequestURL, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
|
}
|
|
}
|
|
|
|
var avatarRequestCancellable: AnyCancellable? {
|
|
get {
|
|
objc_getAssociatedObject(self, &FLAnimatedImageViewAssociatedKeys.avatarRequestCancellable) as? AnyCancellable
|
|
}
|
|
set {
|
|
objc_setAssociatedObject(self, &FLAnimatedImageViewAssociatedKeys.avatarRequestCancellable, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
|
}
|
|
}
|
|
|
|
func setImage(
|
|
url: URL?,
|
|
placeholder: UIImage?,
|
|
scaleToSize: CGSize?,
|
|
completion: ((UIImage?) -> Void)? = nil
|
|
) {
|
|
// cancel task
|
|
activeAvatarRequestURL = nil
|
|
avatarRequestCancellable?.cancel()
|
|
|
|
// set placeholder
|
|
image = placeholder
|
|
|
|
// set image
|
|
guard let url = url else { return }
|
|
activeAvatarRequestURL = url
|
|
let avatarRequest = AF.request(url).publishData()
|
|
avatarRequestCancellable = avatarRequest
|
|
.sink { response in
|
|
switch response.result {
|
|
case .success(let data):
|
|
DispatchQueue.global().async {
|
|
let image: UIImage? = {
|
|
if let scaleToSize = scaleToSize {
|
|
return UIImage(data: data)?.af.imageScaled(to: scaleToSize, scale: UIScreen.main.scale)
|
|
} else {
|
|
return UIImage(data: data)
|
|
}
|
|
}()
|
|
let animatedImage = FLAnimatedImage(animatedGIFData: data)
|
|
|
|
DispatchQueue.main.async { [weak self] in
|
|
guard let self = self else { return }
|
|
guard self.activeAvatarRequestURL == url else { return }
|
|
if let animatedImage = animatedImage {
|
|
self.animatedImage = animatedImage
|
|
} else {
|
|
self.image = image
|
|
}
|
|
completion?(image)
|
|
}
|
|
}
|
|
case .failure:
|
|
completion?(nil)
|
|
}
|
|
}
|
|
}
|
|
}
|