Account header progress
This commit is contained in:
parent
a4b94bf33c
commit
67e1a59ffd
|
@ -1,5 +1,6 @@
|
||||||
// Copyright © 2020 Metabolist. All rights reserved.
|
// Copyright © 2020 Metabolist. All rights reserved.
|
||||||
|
|
||||||
|
"account.field.verified" = "Verified %@";
|
||||||
"account.statuses" = "Posts";
|
"account.statuses" = "Posts";
|
||||||
"account.statuses-and-replies" = "Posts & Replies";
|
"account.statuses-and-replies" = "Posts & Replies";
|
||||||
"account.media" = "Media";
|
"account.media" = "Media";
|
||||||
|
@ -32,6 +33,7 @@
|
||||||
"lists.new-list-title" = "New List Title";
|
"lists.new-list-title" = "New List Title";
|
||||||
"load-more" = "Load More";
|
"load-more" = "Load More";
|
||||||
"messages" = "Messages";
|
"messages" = "Messages";
|
||||||
|
"ok" = "OK";
|
||||||
"pending.pending-confirmation" = "Your account is pending confirmation";
|
"pending.pending-confirmation" = "Your account is pending confirmation";
|
||||||
"preferences" = "Preferences";
|
"preferences" = "Preferences";
|
||||||
"preferences.app" = "App Preferences";
|
"preferences.app" = "App Preferences";
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
D00702312555F4AE00F38136 /* ConversationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00702302555F4AE00F38136 /* ConversationView.swift */; };
|
D00702312555F4AE00F38136 /* ConversationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00702302555F4AE00F38136 /* ConversationView.swift */; };
|
||||||
D00702362555F4C500F38136 /* ConversationContentConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00702352555F4C500F38136 /* ConversationContentConfiguration.swift */; };
|
D00702362555F4C500F38136 /* ConversationContentConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00702352555F4C500F38136 /* ConversationContentConfiguration.swift */; };
|
||||||
D007023E25562A2800F38136 /* ConversationAvatarsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D007023D25562A2800F38136 /* ConversationAvatarsView.swift */; };
|
D007023E25562A2800F38136 /* ConversationAvatarsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D007023D25562A2800F38136 /* ConversationAvatarsView.swift */; };
|
||||||
|
D0070252255921B100F38136 /* AccountFieldView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0070251255921B100F38136 /* AccountFieldView.swift */; };
|
||||||
D00CB2ED2533ACC00080096B /* StatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00CB2EC2533ACC00080096B /* StatusView.swift */; };
|
D00CB2ED2533ACC00080096B /* StatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00CB2EC2533ACC00080096B /* StatusView.swift */; };
|
||||||
D01C6FAC252024BD003D0300 /* Array+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C6FAB252024BD003D0300 /* Array+Extensions.swift */; };
|
D01C6FAC252024BD003D0300 /* Array+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C6FAB252024BD003D0300 /* Array+Extensions.swift */; };
|
||||||
D01EF22425182B1F00650C6B /* AccountHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01EF22325182B1F00650C6B /* AccountHeaderView.swift */; };
|
D01EF22425182B1F00650C6B /* AccountHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01EF22325182B1F00650C6B /* AccountHeaderView.swift */; };
|
||||||
|
@ -124,6 +125,7 @@
|
||||||
D00702302555F4AE00F38136 /* ConversationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationView.swift; sourceTree = "<group>"; };
|
D00702302555F4AE00F38136 /* ConversationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationView.swift; sourceTree = "<group>"; };
|
||||||
D00702352555F4C500F38136 /* ConversationContentConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationContentConfiguration.swift; sourceTree = "<group>"; };
|
D00702352555F4C500F38136 /* ConversationContentConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationContentConfiguration.swift; sourceTree = "<group>"; };
|
||||||
D007023D25562A2800F38136 /* ConversationAvatarsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationAvatarsView.swift; sourceTree = "<group>"; };
|
D007023D25562A2800F38136 /* ConversationAvatarsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationAvatarsView.swift; sourceTree = "<group>"; };
|
||||||
|
D0070251255921B100F38136 /* AccountFieldView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountFieldView.swift; sourceTree = "<group>"; };
|
||||||
D00CB2EC2533ACC00080096B /* StatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusView.swift; sourceTree = "<group>"; };
|
D00CB2EC2533ACC00080096B /* StatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusView.swift; sourceTree = "<group>"; };
|
||||||
D01C6FAB252024BD003D0300 /* Array+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Extensions.swift"; sourceTree = "<group>"; };
|
D01C6FAB252024BD003D0300 /* Array+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Extensions.swift"; sourceTree = "<group>"; };
|
||||||
D01EF22325182B1F00650C6B /* AccountHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountHeaderView.swift; sourceTree = "<group>"; };
|
D01EF22325182B1F00650C6B /* AccountHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountHeaderView.swift; sourceTree = "<group>"; };
|
||||||
|
@ -342,6 +344,7 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
D0F0B112251A86A000942152 /* AccountContentConfiguration.swift */,
|
D0F0B112251A86A000942152 /* AccountContentConfiguration.swift */,
|
||||||
|
D0070251255921B100F38136 /* AccountFieldView.swift */,
|
||||||
D01EF22325182B1F00650C6B /* AccountHeaderView.swift */,
|
D01EF22325182B1F00650C6B /* AccountHeaderView.swift */,
|
||||||
D0F0B125251A90F400942152 /* AccountListCell.swift */,
|
D0F0B125251A90F400942152 /* AccountListCell.swift */,
|
||||||
D0F0B10D251A868200942152 /* AccountView.swift */,
|
D0F0B10D251A868200942152 /* AccountView.swift */,
|
||||||
|
@ -674,6 +677,7 @@
|
||||||
D00702312555F4AE00F38136 /* ConversationView.swift in Sources */,
|
D00702312555F4AE00F38136 /* ConversationView.swift in Sources */,
|
||||||
D0BEB21124FA2A91001B0F04 /* EditFilterView.swift in Sources */,
|
D0BEB21124FA2A91001B0F04 /* EditFilterView.swift in Sources */,
|
||||||
D08B8D4A253FC36500B1EBEF /* ImageNavigationController.swift in Sources */,
|
D08B8D4A253FC36500B1EBEF /* ImageNavigationController.swift in Sources */,
|
||||||
|
D0070252255921B100F38136 /* AccountFieldView.swift in Sources */,
|
||||||
D0030982250C6C8500EACB32 /* URL+Extensions.swift in Sources */,
|
D0030982250C6C8500EACB32 /* URL+Extensions.swift in Sources */,
|
||||||
D00CB2ED2533ACC00080096B /* StatusView.swift in Sources */,
|
D00CB2ED2533ACC00080096B /* StatusView.swift in Sources */,
|
||||||
D0A1F4F7252E7D4B004435BF /* TableViewDataSource.swift in Sources */,
|
D0A1F4F7252E7D4B004435BF /* TableViewDataSource.swift in Sources */,
|
||||||
|
|
|
@ -34,6 +34,8 @@ public extension AccountViewModel {
|
||||||
|
|
||||||
var accountName: String { "@".appending(accountService.account.acct) }
|
var accountName: String { "@".appending(accountService.account.acct) }
|
||||||
|
|
||||||
|
var fields: [Account.Field] { accountService.account.fields }
|
||||||
|
|
||||||
var note: NSAttributedString { accountService.account.note.attributed }
|
var note: NSAttributedString { accountService.account.note.attributed }
|
||||||
|
|
||||||
var emoji: [Emoji] { accountService.account.emojis }
|
var emoji: [Emoji] { accountService.account.emojis }
|
||||||
|
|
|
@ -49,6 +49,12 @@ public extension ProfileViewModel {
|
||||||
|
|
||||||
imagePresentationsSubject.send(accountViewModel.headerURL)
|
imagePresentationsSubject.send(accountViewModel.headerURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func presentAvatar() {
|
||||||
|
guard let accountViewModel = accountViewModel else { return }
|
||||||
|
|
||||||
|
imagePresentationsSubject.send(accountViewModel.avatarURL(profile: true))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ProfileViewModel: CollectionViewModel {
|
extension ProfileViewModel: CollectionViewModel {
|
||||||
|
|
|
@ -0,0 +1,154 @@
|
||||||
|
// Copyright © 2020 Metabolist. All rights reserved.
|
||||||
|
|
||||||
|
import Mastodon
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
final class AccountFieldView: UIView {
|
||||||
|
let nameLabel = UILabel()
|
||||||
|
let valueTextView = TouchFallthroughTextView()
|
||||||
|
|
||||||
|
// swiftlint:disable:next function_body_length
|
||||||
|
init(field: Account.Field, emoji: [Emoji]) {
|
||||||
|
super.init(frame: .zero)
|
||||||
|
|
||||||
|
let verified = field.verifiedAt != nil
|
||||||
|
|
||||||
|
backgroundColor = .systemBackground
|
||||||
|
|
||||||
|
let nameBackgroundView = UIView()
|
||||||
|
|
||||||
|
addSubview(nameBackgroundView)
|
||||||
|
nameBackgroundView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
nameBackgroundView.backgroundColor = .secondarySystemBackground
|
||||||
|
|
||||||
|
let valueBackgroundView = UIView()
|
||||||
|
|
||||||
|
addSubview(valueBackgroundView)
|
||||||
|
valueBackgroundView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
valueBackgroundView.backgroundColor = verified
|
||||||
|
? UIColor.systemGreen.withAlphaComponent(0.25)
|
||||||
|
: .systemBackground
|
||||||
|
|
||||||
|
addSubview(nameLabel)
|
||||||
|
nameLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
nameLabel.numberOfLines = 0
|
||||||
|
nameLabel.font = .preferredFont(forTextStyle: .headline)
|
||||||
|
nameLabel.textAlignment = .center
|
||||||
|
nameLabel.textColor = .secondaryLabel
|
||||||
|
|
||||||
|
let mutableName = NSMutableAttributedString(string: field.name)
|
||||||
|
|
||||||
|
mutableName.insert(emoji: emoji, view: nameLabel)
|
||||||
|
mutableName.resizeAttachments(toLineHeight: nameLabel.font.lineHeight)
|
||||||
|
nameLabel.attributedText = mutableName
|
||||||
|
|
||||||
|
let dividerView = UIView()
|
||||||
|
|
||||||
|
addSubview(dividerView)
|
||||||
|
dividerView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
dividerView.backgroundColor = .separator
|
||||||
|
|
||||||
|
addSubview(valueTextView)
|
||||||
|
valueTextView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
valueTextView.isScrollEnabled = false
|
||||||
|
valueTextView.backgroundColor = .clear
|
||||||
|
|
||||||
|
if verified {
|
||||||
|
valueTextView.linkTextAttributes = [
|
||||||
|
.foregroundColor: UIColor.systemGreen as Any,
|
||||||
|
.underlineColor: UIColor.clear]
|
||||||
|
}
|
||||||
|
|
||||||
|
let valueFont = UIFont.preferredFont(forTextStyle: verified ? .headline : .body)
|
||||||
|
let mutableValue = NSMutableAttributedString(attributedString: field.value.attributed)
|
||||||
|
let valueRange = NSRange(location: 0, length: mutableValue.length)
|
||||||
|
|
||||||
|
mutableValue.removeAttribute(.font, range: valueRange)
|
||||||
|
mutableValue.addAttributes(
|
||||||
|
[.font: valueFont as Any,
|
||||||
|
.foregroundColor: UIColor.label],
|
||||||
|
range: valueRange)
|
||||||
|
mutableValue.insert(emoji: emoji, view: valueTextView)
|
||||||
|
mutableValue.resizeAttachments(toLineHeight: valueFont.lineHeight)
|
||||||
|
|
||||||
|
valueTextView.attributedText = mutableValue
|
||||||
|
valueTextView.textAlignment = .center
|
||||||
|
|
||||||
|
let checkButton = UIButton()
|
||||||
|
|
||||||
|
checkButton.setImage(
|
||||||
|
UIImage(
|
||||||
|
systemName: "checkmark",
|
||||||
|
withConfiguration: UIImage.SymbolConfiguration(scale: .small)),
|
||||||
|
for: .normal)
|
||||||
|
|
||||||
|
addSubview(checkButton)
|
||||||
|
checkButton.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
checkButton.tintColor = .systemGreen
|
||||||
|
checkButton.isHidden = !verified
|
||||||
|
checkButton.showsMenuAsPrimaryAction = true
|
||||||
|
|
||||||
|
if let verifiedAt = field.verifiedAt {
|
||||||
|
checkButton.menu = UIMenu(
|
||||||
|
title: String.localizedStringWithFormat(
|
||||||
|
NSLocalizedString("account.field.verified", comment: ""),
|
||||||
|
Self.dateFormatter.string(from: verifiedAt)),
|
||||||
|
options: .displayInline,
|
||||||
|
children: [UIAction(title: NSLocalizedString("ok", comment: "")) { _ in }])
|
||||||
|
}
|
||||||
|
|
||||||
|
let nameLabelBottomConstraint = nameLabel.bottomAnchor.constraint(
|
||||||
|
equalTo: bottomAnchor,
|
||||||
|
constant: -.defaultSpacing)
|
||||||
|
let valueTextViewBottomConstraint = valueTextView.bottomAnchor.constraint(
|
||||||
|
lessThanOrEqualTo: bottomAnchor,
|
||||||
|
constant: -.defaultSpacing)
|
||||||
|
|
||||||
|
for constraint in [nameLabelBottomConstraint, valueTextViewBottomConstraint] {
|
||||||
|
constraint.priority = .justBelowMax
|
||||||
|
}
|
||||||
|
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
nameLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: .defaultSpacing),
|
||||||
|
nameLabel.topAnchor.constraint(equalTo: topAnchor, constant: .defaultSpacing),
|
||||||
|
nameLabelBottomConstraint,
|
||||||
|
dividerView.leadingAnchor.constraint(equalTo: nameLabel.trailingAnchor, constant: .defaultSpacing),
|
||||||
|
dividerView.topAnchor.constraint(equalTo: topAnchor),
|
||||||
|
dividerView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||||
|
dividerView.widthAnchor.constraint(equalToConstant: .hairline),
|
||||||
|
checkButton.leadingAnchor.constraint(equalTo: dividerView.trailingAnchor, constant: .defaultSpacing),
|
||||||
|
valueTextView.leadingAnchor.constraint(
|
||||||
|
equalTo: verified ? checkButton.trailingAnchor : dividerView.trailingAnchor,
|
||||||
|
constant: .defaultSpacing),
|
||||||
|
valueTextView.topAnchor.constraint(greaterThanOrEqualTo: topAnchor, constant: .defaultSpacing),
|
||||||
|
valueTextView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -.defaultSpacing),
|
||||||
|
valueTextViewBottomConstraint,
|
||||||
|
nameLabel.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 1 / 3),
|
||||||
|
checkButton.centerYAnchor.constraint(equalTo: valueTextView.centerYAnchor),
|
||||||
|
valueTextView.centerYAnchor.constraint(equalTo: nameLabel.centerYAnchor),
|
||||||
|
nameBackgroundView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||||
|
nameBackgroundView.topAnchor.constraint(equalTo: topAnchor),
|
||||||
|
nameBackgroundView.trailingAnchor.constraint(equalTo: dividerView.leadingAnchor),
|
||||||
|
nameBackgroundView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||||
|
valueBackgroundView.leadingAnchor.constraint(equalTo: dividerView.trailingAnchor),
|
||||||
|
valueBackgroundView.topAnchor.constraint(equalTo: topAnchor),
|
||||||
|
valueBackgroundView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||||
|
valueBackgroundView.bottomAnchor.constraint(equalTo: bottomAnchor)
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(*, unavailable)
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension AccountFieldView {
|
||||||
|
static let dateFormatter: DateFormatter = {
|
||||||
|
let formatter = DateFormatter()
|
||||||
|
|
||||||
|
formatter.dateStyle = .full
|
||||||
|
|
||||||
|
return formatter
|
||||||
|
}()
|
||||||
|
}
|
|
@ -7,6 +7,11 @@ import ViewModels
|
||||||
final class AccountHeaderView: UIView {
|
final class AccountHeaderView: UIView {
|
||||||
let headerImageView = AnimatedImageView()
|
let headerImageView = AnimatedImageView()
|
||||||
let headerButton = UIButton()
|
let headerButton = UIButton()
|
||||||
|
let avatarImageView = UIImageView()
|
||||||
|
let avatarButton = UIButton()
|
||||||
|
let displayNameLabel = UILabel()
|
||||||
|
let accountLabel = UILabel()
|
||||||
|
let fieldsStackView = UIStackView()
|
||||||
let noteTextView = TouchFallthroughTextView()
|
let noteTextView = TouchFallthroughTextView()
|
||||||
let segmentedControl = UISegmentedControl()
|
let segmentedControl = UISegmentedControl()
|
||||||
|
|
||||||
|
@ -15,6 +20,35 @@ final class AccountHeaderView: UIView {
|
||||||
if let accountViewModel = viewModel?.accountViewModel {
|
if let accountViewModel = viewModel?.accountViewModel {
|
||||||
headerImageView.kf.setImage(with: accountViewModel.headerURL)
|
headerImageView.kf.setImage(with: accountViewModel.headerURL)
|
||||||
headerImageView.tag = accountViewModel.headerURL.hashValue
|
headerImageView.tag = accountViewModel.headerURL.hashValue
|
||||||
|
avatarImageView.kf.setImage(with: accountViewModel.avatarURL(profile: true))
|
||||||
|
avatarImageView.tag = accountViewModel.avatarURL(profile: true).hashValue
|
||||||
|
|
||||||
|
if accountViewModel.displayName.isEmpty {
|
||||||
|
displayNameLabel.isHidden = true
|
||||||
|
} else {
|
||||||
|
let mutableDisplayName = NSMutableAttributedString(string: accountViewModel.displayName)
|
||||||
|
|
||||||
|
mutableDisplayName.insert(emoji: accountViewModel.emoji, view: displayNameLabel)
|
||||||
|
mutableDisplayName.resizeAttachments(toLineHeight: displayNameLabel.font.lineHeight)
|
||||||
|
displayNameLabel.attributedText = mutableDisplayName
|
||||||
|
}
|
||||||
|
|
||||||
|
accountLabel.text = accountViewModel.accountName
|
||||||
|
|
||||||
|
for view in fieldsStackView.arrangedSubviews {
|
||||||
|
fieldsStackView.removeArrangedSubview(view)
|
||||||
|
view.removeFromSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
for field in accountViewModel.fields {
|
||||||
|
let fieldView = AccountFieldView(field: field, emoji: accountViewModel.emoji)
|
||||||
|
|
||||||
|
fieldView.valueTextView.delegate = self
|
||||||
|
|
||||||
|
fieldsStackView.addArrangedSubview(fieldView)
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldsStackView.isHidden = accountViewModel.fields.isEmpty
|
||||||
|
|
||||||
let noteFont = UIFont.preferredFont(forTextStyle: .callout)
|
let noteFont = UIFont.preferredFont(forTextStyle: .callout)
|
||||||
let mutableNote = NSMutableAttributedString(attributedString: accountViewModel.note)
|
let mutableNote = NSMutableAttributedString(attributedString: accountViewModel.note)
|
||||||
|
@ -64,6 +98,8 @@ extension AccountHeaderView: UITextViewDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension AccountHeaderView {
|
private extension AccountHeaderView {
|
||||||
|
static let avatarDimension = CGFloat.avatarDimension * 2
|
||||||
|
|
||||||
// swiftlint:disable:next function_body_length
|
// swiftlint:disable:next function_body_length
|
||||||
func initialSetup() {
|
func initialSetup() {
|
||||||
let baseStackView = UIStackView()
|
let baseStackView = UIStackView()
|
||||||
|
@ -78,17 +114,51 @@ private extension AccountHeaderView {
|
||||||
headerButton.translatesAutoresizingMaskIntoConstraints = false
|
headerButton.translatesAutoresizingMaskIntoConstraints = false
|
||||||
headerButton.setBackgroundImage(.highlightedButtonBackground, for: .highlighted)
|
headerButton.setBackgroundImage(.highlightedButtonBackground, for: .highlighted)
|
||||||
|
|
||||||
headerButton.addAction(
|
headerButton.addAction(UIAction { [weak self] _ in self?.viewModel?.presentHeader() }, for: .touchUpInside)
|
||||||
UIAction { [weak self] _ in self?.viewModel?.presentHeader() },
|
|
||||||
for: .touchUpInside)
|
addSubview(avatarImageView)
|
||||||
|
avatarImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
avatarImageView.contentMode = .scaleAspectFill
|
||||||
|
avatarImageView.clipsToBounds = true
|
||||||
|
avatarImageView.isUserInteractionEnabled = true
|
||||||
|
avatarImageView.layer.cornerRadius = Self.avatarDimension / 2
|
||||||
|
avatarImageView.layer.borderWidth = .compactSpacing
|
||||||
|
avatarImageView.layer.borderColor = UIColor.systemBackground.cgColor
|
||||||
|
|
||||||
|
avatarImageView.addSubview(avatarButton)
|
||||||
|
avatarButton.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
avatarButton.setBackgroundImage(.highlightedButtonBackground, for: .highlighted)
|
||||||
|
|
||||||
|
avatarButton.addAction(UIAction { [weak self] _ in self?.viewModel?.presentAvatar() }, for: .touchUpInside)
|
||||||
|
|
||||||
addSubview(baseStackView)
|
addSubview(baseStackView)
|
||||||
baseStackView.translatesAutoresizingMaskIntoConstraints = false
|
baseStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
baseStackView.axis = .vertical
|
baseStackView.axis = .vertical
|
||||||
|
baseStackView.spacing = .defaultSpacing
|
||||||
|
|
||||||
|
baseStackView.addArrangedSubview(displayNameLabel)
|
||||||
|
displayNameLabel.numberOfLines = 0
|
||||||
|
displayNameLabel.font = .preferredFont(forTextStyle: .headline)
|
||||||
|
displayNameLabel.adjustsFontForContentSizeCategory = true
|
||||||
|
|
||||||
|
baseStackView.addArrangedSubview(accountLabel)
|
||||||
|
accountLabel.numberOfLines = 0
|
||||||
|
accountLabel.font = .preferredFont(forTextStyle: .subheadline)
|
||||||
|
accountLabel.adjustsFontForContentSizeCategory = true
|
||||||
|
accountLabel.textColor = .secondaryLabel
|
||||||
|
|
||||||
|
baseStackView.addArrangedSubview(fieldsStackView)
|
||||||
|
fieldsStackView.axis = .vertical
|
||||||
|
fieldsStackView.spacing = .hairline
|
||||||
|
fieldsStackView.backgroundColor = .separator
|
||||||
|
fieldsStackView.clipsToBounds = true
|
||||||
|
fieldsStackView.layer.borderColor = UIColor.separator.cgColor
|
||||||
|
fieldsStackView.layer.borderWidth = .hairline
|
||||||
|
fieldsStackView.layer.cornerRadius = .defaultCornerRadius
|
||||||
|
|
||||||
|
baseStackView.addArrangedSubview(noteTextView)
|
||||||
noteTextView.isScrollEnabled = false
|
noteTextView.isScrollEnabled = false
|
||||||
noteTextView.delegate = self
|
noteTextView.delegate = self
|
||||||
baseStackView.addArrangedSubview(noteTextView)
|
|
||||||
|
|
||||||
for (index, collection) in ProfileCollection.allCases.enumerated() {
|
for (index, collection) in ProfileCollection.allCases.enumerated() {
|
||||||
segmentedControl.insertSegment(
|
segmentedControl.insertSegment(
|
||||||
|
@ -119,10 +189,18 @@ private extension AccountHeaderView {
|
||||||
headerButton.topAnchor.constraint(equalTo: headerImageView.topAnchor),
|
headerButton.topAnchor.constraint(equalTo: headerImageView.topAnchor),
|
||||||
headerButton.bottomAnchor.constraint(equalTo: headerImageView.bottomAnchor),
|
headerButton.bottomAnchor.constraint(equalTo: headerImageView.bottomAnchor),
|
||||||
headerButton.trailingAnchor.constraint(equalTo: headerImageView.trailingAnchor),
|
headerButton.trailingAnchor.constraint(equalTo: headerImageView.trailingAnchor),
|
||||||
baseStackView.topAnchor.constraint(equalTo: headerImageView.bottomAnchor),
|
avatarImageView.heightAnchor.constraint(equalToConstant: Self.avatarDimension),
|
||||||
|
avatarImageView.widthAnchor.constraint(equalToConstant: Self.avatarDimension),
|
||||||
|
avatarImageView.leadingAnchor.constraint(equalTo: readableContentGuide.leadingAnchor),
|
||||||
|
avatarImageView.centerYAnchor.constraint(equalTo: headerImageView.bottomAnchor),
|
||||||
|
avatarButton.leadingAnchor.constraint(equalTo: avatarImageView.leadingAnchor),
|
||||||
|
avatarButton.topAnchor.constraint(equalTo: avatarImageView.topAnchor),
|
||||||
|
avatarButton.bottomAnchor.constraint(equalTo: avatarImageView.bottomAnchor),
|
||||||
|
avatarButton.trailingAnchor.constraint(equalTo: avatarImageView.trailingAnchor),
|
||||||
|
baseStackView.topAnchor.constraint(equalTo: avatarImageView.bottomAnchor, constant: .defaultSpacing),
|
||||||
baseStackView.leadingAnchor.constraint(equalTo: readableContentGuide.leadingAnchor),
|
baseStackView.leadingAnchor.constraint(equalTo: readableContentGuide.leadingAnchor),
|
||||||
baseStackView.trailingAnchor.constraint(equalTo: readableContentGuide.trailingAnchor),
|
baseStackView.trailingAnchor.constraint(equalTo: readableContentGuide.trailingAnchor),
|
||||||
baseStackView.bottomAnchor.constraint(equalTo: bottomAnchor)
|
baseStackView.bottomAnchor.constraint(equalTo: readableContentGuide.bottomAnchor)
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue