mastodon-ios/Mastodon/Scene/Notification/TableViewCell/NotificationTableViewCell.s...

257 lines
12 KiB
Swift
Raw Normal View History

2021-04-12 10:31:53 +02:00
//
// NotificationTableViewCell.swift
// Mastodon
//
// Created by sxiaojian on 2021/4/13.
//
2021-04-14 09:00:48 +02:00
import Combine
2021-04-15 04:16:30 +02:00
import CoreDataStack
2021-04-12 10:31:53 +02:00
import Foundation
import UIKit
import Meta
import MetaTextView
import ActiveLabel
2021-04-12 10:31:53 +02:00
2021-04-15 04:16:30 +02:00
protocol NotificationTableViewCellDelegate: AnyObject {
2021-04-14 09:00:48 +02:00
var context: AppContext! { get }
func parent() -> UIViewController
2021-04-15 04:16:30 +02:00
func userAvatarDidPressed(notification: MastodonNotification)
func userNameLabelDidPressed(notification: MastodonNotification)
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, revealContentWarningButtonDidPressed button: UIButton)
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, playerContainerView: PlayerContainerView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta)
2021-04-27 10:54:23 +02:00
func notificationTableViewCell(_ cell: NotificationTableViewCell, notification: MastodonNotification, acceptButtonDidPressed button: UIButton)
func notificationTableViewCell(_ cell: NotificationTableViewCell, notification: MastodonNotification, rejectButtonDidPressed button: UIButton)
2021-04-14 09:00:48 +02:00
}
2021-04-12 10:31:53 +02:00
final class NotificationTableViewCell: UITableViewCell {
2021-04-13 15:31:49 +02:00
static let actionImageBorderWidth: CGFloat = 2
2021-04-12 10:31:53 +02:00
var disposeBag = Set<AnyCancellable>()
2021-04-14 09:00:48 +02:00
var delegate: NotificationTableViewCellDelegate?
let avatarImageView: UIImageView = {
2021-04-12 10:31:53 +02:00
let imageView = UIImageView()
imageView.layer.cornerRadius = 4
imageView.layer.cornerCurve = .continuous
imageView.clipsToBounds = true
return imageView
}()
let actionImageView: UIImageView = {
let imageView = UIImageView()
2021-04-16 16:58:36 +02:00
imageView.tintColor = Asset.Colors.Background.systemBackground.color
2021-04-12 10:31:53 +02:00
return imageView
}()
2021-04-13 15:31:49 +02:00
let actionImageBackground: UIView = {
let view = UIView()
2021-04-14 09:00:48 +02:00
view.layer.cornerRadius = (24 + NotificationTableViewCell.actionImageBorderWidth) / 2
2021-04-13 15:31:49 +02:00
view.layer.cornerCurve = .continuous
view.clipsToBounds = true
view.layer.borderWidth = NotificationTableViewCell.actionImageBorderWidth
2021-04-16 16:58:36 +02:00
view.layer.borderColor = Asset.Colors.Background.systemBackground.color.cgColor
view.tintColor = Asset.Colors.Background.systemBackground.color
2021-04-13 15:31:49 +02:00
return view
}()
2021-04-16 15:55:09 +02:00
let avatarContainer: UIView = {
let view = UIView()
return view
}()
2021-04-12 10:31:53 +02:00
let actionLabel: UILabel = {
let label = UILabel()
label.textColor = Asset.Colors.Label.secondary.color
label.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15, weight: .regular), maximumPointSize: 20)
2021-04-12 10:31:53 +02:00
label.lineBreakMode = .byTruncatingTail
return label
}()
let nameLabel: ActiveLabel = {
let label = ActiveLabel()
2021-04-12 10:31:53 +02:00
label.textColor = Asset.Colors.brandBlue.color
label.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .semibold), maximumPointSize: 20)
2021-04-12 10:31:53 +02:00
label.lineBreakMode = .byTruncatingTail
return label
}()
let acceptButton: UIButton = {
let button = UIButton(type: .custom)
let actionImage = UIImage(systemName: "checkmark.circle.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 28, weight: .semibold))?.withRenderingMode(.alwaysTemplate)
button.setImage(actionImage, for: .normal)
button.tintColor = Asset.Colors.Label.secondary.color
return button
}()
let rejectButton: UIButton = {
let button = UIButton(type: .custom)
let actionImage = UIImage(systemName: "xmark.circle.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 28, weight: .semibold))?.withRenderingMode(.alwaysTemplate)
button.setImage(actionImage, for: .normal)
button.tintColor = Asset.Colors.Label.secondary.color
return button
}()
let buttonStackView = UIStackView()
let separatorLine = UIView.separatorLine
var separatorLineToEdgeLeadingLayoutConstraint: NSLayoutConstraint!
var separatorLineToEdgeTrailingLayoutConstraint: NSLayoutConstraint!
var separatorLineToMarginLeadingLayoutConstraint: NSLayoutConstraint!
var separatorLineToMarginTrailingLayoutConstraint: NSLayoutConstraint!
2021-04-12 10:31:53 +02:00
override func prepareForReuse() {
super.prepareForReuse()
avatarImageView.af.cancelImageRequest()
2021-04-14 09:00:48 +02:00
disposeBag.removeAll()
2021-04-12 10:31:53 +02:00
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
configure()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
configure()
}
}
extension NotificationTableViewCell {
func configure() {
2021-06-30 14:11:38 +02:00
backgroundColor = Asset.Colors.Background.systemBackground.color
2021-04-14 09:00:48 +02:00
2021-04-16 15:55:09 +02:00
let containerStackView = UIStackView()
containerStackView.axis = .vertical
containerStackView.alignment = .fill
2021-04-16 15:55:09 +02:00
containerStackView.layoutMargins = UIEdgeInsets(top: 14, left: 0, bottom: 12, right: 0)
containerStackView.isLayoutMarginsRelativeArrangement = true
containerStackView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(containerStackView)
NSLayoutConstraint.activate([
containerStackView.topAnchor.constraint(equalTo: contentView.topAnchor),
containerStackView.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor),
contentView.readableContentGuide.trailingAnchor.constraint(equalTo: containerStackView.trailingAnchor),
contentView.bottomAnchor.constraint(equalTo: containerStackView.bottomAnchor),
2021-04-15 04:37:46 +02:00
])
let horizontalStackView = UIStackView()
horizontalStackView.translatesAutoresizingMaskIntoConstraints = false
horizontalStackView.axis = .horizontal
horizontalStackView.spacing = 6
horizontalStackView.addArrangedSubview(avatarContainer)
2021-04-16 15:55:09 +02:00
avatarContainer.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
avatarContainer.heightAnchor.constraint(equalToConstant: 47).priority(.required - 1),
avatarContainer.widthAnchor.constraint(equalToConstant: 47).priority(.required - 1)
2021-04-12 10:31:53 +02:00
])
2021-04-16 15:55:09 +02:00
avatarContainer.addSubview(avatarImageView)
avatarImageView.translatesAutoresizingMaskIntoConstraints = false
2021-04-16 15:55:09 +02:00
NSLayoutConstraint.activate([
avatarImageView.heightAnchor.constraint(equalToConstant: 35).priority(.required - 1),
avatarImageView.widthAnchor.constraint(equalToConstant: 35).priority(.required - 1),
avatarImageView.topAnchor.constraint(equalTo: avatarContainer.topAnchor),
avatarImageView.leadingAnchor.constraint(equalTo: avatarContainer.leadingAnchor)
2021-04-12 10:31:53 +02:00
])
2021-04-16 15:55:09 +02:00
avatarContainer.addSubview(actionImageBackground)
actionImageBackground.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
actionImageBackground.heightAnchor.constraint(equalToConstant: 24 + NotificationTableViewCell.actionImageBorderWidth).priority(.required - 1),
actionImageBackground.widthAnchor.constraint(equalToConstant: 24 + NotificationTableViewCell.actionImageBorderWidth).priority(.required - 1),
actionImageBackground.bottomAnchor.constraint(equalTo: avatarContainer.bottomAnchor),
actionImageBackground.trailingAnchor.constraint(equalTo: avatarContainer.trailingAnchor)
])
avatarContainer.addSubview(actionImageView)
actionImageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
actionImageView.centerXAnchor.constraint(equalTo: actionImageBackground.centerXAnchor),
actionImageView.centerYAnchor.constraint(equalTo: actionImageBackground.centerYAnchor)
])
nameLabel.translatesAutoresizingMaskIntoConstraints = false
horizontalStackView.addArrangedSubview(nameLabel)
2021-04-16 15:55:09 +02:00
actionLabel.translatesAutoresizingMaskIntoConstraints = false
horizontalStackView.addArrangedSubview(actionLabel)
nameLabel.setContentCompressionResistancePriority(.required - 1, for: .horizontal)
nameLabel.setContentHuggingPriority(.required - 1, for: .horizontal)
2021-04-16 16:58:36 +02:00
actionLabel.setContentHuggingPriority(.defaultLow, for: .horizontal)
2021-04-16 15:55:09 +02:00
containerStackView.addArrangedSubview(horizontalStackView)
buttonStackView.translatesAutoresizingMaskIntoConstraints = false
buttonStackView.axis = .horizontal
buttonStackView.distribution = .fillEqually
acceptButton.translatesAutoresizingMaskIntoConstraints = false
2021-04-27 08:43:38 +02:00
rejectButton.translatesAutoresizingMaskIntoConstraints = false
buttonStackView.addArrangedSubview(acceptButton)
buttonStackView.addArrangedSubview(rejectButton)
containerStackView.addArrangedSubview(buttonStackView)
separatorLine.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(separatorLine)
separatorLineToEdgeLeadingLayoutConstraint = separatorLine.leadingAnchor.constraint(equalTo: contentView.leadingAnchor)
separatorLineToEdgeTrailingLayoutConstraint = separatorLine.trailingAnchor.constraint(equalTo: contentView.trailingAnchor)
separatorLineToMarginLeadingLayoutConstraint = separatorLine.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor)
separatorLineToMarginTrailingLayoutConstraint = separatorLine.trailingAnchor.constraint(equalTo: contentView.readableContentGuide.trailingAnchor)
NSLayoutConstraint.activate([
separatorLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
separatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: contentView)),
])
resetSeparatorLineLayout()
2021-04-12 10:31:53 +02:00
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
2021-04-16 16:58:36 +02:00
actionImageBackground.layer.borderColor = Asset.Colors.Background.systemBackground.color.cgColor
resetSeparatorLineLayout()
2021-04-12 10:31:53 +02:00
}
}
extension NotificationTableViewCell {
private func resetSeparatorLineLayout() {
separatorLineToEdgeLeadingLayoutConstraint.isActive = false
separatorLineToEdgeTrailingLayoutConstraint.isActive = false
separatorLineToMarginLeadingLayoutConstraint.isActive = false
separatorLineToMarginTrailingLayoutConstraint.isActive = false
if traitCollection.userInterfaceIdiom == .phone {
// to edge
NSLayoutConstraint.activate([
separatorLineToEdgeLeadingLayoutConstraint,
separatorLineToEdgeTrailingLayoutConstraint,
])
} else {
if traitCollection.horizontalSizeClass == .compact {
// to edge
NSLayoutConstraint.activate([
separatorLineToEdgeLeadingLayoutConstraint,
separatorLineToEdgeTrailingLayoutConstraint,
])
} else {
// to margin
NSLayoutConstraint.activate([
separatorLineToMarginLeadingLayoutConstraint,
separatorLineToMarginTrailingLayoutConstraint,
])
}
}
}
}