mastodon-ios/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift

180 lines
6.5 KiB
Swift
Raw Normal View History

2021-09-24 13:58:50 +02:00
//
// SidebarListContentView.swift
// Mastodon
//
// Created by Cirno MainasuK on 2021-9-24.
//
import os.log
import UIKit
import MetaTextKit
import FLAnimatedImage
final class SidebarListContentView: UIView, UIContentView {
let logger = Logger(subsystem: "SidebarListContentView", category: "UI")
let imageView = UIImageView()
2021-10-28 13:17:41 +02:00
let avatarButton: CircleAvatarButton = {
let button = CircleAvatarButton()
button.borderWidth = 2
button.borderColor = UIColor.label
2021-10-28 13:17:41 +02:00
return button
}()
2021-09-24 13:58:50 +02:00
private var currentConfiguration: ContentConfiguration!
var configuration: UIContentConfiguration {
get {
currentConfiguration
}
set {
guard let newConfiguration = newValue as? ContentConfiguration else { return }
apply(configuration: newConfiguration)
}
}
init(configuration: ContentConfiguration) {
super.init(frame: .zero)
_init()
apply(configuration: configuration)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
_init()
}
}
extension SidebarListContentView {
private func _init() {
imageView.translatesAutoresizingMaskIntoConstraints = false
2021-10-28 13:17:41 +02:00
addSubview(imageView)
2021-09-24 13:58:50 +02:00
NSLayoutConstraint.activate([
2021-10-28 13:17:41 +02:00
imageView.topAnchor.constraint(equalTo: topAnchor, constant: 16),
imageView.centerXAnchor.constraint(equalTo: centerXAnchor),
bottomAnchor.constraint(equalTo: imageView.bottomAnchor, constant: 16),
imageView.widthAnchor.constraint(equalToConstant: 40).priority(.required - 1),
imageView.heightAnchor.constraint(equalToConstant: 40).priority(.required - 1),
2021-09-24 13:58:50 +02:00
])
2021-10-28 13:17:41 +02:00
avatarButton.translatesAutoresizingMaskIntoConstraints = false
addSubview(avatarButton)
NSLayoutConstraint.activate([
2021-10-28 13:17:41 +02:00
avatarButton.centerXAnchor.constraint(equalTo: imageView.centerXAnchor),
avatarButton.centerYAnchor.constraint(equalTo: imageView.centerYAnchor),
avatarButton.widthAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: 1.0).priority(.required - 2),
avatarButton.heightAnchor.constraint(equalTo: imageView.heightAnchor, multiplier: 1.0).priority(.required - 2),
])
2021-10-28 13:17:41 +02:00
avatarButton.setContentHuggingPriority(.defaultLow - 10, for: .vertical)
avatarButton.setContentHuggingPriority(.defaultLow - 10, for: .horizontal)
2021-09-24 13:58:50 +02:00
imageView.contentMode = .scaleAspectFit
2021-10-28 13:17:41 +02:00
avatarButton.contentMode = .scaleAspectFit
imageView.isUserInteractionEnabled = false
avatarButton.isUserInteractionEnabled = false
2021-09-24 13:58:50 +02:00
}
private func apply(configuration: ContentConfiguration) {
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
guard currentConfiguration != configuration else { return }
currentConfiguration = configuration
guard let item = configuration.item else { return }
// configure state
2021-10-29 08:58:09 +02:00
let tintColor = item.isHighlighted ? ThemeService.tintColor.withAlphaComponent(0.5) : ThemeService.tintColor
imageView.tintColor = tintColor
avatarButton.tintColor = tintColor
2021-09-24 13:58:50 +02:00
// configure model
imageView.isHidden = item.imageURL != nil
2021-10-28 13:17:41 +02:00
avatarButton.isHidden = item.imageURL == nil
imageView.image = item.isActive ? item.activeImage.withRenderingMode(.alwaysTemplate) : item.image.withRenderingMode(.alwaysTemplate)
2021-10-28 13:17:41 +02:00
avatarButton.avatarImageView.setImage(
2021-09-24 13:58:50 +02:00
url: item.imageURL,
2021-10-28 13:17:41 +02:00
placeholder: avatarButton.avatarImageView.image ?? .placeholder(color: .systemFill), // reuse to avoid blink
2021-09-24 13:58:50 +02:00
scaleToSize: nil
)
avatarButton.borderWidth = item.isActive ? 2 : 0
avatarButton.setNeedsLayout()
2021-09-24 13:58:50 +02:00
}
}
extension SidebarListContentView {
struct Item: Hashable {
// state
var isSelected: Bool = false
2021-10-29 08:58:09 +02:00
var isHighlighted: Bool = false
var isActive: Bool
2021-09-24 13:58:50 +02:00
// model
2021-10-28 13:17:41 +02:00
let title: String
var image: UIImage
var activeImage: UIImage
2021-09-24 13:58:50 +02:00
let imageURL: URL?
2021-10-28 13:17:41 +02:00
2021-09-24 13:58:50 +02:00
static func == (lhs: SidebarListContentView.Item, rhs: SidebarListContentView.Item) -> Bool {
return lhs.isSelected == rhs.isSelected
2021-10-29 08:58:09 +02:00
&& lhs.isHighlighted == rhs.isHighlighted
&& lhs.isActive == rhs.isActive
2021-10-28 13:17:41 +02:00
&& lhs.title == rhs.title
2021-09-24 13:58:50 +02:00
&& lhs.image == rhs.image
&& lhs.activeImage == rhs.activeImage
2021-09-24 13:58:50 +02:00
&& lhs.imageURL == rhs.imageURL
}
func hash(into hasher: inout Hasher) {
hasher.combine(isSelected)
2021-10-29 08:58:09 +02:00
hasher.combine(isHighlighted)
hasher.combine(isActive)
2021-10-28 13:17:41 +02:00
hasher.combine(title)
2021-09-24 13:58:50 +02:00
hasher.combine(image)
hasher.combine(activeImage)
2021-09-24 13:58:50 +02:00
imageURL.flatMap { hasher.combine($0) }
}
}
struct ContentConfiguration: UIContentConfiguration, Hashable {
let logger = Logger(subsystem: "SidebarListContentView.ContentConfiguration", category: "ContentConfiguration")
var item: Item?
func makeContentView() -> UIView & UIContentView {
SidebarListContentView(configuration: self)
}
func updated(for state: UIConfigurationState) -> ContentConfiguration {
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
var updatedConfiguration = self
if let state = state as? UICellConfigurationState {
updatedConfiguration.item?.isSelected = state.isHighlighted || state.isSelected
2021-10-29 08:58:09 +02:00
updatedConfiguration.item?.isHighlighted = state.isHighlighted
2021-09-24 13:58:50 +02:00
} else {
assertionFailure()
updatedConfiguration.item?.isSelected = false
2021-10-29 08:58:09 +02:00
updatedConfiguration.item?.isHighlighted = false
2021-09-24 13:58:50 +02:00
}
return updatedConfiguration
}
static func == (
lhs: ContentConfiguration,
rhs: ContentConfiguration
) -> Bool {
return lhs.item == rhs.item
}
func hash(into hasher: inout Hasher) {
hasher.combine(item)
}
}
}