feat: using replica status view in compose scene
This commit is contained in:
parent
b435857214
commit
65887f963a
|
@ -193,7 +193,6 @@
|
|||
DB03F7F026899097007B274C /* ComposeStatusContentTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB03F7EF26899097007B274C /* ComposeStatusContentTableViewCell.swift */; };
|
||||
DB03F7F32689AEA3007B274C /* ComposeRepliedToStatusContentTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB03F7F22689AEA3007B274C /* ComposeRepliedToStatusContentTableViewCell.swift */; };
|
||||
DB03F7F52689B782007B274C /* ComposeTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB03F7F42689B782007B274C /* ComposeTableView.swift */; };
|
||||
DB040ECD26526EA600BEE9D8 /* ComposeCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB040ECC26526EA600BEE9D8 /* ComposeCollectionView.swift */; };
|
||||
DB040ED126538E3D00BEE9D8 /* Trie.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB040ED026538E3C00BEE9D8 /* Trie.swift */; };
|
||||
DB084B5725CBC56C00F898ED /* Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB084B5625CBC56C00F898ED /* Status.swift */; };
|
||||
DB0AC6FC25CD02E600D75117 /* APIService+Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0AC6FB25CD02E600D75117 /* APIService+Instance.swift */; };
|
||||
|
@ -232,6 +231,7 @@
|
|||
DB3667A4268AE2370027D07F /* ComposeStatusPollTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3667A3268AE2370027D07F /* ComposeStatusPollTableViewCell.swift */; };
|
||||
DB3667A6268AE2620027D07F /* ComposeStatusPollSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3667A5268AE2620027D07F /* ComposeStatusPollSection.swift */; };
|
||||
DB3667A8268AE2900027D07F /* ComposeStatusPollItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3667A7268AE2900027D07F /* ComposeStatusPollItem.swift */; };
|
||||
DB3667CA268B14A80027D07F /* ReplicaStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3667C9268B14A80027D07F /* ReplicaStatusView.swift */; };
|
||||
DB3D0FF325BAA61700EAA174 /* AlamofireImage in Frameworks */ = {isa = PBXBuildFile; productRef = DB3D0FF225BAA61700EAA174 /* AlamofireImage */; };
|
||||
DB3D100D25BAA75E00EAA174 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = DB3D100F25BAA75E00EAA174 /* Localizable.strings */; };
|
||||
DB427DD625BAA00100D1B89D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB427DD525BAA00100D1B89D /* AppDelegate.swift */; };
|
||||
|
@ -811,7 +811,6 @@
|
|||
DB03F7EF26899097007B274C /* ComposeStatusContentTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusContentTableViewCell.swift; sourceTree = "<group>"; };
|
||||
DB03F7F22689AEA3007B274C /* ComposeRepliedToStatusContentTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeRepliedToStatusContentTableViewCell.swift; sourceTree = "<group>"; };
|
||||
DB03F7F42689B782007B274C /* ComposeTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeTableView.swift; sourceTree = "<group>"; };
|
||||
DB040ECC26526EA600BEE9D8 /* ComposeCollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeCollectionView.swift; sourceTree = "<group>"; };
|
||||
DB040ED026538E3C00BEE9D8 /* Trie.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Trie.swift; sourceTree = "<group>"; };
|
||||
DB084B5625CBC56C00F898ED /* Status.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Status.swift; sourceTree = "<group>"; };
|
||||
DB0AC6FB25CD02E600D75117 /* APIService+Instance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Instance.swift"; sourceTree = "<group>"; };
|
||||
|
@ -853,6 +852,7 @@
|
|||
DB3667A3268AE2370027D07F /* ComposeStatusPollTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusPollTableViewCell.swift; sourceTree = "<group>"; };
|
||||
DB3667A5268AE2620027D07F /* ComposeStatusPollSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusPollSection.swift; sourceTree = "<group>"; };
|
||||
DB3667A7268AE2900027D07F /* ComposeStatusPollItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusPollItem.swift; sourceTree = "<group>"; };
|
||||
DB3667C9268B14A80027D07F /* ReplicaStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplicaStatusView.swift; sourceTree = "<group>"; };
|
||||
DB3D0FED25BAA42200EAA174 /* MastodonSDK */ = {isa = PBXFileReference; lastKnownFileType = folder; path = MastodonSDK; sourceTree = "<group>"; };
|
||||
DB3D100E25BAA75E00EAA174 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
DB427DD225BAA00100D1B89D /* Mastodon.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Mastodon.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
@ -1975,8 +1975,8 @@
|
|||
DB55D32225FB4D320002F825 /* View */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DB3667C9268B14A80027D07F /* ReplicaStatusView.swift */,
|
||||
DB03F7F42689B782007B274C /* ComposeTableView.swift */,
|
||||
DB040ECC26526EA600BEE9D8 /* ComposeCollectionView.swift */,
|
||||
DBA0A11225FB3FC10079C110 /* ComposeToolbarView.swift */,
|
||||
DB8190C52601FF0400020C08 /* AttachmentContainerView.swift */,
|
||||
DB9A486B26032AC1008B817C /* AttachmentContainerView+EmptyStateView.swift */,
|
||||
|
@ -3484,8 +3484,8 @@
|
|||
DB1D842E26552C4D000346B3 /* StatusTableViewControllerNavigateable.swift in Sources */,
|
||||
DB938F1F2624382F00E5B6C1 /* ThreadViewModel+Diffable.swift in Sources */,
|
||||
2D69CFF425CA9E2200C3A1B2 /* LoadMoreConfigurableTableViewContainer.swift in Sources */,
|
||||
DB040ECD26526EA600BEE9D8 /* ComposeCollectionView.swift in Sources */,
|
||||
DB482A4B261340A7008AE74C /* APIService+UserTimeline.swift in Sources */,
|
||||
DB3667CA268B14A80027D07F /* ReplicaStatusView.swift in Sources */,
|
||||
DB427DD825BAA00100D1B89D /* SceneDelegate.swift in Sources */,
|
||||
0F2021FB2613262F000C64BF /* HashtagTimelineViewController.swift in Sources */,
|
||||
DBCC3B30261440A50045B23D /* UITabBarController.swift in Sources */,
|
||||
|
|
|
@ -190,11 +190,8 @@ extension ComposeViewModel: UITableViewDataSource {
|
|||
// set avatar
|
||||
cell.statusView.configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: status.author.avatarImageURL()))
|
||||
// set name username
|
||||
cell.statusView.nameLabel.text = {
|
||||
let author = status.author
|
||||
return author.displayName.isEmpty ? author.username : author.displayName
|
||||
}()
|
||||
cell.statusView.usernameLabel.text = "@" + (status.reblog ?? status).author.acct
|
||||
cell.statusView.nameLabel.configure(content: status.author.displayNameWithFallback, emojiDict: status.author.emojiDict)
|
||||
cell.statusView.usernameLabel.text = "@" + status.author.acct
|
||||
// set text
|
||||
let content = MastodonContent(content: status.content, emojis: status.emojiMeta)
|
||||
do {
|
||||
|
@ -228,6 +225,8 @@ extension ComposeViewModel: UITableViewDataSource {
|
|||
}
|
||||
// configure author
|
||||
ComposeStatusSection.configureStatusContent(cell: cell, attribute: composeStatusAttribute)
|
||||
// configure content warning
|
||||
cell.statusContentWarningEditorView.textView.text = composeStatusAttribute.contentWarningContent.value
|
||||
// bind content warning
|
||||
composeStatusAttribute.isContentWarningComposing
|
||||
.receive(on: DispatchQueue.main)
|
||||
|
@ -235,7 +234,6 @@ extension ComposeViewModel: UITableViewDataSource {
|
|||
guard let cell = cell else { return }
|
||||
guard let tableView = tableView else { return }
|
||||
// self size input cell
|
||||
//tableView.
|
||||
cell.statusContentWarningEditorView.isHidden = !isContentWarningComposing
|
||||
cell.statusContentWarningEditorView.alpha = 0
|
||||
UIView.animate(withDuration: 0.33, delay: 0, options: [.curveEaseOut]) {
|
||||
|
@ -245,19 +243,21 @@ extension ComposeViewModel: UITableViewDataSource {
|
|||
}
|
||||
}
|
||||
.store(in: &cell.disposeBag)
|
||||
|
||||
cell.contentWarningContent
|
||||
.removeDuplicates()
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak tableView, weak self] text in
|
||||
guard let tableView = tableView else { return }
|
||||
guard let self = self else { return }
|
||||
// bind input data
|
||||
self.composeStatusAttribute.contentWarningContent.value = text
|
||||
|
||||
// self size input cell
|
||||
guard let tableView = tableView else { return }
|
||||
UIView.performWithoutAnimation {
|
||||
tableView.beginUpdates()
|
||||
tableView.endUpdates()
|
||||
}
|
||||
// bind input data
|
||||
self.composeStatusAttribute.contentWarningContent.value = text
|
||||
}
|
||||
.store(in: &cell.disposeBag)
|
||||
// configure custom emoji picker
|
||||
|
|
|
@ -12,14 +12,13 @@ final class ComposeRepliedToStatusContentTableViewCell: UITableViewCell {
|
|||
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
|
||||
let statusView = StatusView()
|
||||
let statusView = ReplicaStatusView()
|
||||
|
||||
let framePublisher = PassthroughSubject<CGRect, Never>()
|
||||
|
||||
override func prepareForReuse() {
|
||||
super.prepareForReuse()
|
||||
|
||||
statusView.updateContentWarningDisplay(isHidden: true, animated: false)
|
||||
disposeBag.removeAll()
|
||||
}
|
||||
|
||||
|
@ -46,9 +45,6 @@ extension ComposeRepliedToStatusContentTableViewCell {
|
|||
selectionStyle = .none
|
||||
backgroundColor = .clear
|
||||
|
||||
statusView.actionToolbarContainer.isHidden = true
|
||||
statusView.revealContentWarningButton.isHidden = true
|
||||
|
||||
statusView.translatesAutoresizingMaskIntoConstraints = false
|
||||
contentView.addSubview(statusView)
|
||||
NSLayoutConstraint.activate([
|
||||
|
@ -57,6 +53,8 @@ extension ComposeRepliedToStatusContentTableViewCell {
|
|||
contentView.layoutMarginsGuide.trailingAnchor.constraint(equalTo: statusView.trailingAnchor),
|
||||
contentView.bottomAnchor.constraint(equalTo: statusView.bottomAnchor, constant: 10).identifier("ComposeRepliedToStatusContentCollectionViewCell.contentView.bottom to statusView.bottom"),
|
||||
])
|
||||
|
||||
statusView.headerContainerView.isHidden = true
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,9 +26,9 @@ final class ComposeStatusAttachmentTableViewCell: UITableViewCell {
|
|||
}
|
||||
|
||||
private(set) var collectionViewHeightLayoutConstraint: NSLayoutConstraint!
|
||||
let collectionView: ComposeCollectionView = {
|
||||
let collectionView: UICollectionView = {
|
||||
let collectionViewLayout = ComposeStatusAttachmentTableViewCell.createLayout()
|
||||
let collectionView = ComposeCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||
collectionView.register(ComposeStatusAttachmentCollectionViewCell.self, forCellWithReuseIdentifier: String(describing: ComposeStatusAttachmentCollectionViewCell.self))
|
||||
collectionView.backgroundColor = Asset.Scene.Compose.background.color
|
||||
collectionView.alwaysBounceVertical = true
|
||||
|
|
|
@ -15,7 +15,7 @@ final class ComposeStatusContentTableViewCell: UITableViewCell {
|
|||
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
|
||||
let statusView = StatusView()
|
||||
let statusView = ReplicaStatusView()
|
||||
|
||||
let statusContentWarningEditorView = StatusContentWarningEditorView()
|
||||
|
||||
|
@ -108,12 +108,10 @@ extension ComposeStatusContentTableViewCell {
|
|||
])
|
||||
statusContentWarningEditorView.textView.delegate = self
|
||||
|
||||
statusView.nameTrialingDotLabel.isHidden = true
|
||||
statusView.dateLabel.isHidden = true
|
||||
statusContentWarningEditorView.isHidden = true
|
||||
statusView.statusContainerStackView.isHidden = true
|
||||
statusView.actionToolbarContainer.isHidden = true
|
||||
statusView.revealContentWarningButton.isHidden = true
|
||||
|
||||
statusView.contentMetaText.textView.delegate = self
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -123,8 +121,6 @@ extension ComposeStatusContentTableViewCell: UITextViewDelegate {
|
|||
|
||||
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
|
||||
switch textView {
|
||||
case statusView.contentMetaText.textView:
|
||||
return false
|
||||
case statusContentWarningEditorView.textView:
|
||||
// disable input line break
|
||||
guard text != "\n" else { return false }
|
||||
|
|
|
@ -34,9 +34,9 @@ final class ComposeStatusPollTableViewCell: UITableViewCell {
|
|||
}
|
||||
|
||||
private(set) var collectionViewHeightLayoutConstraint: NSLayoutConstraint!
|
||||
let collectionView: ComposeCollectionView = {
|
||||
let collectionView: UICollectionView = {
|
||||
let collectionViewLayout = ComposeStatusPollTableViewCell.createLayout()
|
||||
let collectionView = ComposeCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||
collectionView.register(ComposeStatusPollOptionCollectionViewCell.self, forCellWithReuseIdentifier: String(describing: ComposeStatusPollOptionCollectionViewCell.self))
|
||||
collectionView.register(ComposeStatusPollOptionAppendEntryCollectionViewCell.self, forCellWithReuseIdentifier: String(describing: ComposeStatusPollOptionAppendEntryCollectionViewCell.self))
|
||||
collectionView.register(ComposeStatusPollExpiresOptionCollectionViewCell.self, forCellWithReuseIdentifier: String(describing: ComposeStatusPollExpiresOptionCollectionViewCell.self))
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
//
|
||||
// ComposeCollectionView.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021-5-17.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
final class ComposeCollectionView: UICollectionView {
|
||||
|
||||
weak var autoCompleteViewController: AutoCompleteViewController?
|
||||
|
||||
// adjust hitTest for auto-complete
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
guard let autoCompleteViewController = autoCompleteViewController else {
|
||||
return super.hitTest(point, with: event)
|
||||
}
|
||||
|
||||
let thePoint = convert(point, to: autoCompleteViewController.view)
|
||||
if let hitView = autoCompleteViewController.view.hitTest(thePoint, with: event) {
|
||||
return hitView
|
||||
} else {
|
||||
return super.hitTest(point, with: event)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,263 @@
|
|||
//
|
||||
// ReplicaStatusView.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021-6-29.
|
||||
//
|
||||
|
||||
import os.log
|
||||
import UIKit
|
||||
import ActiveLabel
|
||||
import FLAnimatedImage
|
||||
import MetaTextView
|
||||
|
||||
final class ReplicaStatusView: UIView {
|
||||
|
||||
static let avatarImageSize = CGSize(width: 42, height: 42)
|
||||
static let avatarImageCornerRadius: CGFloat = 4
|
||||
static let avatarToLabelSpacing: CGFloat = 5
|
||||
static let contentWarningBlurRadius: CGFloat = 12
|
||||
static let containerStackViewSpacing: CGFloat = 10
|
||||
|
||||
let containerStackView = UIStackView()
|
||||
let headerContainerView = UIView()
|
||||
let authorContainerView = UIView()
|
||||
|
||||
static let reblogIconImage: UIImage = {
|
||||
let font = UIFont.systemFont(ofSize: 13, weight: .medium)
|
||||
let configuration = UIImage.SymbolConfiguration(font: font)
|
||||
let image = UIImage(systemName: "arrow.2.squarepath", withConfiguration: configuration)!.withTintColor(Asset.Colors.Label.secondary.color)
|
||||
return image
|
||||
}()
|
||||
|
||||
static let replyIconImage: UIImage = {
|
||||
let font = UIFont.systemFont(ofSize: 13, weight: .medium)
|
||||
let configuration = UIImage.SymbolConfiguration(font: font)
|
||||
let image = UIImage(systemName: "arrowshape.turn.up.left.fill", withConfiguration: configuration)!.withTintColor(Asset.Colors.Label.secondary.color)
|
||||
return image
|
||||
}()
|
||||
|
||||
static func iconAttributedString(image: UIImage) -> NSAttributedString {
|
||||
let attributedString = NSMutableAttributedString()
|
||||
let imageTextAttachment = NSTextAttachment()
|
||||
let imageAttribute = NSAttributedString(attachment: imageTextAttachment)
|
||||
imageTextAttachment.image = image
|
||||
attributedString.append(imageAttribute)
|
||||
return attributedString
|
||||
}
|
||||
|
||||
let headerIconLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.attributedText = StatusView.iconAttributedString(image: StatusView.reblogIconImage)
|
||||
return label
|
||||
}()
|
||||
|
||||
let headerInfoLabel: ActiveLabel = {
|
||||
let label = ActiveLabel(style: .statusHeader)
|
||||
label.text = "Bob reblogged"
|
||||
label.layer.masksToBounds = false
|
||||
return label
|
||||
}()
|
||||
|
||||
let avatarView: UIView = {
|
||||
let view = UIView()
|
||||
view.isAccessibilityElement = true
|
||||
view.accessibilityTraits = .button
|
||||
view.accessibilityLabel = L10n.Common.Controls.Status.showUserProfile
|
||||
return view
|
||||
}()
|
||||
let avatarImageView: UIImageView = FLAnimatedImageView()
|
||||
let avatarStackedContainerButton: AvatarStackContainerButton = AvatarStackContainerButton()
|
||||
|
||||
let nameLabel: ActiveLabel = {
|
||||
let label = ActiveLabel(style: .statusName)
|
||||
return label
|
||||
}()
|
||||
|
||||
let nameTrialingDotLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.textColor = Asset.Colors.Label.secondary.color
|
||||
label.font = .systemFont(ofSize: 17)
|
||||
label.text = "·"
|
||||
label.isAccessibilityElement = false
|
||||
return label
|
||||
}()
|
||||
|
||||
let usernameLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .systemFont(ofSize: 15, weight: .regular)
|
||||
label.textColor = Asset.Colors.Label.secondary.color
|
||||
label.text = "@alice"
|
||||
label.isAccessibilityElement = false
|
||||
return label
|
||||
}()
|
||||
|
||||
let dateLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .systemFont(ofSize: 13, weight: .regular)
|
||||
label.textColor = Asset.Colors.Label.secondary.color
|
||||
label.text = "1d"
|
||||
return label
|
||||
}()
|
||||
|
||||
let contentMetaText: MetaText = {
|
||||
let metaText = MetaText()
|
||||
metaText.textView.backgroundColor = .clear
|
||||
metaText.textView.isEditable = false
|
||||
metaText.textView.isSelectable = false
|
||||
metaText.textView.isScrollEnabled = false
|
||||
metaText.textView.textContainer.lineFragmentPadding = 0
|
||||
metaText.textView.textContainerInset = .zero
|
||||
metaText.textView.layer.masksToBounds = false
|
||||
return metaText
|
||||
}()
|
||||
|
||||
let statusContainerStackView = UIStackView()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
_init()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
_init()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ReplicaStatusView {
|
||||
private func _init() {
|
||||
// container: [reblog | author | status | action toolbar]
|
||||
// note: do not set spacing for nested stackView to avoid SDK layout conflict issue
|
||||
containerStackView.axis = .vertical
|
||||
// containerStackView.spacing = 10
|
||||
containerStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(containerStackView)
|
||||
NSLayoutConstraint.activate([
|
||||
containerStackView.topAnchor.constraint(equalTo: topAnchor),
|
||||
containerStackView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
trailingAnchor.constraint(equalTo: containerStackView.trailingAnchor),
|
||||
bottomAnchor.constraint(equalTo: containerStackView.bottomAnchor),
|
||||
])
|
||||
containerStackView.setContentHuggingPriority(.required - 1, for: .vertical)
|
||||
containerStackView.setContentCompressionResistancePriority(.required - 1, for: .vertical)
|
||||
|
||||
// header container: [icon | info]
|
||||
let headerContainerStackView = UIStackView()
|
||||
headerContainerStackView.axis = .horizontal
|
||||
headerContainerStackView.spacing = 4
|
||||
headerContainerStackView.addArrangedSubview(headerIconLabel)
|
||||
headerContainerStackView.addArrangedSubview(headerInfoLabel)
|
||||
headerIconLabel.setContentHuggingPriority(.defaultHigh, for: .horizontal)
|
||||
|
||||
headerContainerStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
headerContainerView.addSubview(headerContainerStackView)
|
||||
NSLayoutConstraint.activate([
|
||||
headerContainerStackView.topAnchor.constraint(equalTo: headerContainerView.topAnchor),
|
||||
headerContainerStackView.leadingAnchor.constraint(equalTo: headerContainerView.leadingAnchor),
|
||||
headerContainerStackView.trailingAnchor.constraint(equalTo: headerContainerView.trailingAnchor),
|
||||
headerContainerView.bottomAnchor.constraint(equalTo: headerContainerStackView.bottomAnchor, constant: StatusView.containerStackViewSpacing).priority(.defaultHigh),
|
||||
])
|
||||
containerStackView.addArrangedSubview(headerContainerView)
|
||||
defer {
|
||||
containerStackView.bringSubviewToFront(headerContainerView)
|
||||
}
|
||||
|
||||
// author container: [avatar | author meta container | reveal button]
|
||||
let authorContainerStackView = UIStackView()
|
||||
authorContainerStackView.axis = .horizontal
|
||||
authorContainerStackView.spacing = StatusView.avatarToLabelSpacing
|
||||
authorContainerStackView.distribution = .fill
|
||||
|
||||
// avatar
|
||||
avatarView.translatesAutoresizingMaskIntoConstraints = false
|
||||
authorContainerStackView.addArrangedSubview(avatarView)
|
||||
NSLayoutConstraint.activate([
|
||||
avatarView.widthAnchor.constraint(equalToConstant: StatusView.avatarImageSize.width).priority(.required - 1),
|
||||
avatarView.heightAnchor.constraint(equalToConstant: StatusView.avatarImageSize.height).priority(.required - 1),
|
||||
])
|
||||
avatarImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
avatarView.addSubview(avatarImageView)
|
||||
NSLayoutConstraint.activate([
|
||||
avatarImageView.topAnchor.constraint(equalTo: avatarView.topAnchor),
|
||||
avatarImageView.leadingAnchor.constraint(equalTo: avatarView.leadingAnchor),
|
||||
avatarImageView.trailingAnchor.constraint(equalTo: avatarView.trailingAnchor),
|
||||
avatarImageView.bottomAnchor.constraint(equalTo: avatarView.bottomAnchor),
|
||||
])
|
||||
avatarStackedContainerButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
avatarView.addSubview(avatarStackedContainerButton)
|
||||
NSLayoutConstraint.activate([
|
||||
avatarStackedContainerButton.topAnchor.constraint(equalTo: avatarView.topAnchor),
|
||||
avatarStackedContainerButton.leadingAnchor.constraint(equalTo: avatarView.leadingAnchor),
|
||||
avatarStackedContainerButton.trailingAnchor.constraint(equalTo: avatarView.trailingAnchor),
|
||||
avatarStackedContainerButton.bottomAnchor.constraint(equalTo: avatarView.bottomAnchor),
|
||||
])
|
||||
|
||||
// author meta container: [title container | subtitle container]
|
||||
let authorMetaContainerStackView = UIStackView()
|
||||
authorContainerStackView.addArrangedSubview(authorMetaContainerStackView)
|
||||
authorMetaContainerStackView.axis = .vertical
|
||||
authorMetaContainerStackView.spacing = 4
|
||||
|
||||
// title container: [display name | "·" | date | padding]
|
||||
let titleContainerStackView = UIStackView()
|
||||
authorMetaContainerStackView.addArrangedSubview(titleContainerStackView)
|
||||
titleContainerStackView.axis = .horizontal
|
||||
titleContainerStackView.spacing = 4
|
||||
nameLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||
titleContainerStackView.addArrangedSubview(nameLabel)
|
||||
NSLayoutConstraint.activate([
|
||||
nameLabel.heightAnchor.constraint(equalToConstant: 22).priority(.defaultHigh),
|
||||
])
|
||||
titleContainerStackView.alignment = .firstBaseline
|
||||
titleContainerStackView.addArrangedSubview(nameTrialingDotLabel)
|
||||
titleContainerStackView.addArrangedSubview(dateLabel)
|
||||
titleContainerStackView.addArrangedSubview(UIView()) // padding
|
||||
nameLabel.setContentHuggingPriority(.defaultHigh + 1, for: .horizontal)
|
||||
nameTrialingDotLabel.setContentHuggingPriority(.defaultHigh + 2, for: .horizontal)
|
||||
nameTrialingDotLabel.setContentCompressionResistancePriority(.required - 2, for: .horizontal)
|
||||
dateLabel.setContentHuggingPriority(.defaultHigh, for: .horizontal)
|
||||
dateLabel.setContentCompressionResistancePriority(.required - 1, for: .horizontal)
|
||||
|
||||
// subtitle container: [username]
|
||||
let subtitleContainerStackView = UIStackView()
|
||||
authorMetaContainerStackView.addArrangedSubview(subtitleContainerStackView)
|
||||
subtitleContainerStackView.axis = .horizontal
|
||||
subtitleContainerStackView.addArrangedSubview(usernameLabel)
|
||||
|
||||
authorContainerStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
authorContainerView.addSubview(authorContainerStackView)
|
||||
NSLayoutConstraint.activate([
|
||||
authorContainerStackView.topAnchor.constraint(equalTo: authorContainerView.topAnchor),
|
||||
authorContainerStackView.leadingAnchor.constraint(equalTo: authorContainerView.leadingAnchor),
|
||||
authorContainerStackView.trailingAnchor.constraint(equalTo: authorContainerView.trailingAnchor),
|
||||
authorContainerView.bottomAnchor.constraint(equalTo: authorContainerStackView.bottomAnchor, constant: StatusView.containerStackViewSpacing).priority(.defaultHigh),
|
||||
])
|
||||
containerStackView.addArrangedSubview(authorContainerView)
|
||||
|
||||
// status container: [status]
|
||||
containerStackView.addArrangedSubview(statusContainerStackView)
|
||||
statusContainerStackView.axis = .vertical
|
||||
statusContainerStackView.spacing = 10
|
||||
|
||||
// avoid overlay behind other views
|
||||
defer {
|
||||
containerStackView.bringSubviewToFront(authorContainerView)
|
||||
}
|
||||
|
||||
// status
|
||||
statusContainerStackView.addArrangedSubview(contentMetaText.textView)
|
||||
contentMetaText.textView.setContentCompressionResistancePriority(.required - 1, for: .vertical)
|
||||
|
||||
avatarStackedContainerButton.isHidden = true
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - AvatarConfigurableView
|
||||
extension ReplicaStatusView: AvatarConfigurableView {
|
||||
static var configurableAvatarImageSize: CGSize { return Self.avatarImageSize }
|
||||
static var configurableAvatarImageCornerRadius: CGFloat { return 4 }
|
||||
var configurableAvatarImageView: UIImageView? { avatarImageView }
|
||||
var configurableAvatarButton: UIButton? { nil }
|
||||
}
|
|
@ -207,7 +207,6 @@ final class StatusView: UIView {
|
|||
return actionToolbarContainer
|
||||
}()
|
||||
|
||||
//let activeTextLabel = ActiveLabel(style: .default)
|
||||
let contentMetaText: MetaText = {
|
||||
let metaText = MetaText()
|
||||
metaText.textView.backgroundColor = .clear
|
||||
|
|
Loading…
Reference in New Issue