mastodon-ios/Mastodon/Protocol/AvatarConfigurableView.swift

181 lines
7.8 KiB
Swift
Raw Normal View History

2021-02-04 12:28:16 +01:00
//
// AvatarConfigurableView.swift
// Mastodon
//
// Created by Cirno MainasuK on 2021-2-4.
//
import UIKit
import AlamofireImage
import Kingfisher
protocol AvatarConfigurableView {
2021-02-23 08:16:55 +01:00
static var configurableAvatarImageSize: CGSize { get }
static var configurableAvatarImageCornerRadius: CGFloat { get }
2021-02-04 12:28:16 +01:00
var configurableAvatarImageView: UIImageView? { get }
var configurableAvatarButton: UIButton? { get }
2021-02-23 08:16:55 +01:00
func configure(with configuration: AvatarConfigurableViewConfiguration)
2021-02-04 12:28:16 +01:00
func avatarConfigurableView(_ avatarConfigurableView: AvatarConfigurableView, didFinishConfiguration configuration: AvatarConfigurableViewConfiguration)
}
extension AvatarConfigurableView {
2021-02-23 08:16:55 +01:00
public func configure(with configuration: AvatarConfigurableViewConfiguration) {
2021-02-04 12:28:16 +01:00
let placeholderImage: UIImage = {
2021-02-23 08:16:55 +01:00
let placeholderImage = configuration.placeholderImage ?? UIImage.placeholder(size: Self.configurableAvatarImageSize, color: .systemFill)
if Self.configurableAvatarImageCornerRadius < Self.configurableAvatarImageSize.width * 0.5 {
return placeholderImage
.af.imageAspectScaled(toFill: Self.configurableAvatarImageSize)
.af.imageRounded(withCornerRadius: Self.configurableAvatarImageCornerRadius, divideRadiusByImageScale: false)
} else {
return placeholderImage.af.imageRoundedIntoCircle()
}
2021-02-04 12:28:16 +01:00
}()
// cancel previous task
configurableAvatarImageView?.af.cancelImageRequest()
configurableAvatarImageView?.kf.cancelDownloadTask()
configurableAvatarButton?.af.cancelImageRequest(for: .normal)
configurableAvatarButton?.kf.cancelImageDownloadTask()
// reset layer attributes
configurableAvatarImageView?.layer.masksToBounds = false
configurableAvatarImageView?.layer.cornerRadius = 0
configurableAvatarImageView?.layer.cornerCurve = .circular
configurableAvatarButton?.layer.masksToBounds = false
configurableAvatarButton?.layer.cornerRadius = 0
configurableAvatarButton?.layer.cornerCurve = .circular
2021-05-10 10:06:00 +02:00
// accessibility
configurableAvatarImageView?.accessibilityIgnoresInvertColors = true
configurableAvatarButton?.accessibilityIgnoresInvertColors = true
2021-02-04 12:28:16 +01:00
defer {
avatarConfigurableView(self, didFinishConfiguration: configuration)
}
2021-04-09 11:31:43 +02:00
2021-04-28 14:10:17 +02:00
let filter = ScaledToSizeWithRoundedCornersFilter(
size: Self.configurableAvatarImageSize,
radius: configuration.keepImageCorner ? 0 : Self.configurableAvatarImageCornerRadius
)
2021-04-09 11:31:43 +02:00
2021-02-04 12:28:16 +01:00
// set placeholder if no asset
2021-02-23 08:16:55 +01:00
guard let avatarImageURL = configuration.avatarImageURL else {
2021-02-04 12:28:16 +01:00
configurableAvatarImageView?.image = placeholderImage
2021-04-09 11:31:43 +02:00
configurableAvatarImageView?.layer.masksToBounds = true
configurableAvatarImageView?.layer.cornerRadius = Self.configurableAvatarImageCornerRadius
configurableAvatarImageView?.layer.cornerCurve = Self.configurableAvatarImageCornerRadius < Self.configurableAvatarImageSize.width * 0.5 ? .continuous :.circular
2021-02-04 12:28:16 +01:00
configurableAvatarButton?.setImage(placeholderImage, for: .normal)
2021-04-09 11:31:43 +02:00
configurableAvatarButton?.layer.masksToBounds = true
configurableAvatarButton?.layer.cornerRadius = Self.configurableAvatarImageCornerRadius
configurableAvatarButton?.layer.cornerCurve = Self.configurableAvatarImageCornerRadius < Self.configurableAvatarImageSize.width * 0.5 ? .continuous :.circular
2021-02-04 12:28:16 +01:00
return
}
if let avatarImageView = configurableAvatarImageView {
// set avatar (GIF using Kingfisher)
switch avatarImageURL.pathExtension {
case "gif":
avatarImageView.kf.setImage(
with: avatarImageURL,
placeholder: placeholderImage,
options: [
.transition(.fade(0.2))
]
)
avatarImageView.layer.masksToBounds = true
2021-02-23 08:16:55 +01:00
avatarImageView.layer.cornerRadius = Self.configurableAvatarImageCornerRadius
avatarImageView.layer.cornerCurve = Self.configurableAvatarImageCornerRadius < Self.configurableAvatarImageSize.width * 0.5 ? .continuous :.circular
2021-02-04 12:28:16 +01:00
default:
avatarImageView.af.setImage(
withURL: avatarImageURL,
placeholderImage: placeholderImage,
filter: filter,
imageTransition: .crossDissolve(0.3),
runImageTransitionIfCached: false,
completion: nil
)
2021-04-28 14:10:17 +02:00
if Self.configurableAvatarImageCornerRadius > 0, configuration.keepImageCorner {
configurableAvatarImageView?.layer.masksToBounds = true
configurableAvatarImageView?.layer.cornerRadius = Self.configurableAvatarImageCornerRadius
configurableAvatarImageView?.layer.cornerCurve = Self.configurableAvatarImageCornerRadius < Self.configurableAvatarImageSize.width * 0.5 ? .continuous :.circular
}
2021-02-04 12:28:16 +01:00
}
configureLayerBorder(view: avatarImageView, configuration: configuration)
2021-02-04 12:28:16 +01:00
}
if let avatarButton = configurableAvatarButton {
switch avatarImageURL.pathExtension {
case "gif":
avatarButton.kf.setImage(
with: avatarImageURL,
for: .normal,
placeholder: placeholderImage,
options: [
.transition(.fade(0.2))
]
)
avatarButton.layer.masksToBounds = true
2021-02-23 08:16:55 +01:00
avatarButton.layer.cornerRadius = Self.configurableAvatarImageCornerRadius
avatarButton.layer.cornerCurve = Self.configurableAvatarImageCornerRadius < Self.configurableAvatarImageSize.width * 0.5 ? .continuous : .circular
2021-02-04 12:28:16 +01:00
default:
avatarButton.af.setImage(
for: .normal,
url: avatarImageURL,
placeholderImage: placeholderImage,
filter: filter,
completion: nil
)
}
configureLayerBorder(view: avatarButton, configuration: configuration)
2021-02-04 12:28:16 +01:00
}
}
func configureLayerBorder(view: UIView, configuration: AvatarConfigurableViewConfiguration) {
guard let borderWidth = configuration.borderWidth, borderWidth > 0,
let borderColor = configuration.borderColor else {
return
}
view.layer.masksToBounds = true
view.layer.cornerRadius = Self.configurableAvatarImageCornerRadius
view.layer.cornerCurve = .continuous
view.layer.borderColor = borderColor.cgColor
view.layer.borderWidth = borderWidth
}
2021-02-04 12:28:16 +01:00
func avatarConfigurableView(_ avatarConfigurableView: AvatarConfigurableView, didFinishConfiguration configuration: AvatarConfigurableViewConfiguration) { }
}
struct AvatarConfigurableViewConfiguration {
2021-02-23 08:16:55 +01:00
let avatarImageURL: URL?
let placeholderImage: UIImage?
let borderColor: UIColor?
let borderWidth: CGFloat?
2021-02-04 12:28:16 +01:00
2021-04-28 14:10:17 +02:00
let keepImageCorner: Bool
init(
avatarImageURL: URL?,
placeholderImage: UIImage? = nil,
borderColor: UIColor? = nil,
2021-04-28 14:10:17 +02:00
borderWidth: CGFloat? = nil,
2021-04-28 14:36:10 +02:00
keepImageCorner: Bool = false // default clip corner on image
) {
2021-02-23 08:16:55 +01:00
self.avatarImageURL = avatarImageURL
self.placeholderImage = placeholderImage
self.borderColor = borderColor
self.borderWidth = borderWidth
2021-04-28 14:10:17 +02:00
self.keepImageCorner = keepImageCorner
2021-02-04 12:28:16 +01:00
}
}