217 lines
8.7 KiB
Swift
217 lines
8.7 KiB
Swift
//
|
|
// ProfileFieldsView.swift
|
|
// Tusker
|
|
//
|
|
// Created by Shadowfacts on 11/4/22.
|
|
// Copyright © 2022 Shadowfacts. All rights reserved.
|
|
//
|
|
|
|
import UIKit
|
|
import Pachyderm
|
|
|
|
class ProfileFieldsView: UIView {
|
|
|
|
weak var delegate: ProfileHeaderViewDelegate?
|
|
|
|
private var fields = [Account.Field]()
|
|
|
|
private var fieldViews: [(EmojiLabel, ProfileFieldValueView, UIView)] = []
|
|
private var fieldConstraints: [NSLayoutConstraint] = []
|
|
private lazy var dividerLayoutGuide: UILayoutGuide = {
|
|
let guide = UILayoutGuide()
|
|
addLayoutGuide(guide)
|
|
guide.widthAnchor.constraint(equalToConstant: 8).isActive = true
|
|
let centerDividerConstraint = guide.centerXAnchor.constraint(equalTo: centerXAnchor)
|
|
centerDividerConstraint.priority = .defaultHigh
|
|
centerDividerConstraint.isActive = true
|
|
return guide
|
|
}()
|
|
private var dividerXConstraint: NSLayoutConstraint?
|
|
private var boundsObservation: NSKeyValueObservation?
|
|
|
|
private var isUsingSingleColumn: Bool = false
|
|
private var needsSingleColumn: Bool {
|
|
traitCollection.horizontalSizeClass == .compact && traitCollection.preferredContentSizeCategory > .extraLarge
|
|
}
|
|
|
|
override var accessibilityElements: [Any]? {
|
|
get {
|
|
fieldViews.flatMap { [$0.0, $0.1] }
|
|
}
|
|
set {}
|
|
}
|
|
|
|
override init(frame: CGRect) {
|
|
super.init(frame: frame)
|
|
commonInit()
|
|
}
|
|
|
|
required init?(coder: NSCoder) {
|
|
super.init(coder: coder)
|
|
commonInit()
|
|
}
|
|
|
|
private func commonInit() {
|
|
boundsObservation = observe(\.bounds, changeHandler: { [unowned self] _, _ in
|
|
self.setNeedsUpdateConstraints()
|
|
})
|
|
}
|
|
|
|
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
|
super.traitCollectionDidChange(previousTraitCollection)
|
|
if isUsingSingleColumn != needsSingleColumn {
|
|
configureFields()
|
|
}
|
|
}
|
|
|
|
func updateUI(account: AccountMO) {
|
|
isHidden = account.fields.isEmpty
|
|
guard !account.fields.isEmpty,
|
|
fields != account.fields else {
|
|
return
|
|
}
|
|
fields = account.fields
|
|
|
|
for (name, value, fieldContainer) in fieldViews {
|
|
name.removeFromSuperview()
|
|
value.removeFromSuperview()
|
|
fieldContainer.removeFromSuperview()
|
|
}
|
|
fieldViews = []
|
|
|
|
for (index, field) in account.fields.enumerated() {
|
|
let nameLabel = EmojiLabel()
|
|
nameLabel.text = field.name
|
|
nameLabel.font = .preferredFont(forTextStyle: .body).withTraits(.traitBold)!
|
|
nameLabel.adjustsFontForContentSizeCategory = true
|
|
nameLabel.numberOfLines = 0
|
|
nameLabel.lineBreakMode = .byWordWrapping
|
|
nameLabel.showsExpansionTextWhenTruncated = true
|
|
nameLabel.setEmojis(account.emojis, identifier: account.id)
|
|
nameLabel.setContentHuggingPriority(.defaultHigh, for: .vertical)
|
|
|
|
let valueView = ProfileFieldValueView(field: field, account: account)
|
|
valueView.navigationDelegate = delegate
|
|
valueView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
|
|
|
let container = UIView()
|
|
container.translatesAutoresizingMaskIntoConstraints = false
|
|
addSubview(container)
|
|
|
|
nameLabel.translatesAutoresizingMaskIntoConstraints = false
|
|
container.addSubview(nameLabel)
|
|
valueView.translatesAutoresizingMaskIntoConstraints = false
|
|
container.addSubview(valueView)
|
|
|
|
if index % 2 == 0 {
|
|
container.backgroundColor = .secondarySystemFill
|
|
} else {
|
|
container.backgroundColor = .quaternarySystemFill
|
|
}
|
|
if index == 0 || index == fields.count - 1 {
|
|
if fields.count > 1 && index == 0 {
|
|
container.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
|
|
} else if fields.count > 1 && index == fields.count - 1 {
|
|
container.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
|
|
}
|
|
container.layer.cornerRadius = 8
|
|
container.layer.cornerCurve = .continuous
|
|
}
|
|
|
|
fieldViews.append((nameLabel, valueView, container))
|
|
}
|
|
|
|
configureFields()
|
|
}
|
|
|
|
@objc private func configureFields() {
|
|
guard !isHidden else {
|
|
return
|
|
}
|
|
|
|
isUsingSingleColumn = needsSingleColumn
|
|
|
|
NSLayoutConstraint.deactivate(fieldConstraints)
|
|
fieldConstraints = []
|
|
|
|
var prevContainer: UIView?
|
|
|
|
for (name, value, container) in fieldViews {
|
|
fieldConstraints.append(contentsOf: [
|
|
container.leadingAnchor.constraint(equalTo: leadingAnchor),
|
|
container.trailingAnchor.constraint(equalTo: trailingAnchor),
|
|
])
|
|
|
|
if needsSingleColumn {
|
|
name.textAlignment = .natural
|
|
value.setTextAlignment(.natural)
|
|
|
|
fieldConstraints.append(contentsOf: [
|
|
name.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 4),
|
|
name.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: -4),
|
|
name.topAnchor.constraint(equalTo: container.topAnchor, constant: 4),
|
|
|
|
value.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 4),
|
|
value.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: -4),
|
|
value.topAnchor.constraint(equalTo: name.bottomAnchor),
|
|
value.bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: -4),
|
|
])
|
|
} else {
|
|
name.textAlignment = .right
|
|
value.setTextAlignment(.left)
|
|
|
|
fieldConstraints.append(contentsOf: [
|
|
container.heightAnchor.constraint(greaterThanOrEqualToConstant: 32),
|
|
|
|
name.leadingAnchor.constraint(greaterThanOrEqualTo: container.leadingAnchor, constant: 4),
|
|
name.trailingAnchor.constraint(equalTo: dividerLayoutGuide.leadingAnchor),
|
|
name.topAnchor.constraint(equalTo: container.topAnchor, constant: 4),
|
|
name.bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: -4),
|
|
|
|
value.leadingAnchor.constraint(equalTo: dividerLayoutGuide.trailingAnchor),
|
|
value.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: -4),
|
|
value.topAnchor.constraint(equalTo: container.topAnchor, constant: 4),
|
|
value.bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: -4),
|
|
])
|
|
}
|
|
|
|
let containerTopConstraint = container.topAnchor.constraint(equalTo: prevContainer?.bottomAnchor ?? topAnchor)
|
|
fieldConstraints.append(containerTopConstraint)
|
|
prevContainer = container
|
|
}
|
|
|
|
if let prevContainer {
|
|
let lastContainerBottomConstraint = prevContainer.bottomAnchor.constraint(equalTo: bottomAnchor)
|
|
fieldConstraints.append(lastContainerBottomConstraint)
|
|
}
|
|
|
|
NSLayoutConstraint.activate(fieldConstraints)
|
|
}
|
|
|
|
override func updateConstraints() {
|
|
if !needsSingleColumn,
|
|
!fieldViews.isEmpty {
|
|
let maxNameWidth = fieldViews.map {
|
|
$0.0.sizeThatFits(UIView.layoutFittingCompressedSize).width
|
|
}.max()!
|
|
let maxValueWidth = fieldViews.map {
|
|
$0.1.sizeThatFits(UIView.layoutFittingCompressedSize).width
|
|
}.max()!
|
|
|
|
let defaultWidth = (bounds.width - 8) / 2
|
|
|
|
dividerXConstraint?.isActive = false
|
|
if maxNameWidth > defaultWidth && maxValueWidth < defaultWidth {
|
|
dividerXConstraint = dividerLayoutGuide.leadingAnchor.constraint(equalTo: leadingAnchor, constant: min(maxNameWidth, bounds.width * 2 / 3))
|
|
dividerXConstraint!.isActive = true
|
|
} else if maxNameWidth < defaultWidth && maxValueWidth > defaultWidth {
|
|
dividerXConstraint = dividerLayoutGuide.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -min(maxValueWidth, bounds.width * 2 / 3))
|
|
dividerXConstraint!.isActive = true
|
|
}
|
|
}
|
|
|
|
super.updateConstraints()
|
|
}
|
|
|
|
}
|