mirror of
https://github.com/metabolist/metatext.git
synced 2024-11-25 09:41:00 +00:00
Cell refactor
This commit is contained in:
parent
5275ee0d21
commit
bd1659af6a
8 changed files with 366 additions and 680 deletions
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
D0030982250C6C8500EACB32 /* URL+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0030981250C6C8500EACB32 /* URL+Extensions.swift */; };
|
D0030982250C6C8500EACB32 /* URL+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0030981250C6C8500EACB32 /* URL+Extensions.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 */; };
|
||||||
D01F41D924F880C400D55A2D /* TouchFallthroughTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F41D624F880C400D55A2D /* TouchFallthroughTextView.swift */; };
|
D01F41D924F880C400D55A2D /* TouchFallthroughTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F41D624F880C400D55A2D /* TouchFallthroughTextView.swift */; };
|
||||||
|
@ -15,13 +16,11 @@
|
||||||
D02E1F95250B13210071AD56 /* SafariView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02E1F94250B13210071AD56 /* SafariView.swift */; };
|
D02E1F95250B13210071AD56 /* SafariView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02E1F94250B13210071AD56 /* SafariView.swift */; };
|
||||||
D0625E59250F092900502611 /* StatusListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0625E58250F092900502611 /* StatusListCell.swift */; };
|
D0625E59250F092900502611 /* StatusListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0625E58250F092900502611 /* StatusListCell.swift */; };
|
||||||
D0625E5D250F0B5C00502611 /* StatusContentConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0625E5C250F0B5C00502611 /* StatusContentConfiguration.swift */; };
|
D0625E5D250F0B5C00502611 /* StatusContentConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0625E5C250F0B5C00502611 /* StatusContentConfiguration.swift */; };
|
||||||
D0625E5F250F0CFF00502611 /* StatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0625E5E250F0CFF00502611 /* StatusView.swift */; };
|
|
||||||
D06B492324D4611300642749 /* KingfisherSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = D06B492224D4611300642749 /* KingfisherSwiftUI */; };
|
D06B492324D4611300642749 /* KingfisherSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = D06B492224D4611300642749 /* KingfisherSwiftUI */; };
|
||||||
D06BC5E625202AD90079541D /* ProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06BC5E525202AD90079541D /* ProfileViewController.swift */; };
|
D06BC5E625202AD90079541D /* ProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06BC5E525202AD90079541D /* ProfileViewController.swift */; };
|
||||||
D0A1F4F7252E7D4B004435BF /* TableViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A1F4F6252E7D4B004435BF /* TableViewDataSource.swift */; };
|
D0A1F4F7252E7D4B004435BF /* TableViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A1F4F6252E7D4B004435BF /* TableViewDataSource.swift */; };
|
||||||
D0B32F50250B373600311912 /* RegistrationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B32F4F250B373600311912 /* RegistrationView.swift */; };
|
D0B32F50250B373600311912 /* RegistrationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B32F4F250B373600311912 /* RegistrationView.swift */; };
|
||||||
D0B5FE9B251583DB00478838 /* ProfileCollection+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B5FE9A251583DB00478838 /* ProfileCollection+Extensions.swift */; };
|
D0B5FE9B251583DB00478838 /* ProfileCollection+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B5FE9A251583DB00478838 /* ProfileCollection+Extensions.swift */; };
|
||||||
D0B7434925100DBB00C13DB6 /* StatusView.xib in Resources */ = {isa = PBXBuildFile; fileRef = D0B7434825100DBB00C13DB6 /* StatusView.xib */; };
|
|
||||||
D0B8510C25259E56004E0744 /* LoadMoreCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B8510B25259E56004E0744 /* LoadMoreCell.swift */; };
|
D0B8510C25259E56004E0744 /* LoadMoreCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B8510B25259E56004E0744 /* LoadMoreCell.swift */; };
|
||||||
D0BEB1F324F8EE8C001B0F04 /* StatusAttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1F224F8EE8C001B0F04 /* StatusAttachmentView.swift */; };
|
D0BEB1F324F8EE8C001B0F04 /* StatusAttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1F224F8EE8C001B0F04 /* StatusAttachmentView.swift */; };
|
||||||
D0BEB1F724F9A84B001B0F04 /* LoadingTableFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1F624F9A84B001B0F04 /* LoadingTableFooterView.swift */; };
|
D0BEB1F724F9A84B001B0F04 /* LoadingTableFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEB1F624F9A84B001B0F04 /* LoadingTableFooterView.swift */; };
|
||||||
|
@ -99,6 +98,7 @@
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
D0030981250C6C8500EACB32 /* URL+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+Extensions.swift"; sourceTree = "<group>"; };
|
D0030981250C6C8500EACB32 /* URL+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+Extensions.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>"; };
|
||||||
D01F41D624F880C400D55A2D /* TouchFallthroughTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TouchFallthroughTextView.swift; sourceTree = "<group>"; };
|
D01F41D624F880C400D55A2D /* TouchFallthroughTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TouchFallthroughTextView.swift; sourceTree = "<group>"; };
|
||||||
|
@ -107,7 +107,6 @@
|
||||||
D047FA8C24C3E21200AF17C5 /* Metatext.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Metatext.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
D047FA8C24C3E21200AF17C5 /* Metatext.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Metatext.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
D0625E58250F092900502611 /* StatusListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusListCell.swift; sourceTree = "<group>"; };
|
D0625E58250F092900502611 /* StatusListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusListCell.swift; sourceTree = "<group>"; };
|
||||||
D0625E5C250F0B5C00502611 /* StatusContentConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusContentConfiguration.swift; sourceTree = "<group>"; };
|
D0625E5C250F0B5C00502611 /* StatusContentConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusContentConfiguration.swift; sourceTree = "<group>"; };
|
||||||
D0625E5E250F0CFF00502611 /* StatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusView.swift; sourceTree = "<group>"; };
|
|
||||||
D0666A2124C677B400F3F04B /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
D0666A2124C677B400F3F04B /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
D0666A2524C677B400F3F04B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
D0666A2524C677B400F3F04B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
D06BC5E525202AD90079541D /* ProfileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewController.swift; sourceTree = "<group>"; };
|
D06BC5E525202AD90079541D /* ProfileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewController.swift; sourceTree = "<group>"; };
|
||||||
|
@ -116,7 +115,6 @@
|
||||||
D0AD03552505814D0085A466 /* Base16 */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Base16; sourceTree = "<group>"; };
|
D0AD03552505814D0085A466 /* Base16 */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Base16; sourceTree = "<group>"; };
|
||||||
D0B32F4F250B373600311912 /* RegistrationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegistrationView.swift; sourceTree = "<group>"; };
|
D0B32F4F250B373600311912 /* RegistrationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegistrationView.swift; sourceTree = "<group>"; };
|
||||||
D0B5FE9A251583DB00478838 /* ProfileCollection+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileCollection+Extensions.swift"; sourceTree = "<group>"; };
|
D0B5FE9A251583DB00478838 /* ProfileCollection+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileCollection+Extensions.swift"; sourceTree = "<group>"; };
|
||||||
D0B7434825100DBB00C13DB6 /* StatusView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = StatusView.xib; sourceTree = "<group>"; };
|
|
||||||
D0B8510B25259E56004E0744 /* LoadMoreCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadMoreCell.swift; sourceTree = "<group>"; };
|
D0B8510B25259E56004E0744 /* LoadMoreCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadMoreCell.swift; sourceTree = "<group>"; };
|
||||||
D0BDF66524FD7A6400C7FA1C /* ServiceLayer */ = {isa = PBXFileReference; lastKnownFileType = folder; path = ServiceLayer; sourceTree = "<group>"; };
|
D0BDF66524FD7A6400C7FA1C /* ServiceLayer */ = {isa = PBXFileReference; lastKnownFileType = folder; path = ServiceLayer; sourceTree = "<group>"; };
|
||||||
D0BEB1F224F8EE8C001B0F04 /* StatusAttachmentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusAttachmentView.swift; sourceTree = "<group>"; };
|
D0BEB1F224F8EE8C001B0F04 /* StatusAttachmentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusAttachmentView.swift; sourceTree = "<group>"; };
|
||||||
|
@ -245,8 +243,7 @@
|
||||||
D0BEB1F224F8EE8C001B0F04 /* StatusAttachmentView.swift */,
|
D0BEB1F224F8EE8C001B0F04 /* StatusAttachmentView.swift */,
|
||||||
D0625E5C250F0B5C00502611 /* StatusContentConfiguration.swift */,
|
D0625E5C250F0B5C00502611 /* StatusContentConfiguration.swift */,
|
||||||
D0625E58250F092900502611 /* StatusListCell.swift */,
|
D0625E58250F092900502611 /* StatusListCell.swift */,
|
||||||
D0625E5E250F0CFF00502611 /* StatusView.swift */,
|
D00CB2EC2533ACC00080096B /* StatusView.swift */,
|
||||||
D0B7434825100DBB00C13DB6 /* StatusView.xib */,
|
|
||||||
);
|
);
|
||||||
path = Status;
|
path = Status;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -491,7 +488,6 @@
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
D0C7D4C524F7616A001EBDBB /* Localizable.strings in Resources */,
|
D0C7D4C524F7616A001EBDBB /* Localizable.strings in Resources */,
|
||||||
D0B7434925100DBB00C13DB6 /* StatusView.xib in Resources */,
|
|
||||||
D0C7D4C224F7616A001EBDBB /* Assets.xcassets in Resources */,
|
D0C7D4C224F7616A001EBDBB /* Assets.xcassets in Resources */,
|
||||||
D0C7D4C624F7616A001EBDBB /* Localizable.stringsdict in Resources */,
|
D0C7D4C624F7616A001EBDBB /* Localizable.stringsdict in Resources */,
|
||||||
);
|
);
|
||||||
|
@ -552,7 +548,6 @@
|
||||||
D0F0B113251A86A000942152 /* AccountContentConfiguration.swift in Sources */,
|
D0F0B113251A86A000942152 /* AccountContentConfiguration.swift in Sources */,
|
||||||
D01F41D924F880C400D55A2D /* TouchFallthroughTextView.swift in Sources */,
|
D01F41D924F880C400D55A2D /* TouchFallthroughTextView.swift in Sources */,
|
||||||
D0C7D4D624F7616A001EBDBB /* NSMutableAttributedString+Extensions.swift in Sources */,
|
D0C7D4D624F7616A001EBDBB /* NSMutableAttributedString+Extensions.swift in Sources */,
|
||||||
D0625E5F250F0CFF00502611 /* StatusView.swift in Sources */,
|
|
||||||
D0625E59250F092900502611 /* StatusListCell.swift in Sources */,
|
D0625E59250F092900502611 /* StatusListCell.swift in Sources */,
|
||||||
D0E569DB2529319100FA1D72 /* LoadMoreView.swift in Sources */,
|
D0E569DB2529319100FA1D72 /* LoadMoreView.swift in Sources */,
|
||||||
D0C7D49D24F7616A001EBDBB /* PostingReadingPreferencesView.swift in Sources */,
|
D0C7D49D24F7616A001EBDBB /* PostingReadingPreferencesView.swift in Sources */,
|
||||||
|
@ -576,6 +571,7 @@
|
||||||
D01F41E424F8889700D55A2D /* StatusAttachmentsView.swift in Sources */,
|
D01F41E424F8889700D55A2D /* StatusAttachmentsView.swift in Sources */,
|
||||||
D0BEB21124FA2A91001B0F04 /* EditFilterView.swift in Sources */,
|
D0BEB21124FA2A91001B0F04 /* EditFilterView.swift in Sources */,
|
||||||
D0030982250C6C8500EACB32 /* URL+Extensions.swift in Sources */,
|
D0030982250C6C8500EACB32 /* URL+Extensions.swift in Sources */,
|
||||||
|
D00CB2ED2533ACC00080096B /* StatusView.swift in Sources */,
|
||||||
D0A1F4F7252E7D4B004435BF /* TableViewDataSource.swift in Sources */,
|
D0A1F4F7252E7D4B004435BF /* TableViewDataSource.swift in Sources */,
|
||||||
D0C7D4C424F7616A001EBDBB /* AppDelegate.swift in Sources */,
|
D0C7D4C424F7616A001EBDBB /* AppDelegate.swift in Sources */,
|
||||||
D0C7D49924F7616A001EBDBB /* AddIdentityView.swift in Sources */,
|
D0C7D49924F7616A001EBDBB /* AddIdentityView.swift in Sources */,
|
||||||
|
|
|
@ -95,7 +95,7 @@ private extension AccountHeaderView {
|
||||||
equalTo: headerImageView.widthAnchor,
|
equalTo: headerImageView.widthAnchor,
|
||||||
multiplier: 1 / 3)
|
multiplier: 1 / 3)
|
||||||
|
|
||||||
headerImageAspectRatioConstraint.priority = .init(999)
|
headerImageAspectRatioConstraint.priority = .justBelowMax
|
||||||
|
|
||||||
NSLayoutConstraint.activate([
|
NSLayoutConstraint.activate([
|
||||||
headerImageAspectRatioConstraint,
|
headerImageAspectRatioConstraint,
|
||||||
|
|
|
@ -57,15 +57,13 @@ extension AccountView: UITextViewDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension AccountView {
|
private extension AccountView {
|
||||||
static let avatarDimension: CGFloat = 50
|
|
||||||
|
|
||||||
func initialSetup() {
|
func initialSetup() {
|
||||||
let stackView = UIStackView()
|
let stackView = UIStackView()
|
||||||
|
|
||||||
addSubview(avatarImageView)
|
addSubview(avatarImageView)
|
||||||
addSubview(stackView)
|
addSubview(stackView)
|
||||||
avatarImageView.translatesAutoresizingMaskIntoConstraints = false
|
avatarImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
avatarImageView.layer.cornerRadius = Self.avatarDimension / 2
|
avatarImageView.layer.cornerRadius = .avatarDimension / 2
|
||||||
avatarImageView.clipsToBounds = true
|
avatarImageView.clipsToBounds = true
|
||||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
stackView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
stackView.axis = .vertical
|
stackView.axis = .vertical
|
||||||
|
@ -85,8 +83,8 @@ private extension AccountView {
|
||||||
noteTextView.delegate = self
|
noteTextView.delegate = self
|
||||||
|
|
||||||
NSLayoutConstraint.activate([
|
NSLayoutConstraint.activate([
|
||||||
avatarImageView.widthAnchor.constraint(equalToConstant: Self.avatarDimension),
|
avatarImageView.widthAnchor.constraint(equalToConstant: .avatarDimension),
|
||||||
avatarImageView.heightAnchor.constraint(equalToConstant: Self.avatarDimension),
|
avatarImageView.heightAnchor.constraint(equalToConstant: .avatarDimension),
|
||||||
avatarImageView.topAnchor.constraint(equalTo: readableContentGuide.topAnchor),
|
avatarImageView.topAnchor.constraint(equalTo: readableContentGuide.topAnchor),
|
||||||
avatarImageView.leadingAnchor.constraint(equalTo: readableContentGuide.leadingAnchor),
|
avatarImageView.leadingAnchor.constraint(equalTo: readableContentGuide.leadingAnchor),
|
||||||
avatarImageView.bottomAnchor.constraint(lessThanOrEqualTo: readableContentGuide.bottomAnchor),
|
avatarImageView.bottomAnchor.constraint(lessThanOrEqualTo: readableContentGuide.bottomAnchor),
|
||||||
|
|
|
@ -18,7 +18,7 @@ struct SecondaryNavigationView: View {
|
||||||
label: {
|
label: {
|
||||||
HStack {
|
HStack {
|
||||||
KFImage(viewModel.identification.identity.image,
|
KFImage(viewModel.identification.identity.image,
|
||||||
options: .downsampled(dimension: 50, scaleFactor: displayScale))
|
options: .downsampled(dimension: .avatarDimension, scaleFactor: displayScale))
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
if viewModel.identification.identity.authenticated {
|
if viewModel.identification.identity.authenticated {
|
||||||
if let account = viewModel.identification.identity.account {
|
if let account = viewModel.identification.identity.account {
|
||||||
|
|
|
@ -7,6 +7,7 @@ final class StatusAttachmentsView: UIView {
|
||||||
private let containerStackView = UIStackView()
|
private let containerStackView = UIStackView()
|
||||||
private let leftStackView = UIStackView()
|
private let leftStackView = UIStackView()
|
||||||
private let rightStackView = UIStackView()
|
private let rightStackView = UIStackView()
|
||||||
|
private var aspectRatioConstraint: NSLayoutConstraint?
|
||||||
|
|
||||||
var attachmentViewModels = [AttachmentViewModel]() {
|
var attachmentViewModels = [AttachmentViewModel]() {
|
||||||
didSet {
|
didSet {
|
||||||
|
@ -32,6 +33,19 @@ final class StatusAttachmentsView: UIView {
|
||||||
leftStackView.addArrangedSubview(attachmentView)
|
leftStackView.addArrangedSubview(attachmentView)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let newAspectRatio: CGFloat
|
||||||
|
|
||||||
|
if attachmentViewModels.count == 1, let aspectRatio = attachmentViewModels.first?.aspectRatio {
|
||||||
|
newAspectRatio = max(CGFloat(aspectRatio), 16 / 9)
|
||||||
|
} else {
|
||||||
|
newAspectRatio = 16 / 9
|
||||||
|
}
|
||||||
|
|
||||||
|
aspectRatioConstraint?.isActive = false
|
||||||
|
aspectRatioConstraint = widthAnchor.constraint(equalTo: heightAnchor, multiplier: newAspectRatio)
|
||||||
|
aspectRatioConstraint?.priority = .justBelowMax
|
||||||
|
aspectRatioConstraint?.isActive = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,53 +1,48 @@
|
||||||
// Copyright © 2020 Metabolist. All rights reserved.
|
// Copyright © 2020 Metabolist. All rights reserved.
|
||||||
|
|
||||||
|
// swiftlint:disable file_length
|
||||||
import Kingfisher
|
import Kingfisher
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
class StatusView: UIView {
|
final class StatusView: UIView {
|
||||||
@IBOutlet var baseView: UIView!
|
let avatarImageView = AnimatedImageView()
|
||||||
@IBOutlet weak var metaIcon: UIImageView!
|
let avatarButton = UIButton()
|
||||||
@IBOutlet weak var metaLabel: UILabel!
|
let infoIcon = UIImageView()
|
||||||
@IBOutlet weak var contentTextView: TouchFallthroughTextView!
|
let infoLabel = UILabel()
|
||||||
@IBOutlet weak var avatarButton: UIButton!
|
let displayNameLabel = UILabel()
|
||||||
@IBOutlet weak var avatarImageView: AnimatedImageView!
|
let accountLabel = UILabel()
|
||||||
@IBOutlet weak var displayNameLabel: UILabel!
|
let timeLabel = UILabel()
|
||||||
@IBOutlet weak var accountLabel: UILabel!
|
let spoilerTextLabel = UILabel()
|
||||||
@IBOutlet weak var timeLabel: UILabel!
|
let toggleShowMoreButton = UIButton(type: .system)
|
||||||
@IBOutlet weak var spoilerTextLabel: UILabel!
|
let contentTextView = TouchFallthroughTextView()
|
||||||
@IBOutlet weak var toggleShowMoreButton: UIButton!
|
let attachmentsView = StatusAttachmentsView()
|
||||||
@IBOutlet weak var replyButton: UIButton!
|
let cardView = CardView()
|
||||||
@IBOutlet weak var reblogButton: UIButton!
|
let contextParentTimeLabel = UILabel()
|
||||||
@IBOutlet weak var favoriteButton: UIButton!
|
let timeApplicationDividerLabel = UILabel()
|
||||||
@IBOutlet weak var shareButton: UIButton!
|
let applicationButton = UIButton(type: .system)
|
||||||
@IBOutlet weak var attachmentsView: StatusAttachmentsView!
|
let rebloggedByButton = UIButton()
|
||||||
@IBOutlet weak var cardView: CardView!
|
let favoritedByButton = UIButton()
|
||||||
@IBOutlet weak var showMoreView: UIStackView!
|
let replyButton = UIButton()
|
||||||
@IBOutlet weak var hasReplyFollowingView: UIView!
|
let reblogButton = UIButton()
|
||||||
@IBOutlet weak var inReplyToView: UIView!
|
let favoriteButton = UIButton()
|
||||||
@IBOutlet weak var avatarReplyContextView: UIView!
|
let shareButton = UIButton()
|
||||||
@IBOutlet weak var nameDateView: UIStackView!
|
let menuButton = UIButton()
|
||||||
@IBOutlet weak var contextParentAvatarNameView: UIStackView!
|
|
||||||
@IBOutlet weak var contextParentAvatarImageView: AnimatedImageView!
|
|
||||||
@IBOutlet weak var contextParentAvatarButton: UIButton!
|
|
||||||
@IBOutlet weak var contextParentDisplayNameLabel: UILabel!
|
|
||||||
@IBOutlet weak var contextParentAccountLabel: UILabel!
|
|
||||||
@IBOutlet weak var actionButtonsView: UIStackView!
|
|
||||||
@IBOutlet weak var contextParentReplyButton: UIButton!
|
|
||||||
@IBOutlet weak var contextParentReblogButton: UIButton!
|
|
||||||
@IBOutlet weak var contextParentFavoriteButton: UIButton!
|
|
||||||
@IBOutlet weak var contextParentShareButton: UIButton!
|
|
||||||
@IBOutlet weak var contextParentActionsButton: UIButton!
|
|
||||||
@IBOutlet weak var contextParentTimeLabel: UILabel!
|
|
||||||
@IBOutlet weak var timeApplicationDividerView: UILabel!
|
|
||||||
@IBOutlet weak var applicationButton: UIButton!
|
|
||||||
@IBOutlet weak var contextParentRebloggedByButton: UIButton!
|
|
||||||
@IBOutlet weak var contextParentFavoritedByButton: UIButton!
|
|
||||||
@IBOutlet weak var contextParentItems: UIStackView!
|
|
||||||
@IBOutlet weak var contextParentRebloggedByFavoritedByView: UIStackView!
|
|
||||||
@IBOutlet weak var contextParentRebloggedByFavoritedBySeparator: UIView!
|
|
||||||
|
|
||||||
|
private let containerStackView = UIStackView()
|
||||||
|
private let sideStackView = UIStackView()
|
||||||
|
private let mainStackView = UIStackView()
|
||||||
|
private let nameAccountContainerStackView = UIStackView()
|
||||||
|
private let nameAccountTimeStackView = UIStackView()
|
||||||
|
private let contextParentTimeApplicationStackView = UIStackView()
|
||||||
|
private let contextParentTopNameAccountSpacingView = UIView()
|
||||||
|
private let contextParentBottomNameAccountSpacingView = UIView()
|
||||||
|
private let interactionsDividerView = UIView()
|
||||||
|
private let interactionsStackView = UIStackView()
|
||||||
|
private let buttonsDividerView = UIView()
|
||||||
|
private let buttonsStackView = UIStackView()
|
||||||
|
private let inReplyToView = UIView()
|
||||||
|
private let hasReplyFollowingView = UIView()
|
||||||
private var statusConfiguration: StatusContentConfiguration
|
private var statusConfiguration: StatusContentConfiguration
|
||||||
@IBOutlet private var separatorConstraints: [NSLayoutConstraint]!
|
|
||||||
|
|
||||||
init(configuration: StatusContentConfiguration) {
|
init(configuration: StatusContentConfiguration) {
|
||||||
self.statusConfiguration = configuration
|
self.statusConfiguration = configuration
|
||||||
|
@ -61,14 +56,6 @@ class StatusView: UIView {
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override func layoutSubviews() {
|
|
||||||
super.layoutSubviews()
|
|
||||||
|
|
||||||
for button: UIButton in [toggleShowMoreButton] where button.frame.height != 0 {
|
|
||||||
button.layer.cornerRadius = button.frame.height / 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension StatusView: UIContentView {
|
extension StatusView: UIContentView {
|
||||||
|
@ -79,8 +66,6 @@ extension StatusView: UIContentView {
|
||||||
|
|
||||||
self.statusConfiguration = statusConfiguration
|
self.statusConfiguration = statusConfiguration
|
||||||
|
|
||||||
avatarImageView.kf.cancelDownloadTask()
|
|
||||||
contextParentAvatarImageView.kf.cancelDownloadTask()
|
|
||||||
applyStatusConfiguration()
|
applyStatusConfiguration()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,46 +89,78 @@ extension StatusView: UITextViewDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension StatusView {
|
private extension StatusView {
|
||||||
|
static let actionButtonTitleEdgeInsets = UIEdgeInsets(top: 0, left: 2, bottom: 0, right: 0)
|
||||||
|
|
||||||
|
var actionButtons: [UIButton] {
|
||||||
|
[replyButton, reblogButton, favoriteButton, shareButton, menuButton]
|
||||||
|
}
|
||||||
|
|
||||||
// swiftlint:disable function_body_length
|
// swiftlint:disable function_body_length
|
||||||
func initialSetup() {
|
func initialSetup() {
|
||||||
Bundle.main.loadNibNamed(String(describing: type(of: self)), owner: self, options: nil)
|
addSubview(containerStackView)
|
||||||
|
containerStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
containerStackView.spacing = .defaultSpacing
|
||||||
|
|
||||||
addSubview(baseView)
|
infoIcon.tintColor = .secondaryLabel
|
||||||
|
infoIcon.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||||
|
|
||||||
baseView.translatesAutoresizingMaskIntoConstraints = false
|
sideStackView.axis = .vertical
|
||||||
baseView.backgroundColor = .clear
|
sideStackView.alignment = .trailing
|
||||||
|
sideStackView.spacing = .compactSpacing
|
||||||
|
sideStackView.addArrangedSubview(infoIcon)
|
||||||
|
sideStackView.addArrangedSubview(UIView())
|
||||||
|
containerStackView.addArrangedSubview(sideStackView)
|
||||||
|
|
||||||
NSLayoutConstraint.activate([
|
mainStackView.axis = .vertical
|
||||||
baseView.topAnchor.constraint(equalTo: readableContentGuide.topAnchor),
|
mainStackView.spacing = .compactSpacing
|
||||||
baseView.leadingAnchor.constraint(equalTo: readableContentGuide.leadingAnchor),
|
containerStackView.addArrangedSubview(mainStackView)
|
||||||
baseView.trailingAnchor.constraint(equalTo: readableContentGuide.trailingAnchor),
|
|
||||||
baseView.bottomAnchor.constraint(equalTo: readableContentGuide.bottomAnchor),
|
|
||||||
// These have "Placeholder" checked in the xib file so they can
|
|
||||||
// be set to go beyond the readable content guide
|
|
||||||
inReplyToView.topAnchor.constraint(equalTo: topAnchor),
|
|
||||||
hasReplyFollowingView.bottomAnchor.constraint(equalTo: bottomAnchor)
|
|
||||||
])
|
|
||||||
|
|
||||||
for constraint in separatorConstraints {
|
infoLabel.font = .preferredFont(forTextStyle: .caption1)
|
||||||
constraint.constant = .hairline
|
infoLabel.textColor = .secondaryLabel
|
||||||
}
|
infoLabel.adjustsFontForContentSizeCategory = true
|
||||||
|
infoLabel.setContentHuggingPriority(.required, for: .vertical)
|
||||||
|
mainStackView.addArrangedSubview(infoLabel)
|
||||||
|
|
||||||
avatarImageView.kf.indicatorType = .activity
|
displayNameLabel.font = .preferredFont(forTextStyle: .headline)
|
||||||
contextParentAvatarImageView.kf.indicatorType = .activity
|
displayNameLabel.adjustsFontForContentSizeCategory = true
|
||||||
|
displayNameLabel.setContentHuggingPriority(.required, for: .horizontal)
|
||||||
|
displayNameLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||||
|
nameAccountTimeStackView.addArrangedSubview(displayNameLabel)
|
||||||
|
|
||||||
contentTextView.delegate = self
|
accountLabel.font = .preferredFont(forTextStyle: .subheadline)
|
||||||
|
accountLabel.adjustsFontForContentSizeCategory = true
|
||||||
|
accountLabel.textColor = .secondaryLabel
|
||||||
|
nameAccountTimeStackView.addArrangedSubview(accountLabel)
|
||||||
|
|
||||||
avatarButton.setBackgroundImage(.highlightedButtonBackground, for: .highlighted)
|
timeLabel.font = .preferredFont(forTextStyle: .subheadline)
|
||||||
contextParentAvatarButton.setBackgroundImage(.highlightedButtonBackground, for: .highlighted)
|
timeLabel.adjustsFontForContentSizeCategory = true
|
||||||
|
timeLabel.textColor = .secondaryLabel
|
||||||
|
timeLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||||
|
timeLabel.setContentHuggingPriority(.required, for: .horizontal)
|
||||||
|
nameAccountTimeStackView.addArrangedSubview(timeLabel)
|
||||||
|
|
||||||
let accountAction = UIAction { [weak self] _ in self?.statusConfiguration.viewModel.accountSelected() }
|
nameAccountContainerStackView.spacing = .defaultSpacing
|
||||||
|
nameAccountContainerStackView.addArrangedSubview(nameAccountTimeStackView)
|
||||||
|
mainStackView.addArrangedSubview(nameAccountContainerStackView)
|
||||||
|
|
||||||
avatarButton.addAction(accountAction, for: .touchUpInside)
|
spoilerTextLabel.numberOfLines = 0
|
||||||
contextParentAvatarButton.addAction(accountAction, for: .touchUpInside)
|
spoilerTextLabel.adjustsFontForContentSizeCategory = true
|
||||||
|
mainStackView.addArrangedSubview(spoilerTextLabel)
|
||||||
|
|
||||||
|
toggleShowMoreButton.titleLabel?.font = .preferredFont(forTextStyle: .headline)
|
||||||
|
toggleShowMoreButton.titleLabel?.adjustsFontForContentSizeCategory = true
|
||||||
toggleShowMoreButton.addAction(
|
toggleShowMoreButton.addAction(
|
||||||
UIAction { [weak self] _ in self?.statusConfiguration.viewModel.toggleShowMore() },
|
UIAction { [weak self] _ in self?.statusConfiguration.viewModel.toggleShowMore() },
|
||||||
for: .touchUpInside)
|
for: .touchUpInside)
|
||||||
|
mainStackView.addArrangedSubview(toggleShowMoreButton)
|
||||||
|
|
||||||
|
contentTextView.adjustsFontForContentSizeCategory = true
|
||||||
|
contentTextView.isScrollEnabled = false
|
||||||
|
contentTextView.backgroundColor = .clear
|
||||||
|
contentTextView.delegate = self
|
||||||
|
mainStackView.addArrangedSubview(contentTextView)
|
||||||
|
|
||||||
|
mainStackView.addArrangedSubview(attachmentsView)
|
||||||
|
|
||||||
cardView.button.addAction(
|
cardView.button.addAction(
|
||||||
UIAction { [weak self] _ in
|
UIAction { [weak self] _ in
|
||||||
|
@ -155,24 +172,25 @@ private extension StatusView {
|
||||||
viewModel.urlSelected(url)
|
viewModel.urlSelected(url)
|
||||||
},
|
},
|
||||||
for: .touchUpInside)
|
for: .touchUpInside)
|
||||||
|
mainStackView.addArrangedSubview(cardView)
|
||||||
|
|
||||||
let favoriteAction = UIAction { [weak self] _ in self?.statusConfiguration.viewModel.toggleFavorited() }
|
contextParentTimeLabel.font = .preferredFont(forTextStyle: .footnote)
|
||||||
|
contextParentTimeLabel.adjustsFontForContentSizeCategory = true
|
||||||
|
contextParentTimeLabel.textColor = .secondaryLabel
|
||||||
|
contextParentTimeLabel.setContentHuggingPriority(.required, for: .horizontal)
|
||||||
|
contextParentTimeApplicationStackView.addArrangedSubview(contextParentTimeLabel)
|
||||||
|
|
||||||
favoriteButton.addAction(favoriteAction, for: .touchUpInside)
|
timeApplicationDividerLabel.font = .preferredFont(forTextStyle: .footnote)
|
||||||
contextParentFavoriteButton.addAction(favoriteAction, for: .touchUpInside)
|
timeApplicationDividerLabel.adjustsFontForContentSizeCategory = true
|
||||||
|
timeApplicationDividerLabel.textColor = .secondaryLabel
|
||||||
shareButton.addAction(
|
timeApplicationDividerLabel.text = "•"
|
||||||
UIAction { [weak self] _ in self?.statusConfiguration.viewModel.shareStatus() },
|
timeApplicationDividerLabel.setContentHuggingPriority(.required, for: .horizontal)
|
||||||
for: .touchUpInside)
|
contextParentTimeApplicationStackView.addArrangedSubview(timeApplicationDividerLabel)
|
||||||
|
|
||||||
contextParentRebloggedByButton.addAction(
|
|
||||||
UIAction { [weak self] _ in self?.statusConfiguration.viewModel.rebloggedBySelected() },
|
|
||||||
for: .touchUpInside)
|
|
||||||
|
|
||||||
contextParentFavoritedByButton.addAction(
|
|
||||||
UIAction { [weak self] _ in self?.statusConfiguration.viewModel.favoritedBySelected() },
|
|
||||||
for: .touchUpInside)
|
|
||||||
|
|
||||||
|
applicationButton.titleLabel?.font = .preferredFont(forTextStyle: .footnote)
|
||||||
|
applicationButton.titleLabel?.adjustsFontForContentSizeCategory = true
|
||||||
|
applicationButton.setTitleColor(.secondaryLabel, for: .disabled)
|
||||||
|
applicationButton.setContentHuggingPriority(.required, for: .horizontal)
|
||||||
applicationButton.addAction(
|
applicationButton.addAction(
|
||||||
UIAction { [weak self] _ in
|
UIAction { [weak self] _ in
|
||||||
guard
|
guard
|
||||||
|
@ -183,96 +201,126 @@ private extension StatusView {
|
||||||
viewModel.urlSelected(url)
|
viewModel.urlSelected(url)
|
||||||
},
|
},
|
||||||
for: .touchUpInside)
|
for: .touchUpInside)
|
||||||
|
contextParentTimeApplicationStackView.addArrangedSubview(applicationButton)
|
||||||
|
contextParentTimeApplicationStackView.addArrangedSubview(UIView())
|
||||||
|
|
||||||
|
contextParentTimeApplicationStackView.spacing = .compactSpacing
|
||||||
|
mainStackView.addArrangedSubview(contextParentTimeApplicationStackView)
|
||||||
|
|
||||||
|
for view in [interactionsDividerView, buttonsDividerView] {
|
||||||
|
view.backgroundColor = .opaqueSeparator
|
||||||
|
view.heightAnchor.constraint(equalToConstant: .hairline).isActive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
mainStackView.addArrangedSubview(interactionsDividerView)
|
||||||
|
mainStackView.addArrangedSubview(interactionsStackView)
|
||||||
|
mainStackView.addArrangedSubview(buttonsDividerView)
|
||||||
|
|
||||||
|
rebloggedByButton.contentHorizontalAlignment = .leading
|
||||||
|
rebloggedByButton.addAction(
|
||||||
|
UIAction { [weak self] _ in self?.statusConfiguration.viewModel.rebloggedBySelected() },
|
||||||
|
for: .touchUpInside)
|
||||||
|
interactionsStackView.addArrangedSubview(rebloggedByButton)
|
||||||
|
|
||||||
|
favoritedByButton.contentHorizontalAlignment = .leading
|
||||||
|
favoritedByButton.addAction(
|
||||||
|
UIAction { [weak self] _ in self?.statusConfiguration.viewModel.favoritedBySelected() },
|
||||||
|
for: .touchUpInside)
|
||||||
|
interactionsStackView.addArrangedSubview(favoritedByButton)
|
||||||
|
interactionsStackView.distribution = .fillEqually
|
||||||
|
|
||||||
|
favoriteButton.addAction(
|
||||||
|
UIAction { [weak self] _ in self?.statusConfiguration.viewModel.toggleFavorited() },
|
||||||
|
for: .touchUpInside)
|
||||||
|
|
||||||
|
shareButton.addAction(
|
||||||
|
UIAction { [weak self] _ in self?.statusConfiguration.viewModel.shareStatus() },
|
||||||
|
for: .touchUpInside)
|
||||||
|
|
||||||
|
for button in actionButtons {
|
||||||
|
button.titleLabel?.font = .preferredFont(forTextStyle: .footnote)
|
||||||
|
button.titleLabel?.adjustsFontSizeToFitWidth = true
|
||||||
|
button.tintColor = .secondaryLabel
|
||||||
|
button.setTitleColor(.secondaryLabel, for: .normal)
|
||||||
|
button.titleEdgeInsets = Self.actionButtonTitleEdgeInsets
|
||||||
|
buttonsStackView.addArrangedSubview(button)
|
||||||
|
button.widthAnchor.constraint(greaterThanOrEqualToConstant: .minimumButtonDimension).isActive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
buttonsStackView.distribution = .equalSpacing
|
||||||
|
mainStackView.addArrangedSubview(buttonsStackView)
|
||||||
|
|
||||||
|
avatarImageView.layer.cornerRadius = .avatarDimension / 2
|
||||||
|
avatarImageView.clipsToBounds = true
|
||||||
|
|
||||||
|
let avatarHeightConstraint = avatarImageView.heightAnchor.constraint(equalToConstant: .avatarDimension)
|
||||||
|
|
||||||
|
avatarHeightConstraint.priority = .justBelowMax
|
||||||
|
|
||||||
|
avatarButton.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
avatarImageView.addSubview(avatarButton)
|
||||||
|
avatarImageView.isUserInteractionEnabled = true
|
||||||
|
avatarButton.setBackgroundImage(.highlightedButtonBackground, for: .highlighted)
|
||||||
|
|
||||||
|
avatarButton.addAction(
|
||||||
|
UIAction { [weak self] _ in self?.statusConfiguration.viewModel.accountSelected() },
|
||||||
|
for: .touchUpInside)
|
||||||
|
|
||||||
|
for view in [inReplyToView, hasReplyFollowingView] {
|
||||||
|
addSubview(view)
|
||||||
|
view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
view.backgroundColor = .opaqueSeparator
|
||||||
|
view.widthAnchor.constraint(equalToConstant: .hairline).isActive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
containerStackView.topAnchor.constraint(equalTo: readableContentGuide.topAnchor),
|
||||||
|
containerStackView.leadingAnchor.constraint(equalTo: readableContentGuide.leadingAnchor),
|
||||||
|
containerStackView.trailingAnchor.constraint(equalTo: readableContentGuide.trailingAnchor),
|
||||||
|
containerStackView.bottomAnchor.constraint(equalTo: readableContentGuide.bottomAnchor),
|
||||||
|
avatarImageView.widthAnchor.constraint(equalToConstant: .avatarDimension),
|
||||||
|
avatarHeightConstraint,
|
||||||
|
sideStackView.widthAnchor.constraint(equalToConstant: .avatarDimension),
|
||||||
|
infoIcon.centerYAnchor.constraint(equalTo: infoLabel.centerYAnchor),
|
||||||
|
avatarButton.leadingAnchor.constraint(equalTo: avatarImageView.leadingAnchor),
|
||||||
|
avatarButton.topAnchor.constraint(equalTo: avatarImageView.topAnchor),
|
||||||
|
avatarButton.bottomAnchor.constraint(equalTo: avatarImageView.bottomAnchor),
|
||||||
|
avatarButton.trailingAnchor.constraint(equalTo: avatarImageView.trailingAnchor)
|
||||||
|
])
|
||||||
|
|
||||||
applyStatusConfiguration()
|
applyStatusConfiguration()
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyStatusConfiguration() {
|
func applyStatusConfiguration() {
|
||||||
let viewModel = statusConfiguration.viewModel
|
let viewModel = statusConfiguration.viewModel
|
||||||
|
let isContextParent = viewModel.configuration.isContextParent
|
||||||
let mutableContent = NSMutableAttributedString(attributedString: viewModel.content)
|
let mutableContent = NSMutableAttributedString(attributedString: viewModel.content)
|
||||||
let mutableDisplayName = NSMutableAttributedString(string: viewModel.displayName)
|
let mutableDisplayName = NSMutableAttributedString(string: viewModel.displayName)
|
||||||
let mutableSpoilerText = NSMutableAttributedString(string: viewModel.spoilerText)
|
let mutableSpoilerText = NSMutableAttributedString(string: viewModel.spoilerText)
|
||||||
let contentTextStyle: UIFont.TextStyle = viewModel.configuration.isContextParent ? .title3 : .callout
|
let contentFont = UIFont.preferredFont(forTextStyle: isContextParent ? .title3 : .callout)
|
||||||
let contentFont = UIFont.preferredFont(forTextStyle: contentTextStyle)
|
let contentRange = NSRange(location: 0, length: mutableContent.length)
|
||||||
|
|
||||||
contentTextView.shouldFallthrough = !viewModel.configuration.isContextParent
|
contentTextView.shouldFallthrough = !isContextParent
|
||||||
avatarReplyContextView.isHidden = viewModel.configuration.isContextParent
|
sideStackView.isHidden = isContextParent
|
||||||
nameDateView.isHidden = viewModel.configuration.isContextParent
|
avatarImageView.removeFromSuperview()
|
||||||
contextParentAvatarNameView.isHidden = !viewModel.configuration.isContextParent
|
|
||||||
actionButtonsView.isHidden = viewModel.configuration.isContextParent
|
|
||||||
contextParentItems.isHidden = !viewModel.configuration.isContextParent
|
|
||||||
|
|
||||||
let avatarImageView: UIImageView
|
if isContextParent {
|
||||||
let displayNameLabel: UILabel
|
nameAccountContainerStackView.insertArrangedSubview(avatarImageView, at: 0)
|
||||||
let accountLabel: UILabel
|
|
||||||
|
|
||||||
if viewModel.configuration.isContextParent {
|
|
||||||
avatarImageView = contextParentAvatarImageView
|
|
||||||
displayNameLabel = contextParentDisplayNameLabel
|
|
||||||
accountLabel = contextParentAccountLabel
|
|
||||||
} else {
|
} else {
|
||||||
avatarImageView = self.avatarImageView
|
sideStackView.insertArrangedSubview(avatarImageView, at: 1)
|
||||||
displayNameLabel = self.displayNameLabel
|
|
||||||
accountLabel = self.accountLabel
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let contentRange = NSRange(location: 0, length: mutableContent.length)
|
NSLayoutConstraint.activate([
|
||||||
mutableContent.removeAttribute(.font, range: contentRange)
|
inReplyToView.centerXAnchor.constraint(equalTo: avatarImageView.centerXAnchor),
|
||||||
mutableContent.addAttributes(
|
inReplyToView.topAnchor.constraint(equalTo: topAnchor),
|
||||||
[.font: contentFont as Any,
|
inReplyToView.bottomAnchor.constraint(equalTo: avatarImageView.topAnchor),
|
||||||
.foregroundColor: UIColor.label],
|
hasReplyFollowingView.centerXAnchor.constraint(equalTo: avatarImageView.centerXAnchor),
|
||||||
range: contentRange)
|
hasReplyFollowingView.topAnchor.constraint(equalTo: avatarImageView.bottomAnchor),
|
||||||
mutableContent.insert(emoji: viewModel.contentEmoji, view: contentTextView)
|
hasReplyFollowingView.bottomAnchor.constraint(equalTo: bottomAnchor)
|
||||||
mutableContent.resizeAttachments(toLineHeight: contentFont.lineHeight)
|
])
|
||||||
contentTextView.attributedText = mutableContent
|
|
||||||
contentTextView.isHidden = contentTextView.text == ""
|
|
||||||
mutableDisplayName.insert(emoji: viewModel.displayNameEmoji, view: displayNameLabel)
|
|
||||||
mutableDisplayName.resizeAttachments(toLineHeight: displayNameLabel.font.lineHeight)
|
|
||||||
displayNameLabel.attributedText = mutableDisplayName
|
|
||||||
mutableSpoilerText.insert(emoji: viewModel.contentEmoji, view: spoilerTextLabel)
|
|
||||||
mutableSpoilerText.resizeAttachments(toLineHeight: spoilerTextLabel.font.lineHeight)
|
|
||||||
spoilerTextLabel.attributedText = mutableSpoilerText
|
|
||||||
spoilerTextLabel.isHidden = !viewModel.sensitive || spoilerTextLabel.text == ""
|
|
||||||
toggleShowMoreButton.setTitle(
|
|
||||||
viewModel.shouldShowMore
|
|
||||||
? NSLocalizedString("status.show-less", comment: "")
|
|
||||||
: NSLocalizedString("status.show-more", comment: ""),
|
|
||||||
for: .normal)
|
|
||||||
accountLabel.text = viewModel.accountName
|
|
||||||
timeLabel.text = viewModel.time
|
|
||||||
contextParentTimeLabel.text = viewModel.contextParentTime
|
|
||||||
timeApplicationDividerView.isHidden = viewModel.applicationName == nil
|
|
||||||
applicationButton.isHidden = viewModel.applicationName == nil
|
|
||||||
applicationButton.setTitle(viewModel.applicationName, for: .normal)
|
|
||||||
applicationButton.isEnabled = viewModel.applicationURL != nil
|
|
||||||
avatarImageView.kf.setImage(with: viewModel.avatarURL)
|
|
||||||
toggleShowMoreButton.isHidden = viewModel.spoilerText == ""
|
|
||||||
replyButton.setTitle(viewModel.repliesCount == 0 ? "" : String(viewModel.repliesCount), for: .normal)
|
|
||||||
reblogButton.setTitle(viewModel.reblogsCount == 0 ? "" : String(viewModel.reblogsCount), for: .normal)
|
|
||||||
setReblogButtonColor(reblogged: viewModel.reblogged)
|
|
||||||
favoriteButton.setTitle(viewModel.favoritesCount == 0 ? "" : String(viewModel.favoritesCount), for: .normal)
|
|
||||||
setFavoriteButtonColor(favorited: viewModel.favorited)
|
|
||||||
|
|
||||||
reblogButton.isEnabled = viewModel.canBeReblogged
|
inReplyToView.isHidden = !viewModel.configuration.isReplyInContext
|
||||||
contextParentReblogButton.isEnabled = viewModel.canBeReblogged
|
hasReplyFollowingView.isHidden = !viewModel.configuration.hasReplyFollowing
|
||||||
|
|
||||||
let noReblogs = viewModel.reblogsCount == 0
|
|
||||||
let noFavorites = viewModel.favoritesCount == 0
|
|
||||||
let noInteractions = noReblogs && noFavorites
|
|
||||||
|
|
||||||
setAttributedLocalizedTitle(
|
|
||||||
button: contextParentRebloggedByButton,
|
|
||||||
localizationKey: "status.reblogs-count",
|
|
||||||
count: viewModel.reblogsCount)
|
|
||||||
contextParentRebloggedByButton.isHidden = noReblogs
|
|
||||||
setAttributedLocalizedTitle(
|
|
||||||
button: contextParentFavoritedByButton,
|
|
||||||
localizationKey: "status.favorites-count",
|
|
||||||
count: viewModel.favoritesCount)
|
|
||||||
contextParentFavoritedByButton.isHidden = noFavorites
|
|
||||||
|
|
||||||
contextParentRebloggedByFavoritedByView.isHidden = noInteractions
|
|
||||||
contextParentRebloggedByFavoritedBySeparator.isHidden = noInteractions
|
|
||||||
|
|
||||||
if
|
if
|
||||||
viewModel.isReblog {
|
viewModel.isReblog {
|
||||||
|
@ -280,77 +328,148 @@ private extension StatusView {
|
||||||
NSLocalizedString("status.reblogged-by", comment: ""),
|
NSLocalizedString("status.reblogged-by", comment: ""),
|
||||||
viewModel.rebloggedByDisplayName)
|
viewModel.rebloggedByDisplayName)
|
||||||
let mutableMetaText = NSMutableAttributedString(string: metaText)
|
let mutableMetaText = NSMutableAttributedString(string: metaText)
|
||||||
mutableMetaText.insert(emoji: viewModel.rebloggedByDisplayNameEmoji, view: metaLabel)
|
mutableMetaText.insert(emoji: viewModel.rebloggedByDisplayNameEmoji, view: infoLabel)
|
||||||
mutableMetaText.resizeAttachments(toLineHeight: metaLabel.font.lineHeight)
|
mutableMetaText.resizeAttachments(toLineHeight: infoLabel.font.lineHeight)
|
||||||
metaLabel.attributedText = mutableMetaText
|
infoLabel.attributedText = mutableMetaText
|
||||||
metaIcon.image = UIImage(
|
infoIcon.image = UIImage(
|
||||||
systemName: "arrow.2.squarepath",
|
systemName: "arrow.2.squarepath",
|
||||||
withConfiguration: UIImage.SymbolConfiguration(scale: .small))
|
withConfiguration: UIImage.SymbolConfiguration(scale: .small))
|
||||||
metaLabel.isHidden = false
|
infoLabel.isHidden = false
|
||||||
metaIcon.isHidden = false
|
infoIcon.isHidden = false
|
||||||
} else if viewModel.configuration.isPinned {
|
} else if viewModel.configuration.isPinned {
|
||||||
metaLabel.text = NSLocalizedString("status.pinned-post", comment: "")
|
infoLabel.text = NSLocalizedString("status.pinned-post", comment: "")
|
||||||
metaIcon.image = UIImage(
|
infoIcon.image = UIImage(
|
||||||
systemName: "pin",
|
systemName: "pin",
|
||||||
withConfiguration: UIImage.SymbolConfiguration(scale: .small))
|
withConfiguration: UIImage.SymbolConfiguration(scale: .small))
|
||||||
metaLabel.isHidden = false
|
infoLabel.isHidden = false
|
||||||
metaIcon.isHidden = false
|
infoIcon.isHidden = false
|
||||||
} else {
|
} else {
|
||||||
metaLabel.isHidden = true
|
infoLabel.isHidden = true
|
||||||
metaIcon.isHidden = true
|
infoIcon.isHidden = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutableContent.removeAttribute(.font, range: contentRange)
|
||||||
|
mutableContent.addAttributes(
|
||||||
|
[.font: contentFont, .foregroundColor: UIColor.label],
|
||||||
|
range: contentRange)
|
||||||
|
mutableContent.insert(emoji: viewModel.contentEmoji, view: contentTextView)
|
||||||
|
mutableContent.resizeAttachments(toLineHeight: contentFont.lineHeight)
|
||||||
|
contentTextView.attributedText = mutableContent
|
||||||
|
contentTextView.isHidden = contentTextView.text == ""
|
||||||
|
|
||||||
|
mutableDisplayName.insert(emoji: viewModel.displayNameEmoji, view: displayNameLabel)
|
||||||
|
mutableDisplayName.resizeAttachments(toLineHeight: displayNameLabel.font.lineHeight)
|
||||||
|
displayNameLabel.attributedText = mutableDisplayName
|
||||||
|
|
||||||
|
mutableSpoilerText.insert(emoji: viewModel.contentEmoji, view: spoilerTextLabel)
|
||||||
|
mutableSpoilerText.resizeAttachments(toLineHeight: spoilerTextLabel.font.lineHeight)
|
||||||
|
spoilerTextLabel.font = contentFont
|
||||||
|
spoilerTextLabel.attributedText = mutableSpoilerText
|
||||||
|
spoilerTextLabel.isHidden = spoilerTextLabel.text == ""
|
||||||
|
toggleShowMoreButton.setTitle(
|
||||||
|
viewModel.shouldShowMore
|
||||||
|
? NSLocalizedString("status.show-less", comment: "")
|
||||||
|
: NSLocalizedString("status.show-more", comment: ""),
|
||||||
|
for: .normal)
|
||||||
|
toggleShowMoreButton.isHidden = viewModel.spoilerText == ""
|
||||||
|
|
||||||
|
contentTextView.isHidden = !viewModel.shouldShowMore
|
||||||
|
|
||||||
|
nameAccountTimeStackView.axis = isContextParent ? .vertical : .horizontal
|
||||||
|
nameAccountTimeStackView.alignment = isContextParent ? .leading : .fill
|
||||||
|
nameAccountTimeStackView.spacing = isContextParent ? 0 : .compactSpacing
|
||||||
|
|
||||||
|
contextParentTopNameAccountSpacingView.removeFromSuperview()
|
||||||
|
contextParentBottomNameAccountSpacingView.removeFromSuperview()
|
||||||
|
|
||||||
|
if isContextParent {
|
||||||
|
nameAccountTimeStackView.insertArrangedSubview(contextParentTopNameAccountSpacingView, at: 0)
|
||||||
|
nameAccountTimeStackView.addArrangedSubview(contextParentBottomNameAccountSpacingView)
|
||||||
|
contextParentTopNameAccountSpacingView.heightAnchor
|
||||||
|
.constraint(equalTo: contextParentBottomNameAccountSpacingView.heightAnchor).isActive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
accountLabel.text = viewModel.accountName
|
||||||
|
timeLabel.text = viewModel.time
|
||||||
|
timeLabel.isHidden = isContextParent
|
||||||
|
|
||||||
attachmentsView.isHidden = viewModel.attachmentViewModels.count == 0
|
attachmentsView.isHidden = viewModel.attachmentViewModels.count == 0
|
||||||
attachmentsView.attachmentViewModels = viewModel.attachmentViewModels
|
attachmentsView.attachmentViewModels = viewModel.attachmentViewModels
|
||||||
setNeedsLayout()
|
|
||||||
|
|
||||||
cardView.viewModel = viewModel.cardViewModel
|
cardView.viewModel = viewModel.cardViewModel
|
||||||
cardView.isHidden = viewModel.cardViewModel == nil
|
cardView.isHidden = viewModel.cardViewModel == nil
|
||||||
|
|
||||||
showMoreView.isHidden = !viewModel.shouldShowMore
|
contextParentTimeLabel.text = viewModel.contextParentTime
|
||||||
|
timeApplicationDividerLabel.isHidden = viewModel.applicationName == nil
|
||||||
|
applicationButton.isHidden = viewModel.applicationName == nil
|
||||||
|
applicationButton.setTitle(viewModel.applicationName, for: .normal)
|
||||||
|
applicationButton.isEnabled = viewModel.applicationURL != nil
|
||||||
|
contextParentTimeApplicationStackView.isHidden = !isContextParent
|
||||||
|
|
||||||
inReplyToView.isHidden = !viewModel.configuration.isReplyInContext
|
let noReblogs = viewModel.reblogsCount == 0
|
||||||
|
let noFavorites = viewModel.favoritesCount == 0
|
||||||
|
let noInteractions = !isContextParent || (noReblogs && noFavorites)
|
||||||
|
|
||||||
hasReplyFollowingView.isHidden = !viewModel.configuration.hasReplyFollowing
|
setAttributedLocalizedTitle(
|
||||||
}
|
button: rebloggedByButton,
|
||||||
// swiftlint:enable function_body_length
|
localizationKey: "status.reblogs-count",
|
||||||
|
count: viewModel.reblogsCount)
|
||||||
|
rebloggedByButton.isHidden = noReblogs
|
||||||
|
setAttributedLocalizedTitle(
|
||||||
|
button: favoritedByButton,
|
||||||
|
localizationKey: "status.favorites-count",
|
||||||
|
count: viewModel.favoritesCount)
|
||||||
|
favoritedByButton.isHidden = noFavorites
|
||||||
|
|
||||||
func setReblogButtonColor(reblogged: Bool) {
|
interactionsDividerView.isHidden = noInteractions
|
||||||
let reblogColor: UIColor = reblogged ? .systemGreen : .secondaryLabel
|
interactionsStackView.isHidden = noInteractions
|
||||||
let reblogButton: UIButton
|
buttonsDividerView.isHidden = !isContextParent
|
||||||
|
|
||||||
if statusConfiguration.viewModel.configuration.isContextParent {
|
for button in actionButtons {
|
||||||
reblogButton = contextParentReblogButton
|
button.contentHorizontalAlignment = isContextParent ? .center : .leading
|
||||||
} else {
|
|
||||||
reblogButton = self.reblogButton
|
if isContextParent {
|
||||||
|
button.heightAnchor.constraint(equalToConstant: .minimumButtonDimension).isActive = true
|
||||||
|
} else {
|
||||||
|
button.heightAnchor.constraint(greaterThanOrEqualToConstant: 0).isActive = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setButtonImages(scale: isContextParent ? .medium : .small)
|
||||||
|
|
||||||
|
replyButton.setCountTitle(count: viewModel.repliesCount, isContextParent: isContextParent)
|
||||||
|
reblogButton.setCountTitle(count: viewModel.reblogsCount, isContextParent: isContextParent)
|
||||||
|
favoriteButton.setCountTitle(count: viewModel.favoritesCount, isContextParent: isContextParent)
|
||||||
|
|
||||||
|
let reblogColor: UIColor = viewModel.reblogged ? .systemGreen : .secondaryLabel
|
||||||
|
|
||||||
reblogButton.tintColor = reblogColor
|
reblogButton.tintColor = reblogColor
|
||||||
reblogButton.setTitleColor(reblogColor, for: .normal)
|
reblogButton.setTitleColor(reblogColor, for: .normal)
|
||||||
}
|
reblogButton.isEnabled = viewModel.canBeReblogged
|
||||||
|
|
||||||
func setFavoriteButtonColor(favorited: Bool) {
|
let favoriteColor: UIColor = viewModel.favorited ? .systemYellow : .secondaryLabel
|
||||||
let favoriteColor: UIColor = favorited ? .systemYellow : .secondaryLabel
|
|
||||||
let favoriteButton: UIButton
|
|
||||||
let scale: UIImage.SymbolScale
|
|
||||||
|
|
||||||
if statusConfiguration.viewModel.configuration.isContextParent {
|
|
||||||
favoriteButton = contextParentFavoriteButton
|
|
||||||
scale = .medium
|
|
||||||
} else {
|
|
||||||
favoriteButton = self.favoriteButton
|
|
||||||
scale = .small
|
|
||||||
}
|
|
||||||
|
|
||||||
favoriteButton.tintColor = favoriteColor
|
favoriteButton.tintColor = favoriteColor
|
||||||
favoriteButton.setTitleColor(favoriteColor, for: .normal)
|
favoriteButton.setTitleColor(favoriteColor, for: .normal)
|
||||||
favoriteButton.setImage(UIImage(
|
|
||||||
systemName: favorited ? "star.fill" : "star",
|
avatarImageView.kf.setImage(with: viewModel.avatarURL)
|
||||||
withConfiguration: UIImage.SymbolConfiguration(scale: scale)),
|
}
|
||||||
for: .normal)
|
// swiftlint:enable function_body_length
|
||||||
|
|
||||||
|
func setButtonImages(scale: UIImage.SymbolScale) {
|
||||||
|
replyButton.setImage(UIImage(systemName: "bubble.right",
|
||||||
|
withConfiguration: UIImage.SymbolConfiguration(scale: scale)), for: .normal)
|
||||||
|
reblogButton.setImage(UIImage(systemName: "arrow.2.squarepath",
|
||||||
|
withConfiguration: UIImage.SymbolConfiguration(scale: scale)), for: .normal)
|
||||||
|
favoriteButton.setImage(UIImage(systemName: statusConfiguration.viewModel.favorited ? "star.fill" : "star",
|
||||||
|
withConfiguration: UIImage.SymbolConfiguration(scale: scale)), for: .normal)
|
||||||
|
shareButton.setImage(UIImage(systemName: "square.and.arrow.up",
|
||||||
|
withConfiguration: UIImage.SymbolConfiguration(scale: scale)), for: .normal)
|
||||||
|
menuButton.setImage(UIImage(systemName: "ellipsis",
|
||||||
|
withConfiguration: UIImage.SymbolConfiguration(scale: scale)), for: .normal)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setAttributedLocalizedTitle(button: UIButton, localizationKey: String, count: Int) {
|
func setAttributedLocalizedTitle(button: UIButton, localizationKey: String, count: Int) {
|
||||||
let localizedTitle = String.localizedStringWithFormat(NSLocalizedString(localizationKey, comment: ""), count)
|
let localizedTitle = String.localizedStringWithFormat(NSLocalizedString(localizationKey, comment: ""), count)
|
||||||
|
|
||||||
button.setAttributedTitle(localizedTitle.countEmphasizedAttributedString(count: count), for: .normal)
|
button.setAttributedTitle(localizedTitle.countEmphasizedAttributedString(count: count), for: .normal)
|
||||||
|
@ -359,3 +478,10 @@ private extension StatusView {
|
||||||
for: .highlighted)
|
for: .highlighted)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private extension UIButton {
|
||||||
|
func setCountTitle(count: Int, isContextParent: Bool) {
|
||||||
|
setTitle((isContextParent || count == 0) ? "" : String(count), for: .normal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// swiftlint:enable file_length
|
||||||
|
|
|
@ -1,454 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17156" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
|
||||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
|
||||||
<dependencies>
|
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17125"/>
|
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
|
||||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
|
||||||
</dependencies>
|
|
||||||
<objects>
|
|
||||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="StatusView" customModule="Metatext" customModuleProvider="target">
|
|
||||||
<connections>
|
|
||||||
<outlet property="accountLabel" destination="NMr-1N-vQB" id="v2W-oV-3FP"/>
|
|
||||||
<outlet property="actionButtonsView" destination="zJg-bJ-uzd" id="iFx-AO-sJP"/>
|
|
||||||
<outlet property="applicationButton" destination="Rdt-TR-8S5" id="8dq-u9-oZ7"/>
|
|
||||||
<outlet property="attachmentsView" destination="diz-eN-CAY" id="7Ns-7h-laI"/>
|
|
||||||
<outlet property="avatarButton" destination="Xr7-Jl-psM" id="rKv-sF-8as"/>
|
|
||||||
<outlet property="avatarImageView" destination="5nP-eN-kWB" id="uxB-BV-s8N"/>
|
|
||||||
<outlet property="avatarReplyContextView" destination="H9l-Fc-4W4" id="gqR-14-5D9"/>
|
|
||||||
<outlet property="baseView" destination="iN0-l3-epB" id="Uv8-kN-29p"/>
|
|
||||||
<outlet property="cardView" destination="3dp-0a-Tpx" id="HnM-qF-c1Q"/>
|
|
||||||
<outlet property="contentTextView" destination="hxc-Pn-Vwz" id="VpV-ct-ngH"/>
|
|
||||||
<outlet property="contextParentAccountLabel" destination="8eU-OP-ovw" id="ovL-ho-3QQ"/>
|
|
||||||
<outlet property="contextParentActionsButton" destination="fN1-ao-eiV" id="VWJ-cv-jv0"/>
|
|
||||||
<outlet property="contextParentAvatarButton" destination="biC-25-AyX" id="2LZ-VP-sHm"/>
|
|
||||||
<outlet property="contextParentAvatarImageView" destination="Mkl-wW-t1y" id="KaW-YP-bih"/>
|
|
||||||
<outlet property="contextParentAvatarNameView" destination="JJo-vZ-2Ei" id="TDO-oC-Pxl"/>
|
|
||||||
<outlet property="contextParentDisplayNameLabel" destination="ONj-pm-o1o" id="cMf-BW-MBe"/>
|
|
||||||
<outlet property="contextParentFavoriteButton" destination="vKK-ho-Mc8" id="gUM-L7-Xvd"/>
|
|
||||||
<outlet property="contextParentFavoritedByButton" destination="dCB-Ba-lgt" id="5Ms-YL-of5"/>
|
|
||||||
<outlet property="contextParentItems" destination="dcp-zF-sHI" id="fk0-E0-a1C"/>
|
|
||||||
<outlet property="contextParentReblogButton" destination="c9q-Xj-ZhU" id="r6E-eC-ARj"/>
|
|
||||||
<outlet property="contextParentRebloggedByButton" destination="OaH-fg-fwa" id="VRW-Nv-ciu"/>
|
|
||||||
<outlet property="contextParentRebloggedByFavoritedBySeparator" destination="zAt-7g-Zg4" id="qHu-jW-D7F"/>
|
|
||||||
<outlet property="contextParentRebloggedByFavoritedByView" destination="M1E-qU-AAW" id="1jR-TT-38d"/>
|
|
||||||
<outlet property="contextParentReplyButton" destination="v8s-eL-K9J" id="OXs-A1-gof"/>
|
|
||||||
<outlet property="contextParentShareButton" destination="jXx-KF-3pu" id="Jbo-lf-AeG"/>
|
|
||||||
<outlet property="contextParentTimeLabel" destination="6Fo-vD-qjJ" id="3tZ-Ei-90H"/>
|
|
||||||
<outlet property="displayNameLabel" destination="8mm-Xw-oKi" id="f1U-Vb-70M"/>
|
|
||||||
<outlet property="favoriteButton" destination="ewo-qO-lvX" id="Hp2-L2-sHu"/>
|
|
||||||
<outlet property="hasReplyFollowingView" destination="EJV-En-WBg" id="5Ky-IG-ZmG"/>
|
|
||||||
<outlet property="inReplyToView" destination="gwb-UL-Eqa" id="WsQ-X0-Tw6"/>
|
|
||||||
<outlet property="metaIcon" destination="aO2-AK-zwO" id="zUW-ls-ofz"/>
|
|
||||||
<outlet property="metaLabel" destination="FMa-fP-vr2" id="SpH-Uz-Juk"/>
|
|
||||||
<outlet property="nameDateView" destination="svp-hj-Xn6" id="SzA-ME-jU0"/>
|
|
||||||
<outlet property="reblogButton" destination="ZKl-Hp-Y42" id="bxe-wr-kB7"/>
|
|
||||||
<outlet property="replyButton" destination="6HD-MP-H72" id="5fb-z4-qlm"/>
|
|
||||||
<outlet property="shareButton" destination="zAD-2Z-vhu" id="ZzV-wg-rOZ"/>
|
|
||||||
<outlet property="showMoreView" destination="BXI-3E-NWh" id="Zsm-ho-TbZ"/>
|
|
||||||
<outlet property="spoilerTextLabel" destination="5Gq-2q-Cvx" id="owo-VU-cIm"/>
|
|
||||||
<outlet property="timeApplicationDividerView" destination="hYj-vy-Net" id="F8o-xH-FFP"/>
|
|
||||||
<outlet property="timeLabel" destination="FEN-6u-xs5" id="epT-vQ-T9R"/>
|
|
||||||
<outlet property="toggleShowMoreButton" destination="XqE-Oj-oxH" id="D1n-WP-y9y"/>
|
|
||||||
<outletCollection property="separatorConstraints" destination="VEz-6j-37B" collectionClass="NSMutableArray" id="liC-8J-DV0"/>
|
|
||||||
<outletCollection property="separatorConstraints" destination="H9G-jZ-cek" collectionClass="NSMutableArray" id="E4b-tA-2gG"/>
|
|
||||||
</connections>
|
|
||||||
</placeholder>
|
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
|
||||||
<view contentMode="scaleToFill" id="iN0-l3-epB">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="536" height="864"/>
|
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
|
||||||
<subviews>
|
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="B6h-6a-Lty">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="536" height="864"/>
|
|
||||||
<subviews>
|
|
||||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="H9l-Fc-4W4">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="50" height="864"/>
|
|
||||||
<subviews>
|
|
||||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="arrow.2.squarepath" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="aO2-AK-zwO">
|
|
||||||
<rect key="frame" x="29.5" y="-0.5" width="20.5" height="15"/>
|
|
||||||
<color key="tintColor" systemColor="secondaryLabelColor"/>
|
|
||||||
<preferredSymbolConfiguration key="preferredSymbolConfiguration" scale="small"/>
|
|
||||||
</imageView>
|
|
||||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="gwb-UL-Eqa">
|
|
||||||
<rect key="frame" x="24" y="0.0" width="2" height="26.5"/>
|
|
||||||
<color key="backgroundColor" systemColor="quaternaryLabelColor"/>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstAttribute="width" constant="2" id="CTo-LC-S4B"/>
|
|
||||||
</constraints>
|
|
||||||
</view>
|
|
||||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="5nP-eN-kWB" customClass="AnimatedImageView" customModule="Kingfisher">
|
|
||||||
<rect key="frame" x="0.0" y="26.5" width="50" height="50"/>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstAttribute="height" constant="50" id="MOY-NI-L3C"/>
|
|
||||||
<constraint firstAttribute="width" constant="50" id="dHx-9Y-qH0"/>
|
|
||||||
</constraints>
|
|
||||||
<userDefinedRuntimeAttributes>
|
|
||||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
|
||||||
<integer key="value" value="25"/>
|
|
||||||
</userDefinedRuntimeAttribute>
|
|
||||||
</userDefinedRuntimeAttributes>
|
|
||||||
</imageView>
|
|
||||||
<button opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Xr7-Jl-psM">
|
|
||||||
<rect key="frame" x="0.0" y="26.5" width="50" height="50"/>
|
|
||||||
<userDefinedRuntimeAttributes>
|
|
||||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
|
||||||
<integer key="value" value="25"/>
|
|
||||||
</userDefinedRuntimeAttribute>
|
|
||||||
</userDefinedRuntimeAttributes>
|
|
||||||
</button>
|
|
||||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="EJV-En-WBg">
|
|
||||||
<rect key="frame" x="24" y="76.5" width="2" height="787.5"/>
|
|
||||||
<color key="backgroundColor" systemColor="quaternaryLabelColor"/>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstAttribute="width" constant="2" id="cPl-wP-HET"/>
|
|
||||||
</constraints>
|
|
||||||
</view>
|
|
||||||
</subviews>
|
|
||||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstItem="Xr7-Jl-psM" firstAttribute="bottom" secondItem="5nP-eN-kWB" secondAttribute="bottom" id="59c-8Y-WwT"/>
|
|
||||||
<constraint firstItem="5nP-eN-kWB" firstAttribute="leading" secondItem="H9l-Fc-4W4" secondAttribute="leading" id="AnF-cy-TF6"/>
|
|
||||||
<constraint firstItem="Xr7-Jl-psM" firstAttribute="leading" secondItem="5nP-eN-kWB" secondAttribute="leading" id="AtE-EW-2bE"/>
|
|
||||||
<constraint firstItem="gwb-UL-Eqa" firstAttribute="bottom" secondItem="5nP-eN-kWB" secondAttribute="top" id="M5s-gS-nod"/>
|
|
||||||
<constraint firstItem="EJV-En-WBg" firstAttribute="centerX" secondItem="5nP-eN-kWB" secondAttribute="centerX" id="ZbS-CP-EPR"/>
|
|
||||||
<constraint firstItem="Xr7-Jl-psM" firstAttribute="trailing" secondItem="5nP-eN-kWB" secondAttribute="trailing" id="aDG-XX-Aj3"/>
|
|
||||||
<constraint firstItem="EJV-En-WBg" firstAttribute="top" secondItem="5nP-eN-kWB" secondAttribute="bottom" id="aaW-v3-Deb"/>
|
|
||||||
<constraint firstAttribute="trailing" secondItem="aO2-AK-zwO" secondAttribute="trailing" id="fTn-dx-kgl"/>
|
|
||||||
<constraint firstItem="Xr7-Jl-psM" firstAttribute="top" secondItem="5nP-eN-kWB" secondAttribute="top" id="nEr-NK-zNi"/>
|
|
||||||
<constraint firstAttribute="trailing" secondItem="5nP-eN-kWB" secondAttribute="trailing" id="scQ-5M-FoQ"/>
|
|
||||||
<constraint firstItem="gwb-UL-Eqa" firstAttribute="centerX" secondItem="5nP-eN-kWB" secondAttribute="centerX" id="yRg-Yx-Q4A"/>
|
|
||||||
</constraints>
|
|
||||||
</view>
|
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="JXH-S7-Gjf">
|
|
||||||
<rect key="frame" x="58" y="0.0" width="478" height="864"/>
|
|
||||||
<subviews>
|
|
||||||
<stackView opaque="NO" contentMode="top" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="0RV-3u-4W7">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="478" height="167"/>
|
|
||||||
<subviews>
|
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FMa-fP-vr2">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="478" height="14.5"/>
|
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
|
|
||||||
<color key="textColor" systemColor="secondaryLabelColor"/>
|
|
||||||
<nil key="highlightedColor"/>
|
|
||||||
</label>
|
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="svp-hj-Xn6">
|
|
||||||
<rect key="frame" x="0.0" y="22.5" width="478" height="18"/>
|
|
||||||
<subviews>
|
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" verticalCompressionResistancePriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8mm-Xw-oKi">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="43.5" height="18"/>
|
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
|
|
||||||
<nil key="textColor"/>
|
|
||||||
<nil key="highlightedColor"/>
|
|
||||||
</label>
|
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="NMr-1N-vQB">
|
|
||||||
<rect key="frame" x="47.5" y="0.0" width="389" height="18"/>
|
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
|
|
||||||
<color key="textColor" systemColor="secondaryLabelColor"/>
|
|
||||||
<nil key="highlightedColor"/>
|
|
||||||
</label>
|
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="752" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FEN-6u-xs5">
|
|
||||||
<rect key="frame" x="440.5" y="0.0" width="37.5" height="18"/>
|
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
|
|
||||||
<color key="textColor" systemColor="secondaryLabelColor"/>
|
|
||||||
<nil key="highlightedColor"/>
|
|
||||||
</label>
|
|
||||||
</subviews>
|
|
||||||
</stackView>
|
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="JJo-vZ-2Ei">
|
|
||||||
<rect key="frame" x="0.0" y="48.5" width="478" height="50"/>
|
|
||||||
<subviews>
|
|
||||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="G9w-4E-gst">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
|
|
||||||
<subviews>
|
|
||||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Mkl-wW-t1y" customClass="AnimatedImageView" customModule="Kingfisher">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstAttribute="height" constant="50" id="CUB-dd-5ES"/>
|
|
||||||
<constraint firstAttribute="width" constant="50" id="OWd-GZ-pzg"/>
|
|
||||||
</constraints>
|
|
||||||
<userDefinedRuntimeAttributes>
|
|
||||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
|
||||||
<integer key="value" value="25"/>
|
|
||||||
</userDefinedRuntimeAttribute>
|
|
||||||
</userDefinedRuntimeAttributes>
|
|
||||||
</imageView>
|
|
||||||
<button opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="biC-25-AyX">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
|
|
||||||
<userDefinedRuntimeAttributes>
|
|
||||||
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
|
|
||||||
<integer key="value" value="25"/>
|
|
||||||
</userDefinedRuntimeAttribute>
|
|
||||||
</userDefinedRuntimeAttributes>
|
|
||||||
</button>
|
|
||||||
</subviews>
|
|
||||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstItem="biC-25-AyX" firstAttribute="top" secondItem="Mkl-wW-t1y" secondAttribute="top" id="I2W-iP-K1d"/>
|
|
||||||
<constraint firstItem="biC-25-AyX" firstAttribute="bottom" secondItem="Mkl-wW-t1y" secondAttribute="bottom" id="U0p-m9-fGR"/>
|
|
||||||
<constraint firstItem="Mkl-wW-t1y" firstAttribute="top" secondItem="G9w-4E-gst" secondAttribute="top" id="UcU-Ds-jfN"/>
|
|
||||||
<constraint firstAttribute="trailing" secondItem="Mkl-wW-t1y" secondAttribute="trailing" id="Xh4-dE-t47"/>
|
|
||||||
<constraint firstItem="biC-25-AyX" firstAttribute="leading" secondItem="Mkl-wW-t1y" secondAttribute="leading" id="Z5c-u3-6tE"/>
|
|
||||||
<constraint firstItem="biC-25-AyX" firstAttribute="trailing" secondItem="Mkl-wW-t1y" secondAttribute="trailing" id="fcB-JW-KmC"/>
|
|
||||||
<constraint firstAttribute="bottom" secondItem="Mkl-wW-t1y" secondAttribute="bottom" id="pR8-fI-zaO"/>
|
|
||||||
<constraint firstItem="Mkl-wW-t1y" firstAttribute="leading" secondItem="G9w-4E-gst" secondAttribute="leading" id="vWz-29-nLh"/>
|
|
||||||
</constraints>
|
|
||||||
</view>
|
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="JxA-h1-ocA">
|
|
||||||
<rect key="frame" x="58" y="0.0" width="420" height="50"/>
|
|
||||||
<subviews>
|
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ONj-pm-o1o">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="420" height="32"/>
|
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
|
|
||||||
<nil key="textColor"/>
|
|
||||||
<nil key="highlightedColor"/>
|
|
||||||
</label>
|
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="252" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8eU-OP-ovw">
|
|
||||||
<rect key="frame" x="0.0" y="32" width="420" height="18"/>
|
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
|
|
||||||
<color key="textColor" systemColor="secondaryLabelColor"/>
|
|
||||||
<nil key="highlightedColor"/>
|
|
||||||
</label>
|
|
||||||
</subviews>
|
|
||||||
</stackView>
|
|
||||||
</subviews>
|
|
||||||
</stackView>
|
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5Gq-2q-Cvx">
|
|
||||||
<rect key="frame" x="0.0" y="106.5" width="478" height="19.5"/>
|
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleCallout"/>
|
|
||||||
<nil key="textColor"/>
|
|
||||||
<nil key="highlightedColor"/>
|
|
||||||
</label>
|
|
||||||
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="XqE-Oj-oxH">
|
|
||||||
<rect key="frame" x="0.0" y="134" width="478" height="33"/>
|
|
||||||
<color key="backgroundColor" systemColor="linkColor"/>
|
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
|
|
||||||
<state key="normal" title="Show More">
|
|
||||||
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
|
||||||
</state>
|
|
||||||
</button>
|
|
||||||
</subviews>
|
|
||||||
</stackView>
|
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" verticalCompressionResistancePriority="749" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="BXI-3E-NWh">
|
|
||||||
<rect key="frame" x="0.0" y="175" width="478" height="549.5"/>
|
|
||||||
<subviews>
|
|
||||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" verticalCompressionResistancePriority="751" scrollEnabled="NO" editable="NO" text="Content" textAlignment="natural" adjustsFontForContentSizeCategory="YES" translatesAutoresizingMaskIntoConstraints="NO" id="hxc-Pn-Vwz" customClass="TouchFallthroughTextView" customModule="Metatext" customModuleProvider="target">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="478" height="37"/>
|
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleCallout"/>
|
|
||||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
|
||||||
</textView>
|
|
||||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="diz-eN-CAY" customClass="StatusAttachmentsView" customModule="Metatext" customModuleProvider="target">
|
|
||||||
<rect key="frame" x="0.0" y="45" width="478" height="269"/>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstAttribute="width" secondItem="diz-eN-CAY" secondAttribute="height" multiplier="16:9" priority="999" id="yvF-tL-A5X"/>
|
|
||||||
</constraints>
|
|
||||||
</view>
|
|
||||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3dp-0a-Tpx" customClass="CardView" customModule="Metatext" customModuleProvider="target">
|
|
||||||
<rect key="frame" x="0.0" y="322" width="478" height="227.5"/>
|
|
||||||
</view>
|
|
||||||
</subviews>
|
|
||||||
</stackView>
|
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" translatesAutoresizingMaskIntoConstraints="NO" id="zJg-bJ-uzd">
|
|
||||||
<rect key="frame" x="0.0" y="732.5" width="478" height="18.5"/>
|
|
||||||
<subviews>
|
|
||||||
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="251" contentHorizontalAlignment="leading" contentVerticalAlignment="center" adjustsImageSizeForAccessibilityContentSizeCategory="YES" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="6HD-MP-H72">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="119.5" height="18.5"/>
|
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleCaption2"/>
|
|
||||||
<color key="tintColor" systemColor="secondaryLabelColor"/>
|
|
||||||
<inset key="titleEdgeInsets" minX="4" minY="0.0" maxX="0.0" maxY="0.0"/>
|
|
||||||
<state key="normal" title="1" image="bubble.right" catalog="system">
|
|
||||||
<color key="titleColor" systemColor="secondaryLabelColor"/>
|
|
||||||
<preferredSymbolConfiguration key="preferredSymbolConfiguration" scale="small"/>
|
|
||||||
</state>
|
|
||||||
</button>
|
|
||||||
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="251" contentHorizontalAlignment="leading" contentVerticalAlignment="center" adjustsImageSizeForAccessibilityContentSizeCategory="YES" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ZKl-Hp-Y42">
|
|
||||||
<rect key="frame" x="119.5" y="0.0" width="119.5" height="18.5"/>
|
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleCaption2"/>
|
|
||||||
<color key="tintColor" systemColor="secondaryLabelColor"/>
|
|
||||||
<inset key="titleEdgeInsets" minX="4" minY="0.0" maxX="0.0" maxY="0.0"/>
|
|
||||||
<state key="normal" title="1" image="arrow.2.squarepath" catalog="system">
|
|
||||||
<color key="titleColor" systemColor="secondaryLabelColor"/>
|
|
||||||
<preferredSymbolConfiguration key="preferredSymbolConfiguration" scale="small"/>
|
|
||||||
</state>
|
|
||||||
</button>
|
|
||||||
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="251" contentHorizontalAlignment="leading" contentVerticalAlignment="center" adjustsImageSizeForAccessibilityContentSizeCategory="YES" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ewo-qO-lvX">
|
|
||||||
<rect key="frame" x="239" y="0.0" width="119.5" height="18.5"/>
|
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleCaption2"/>
|
|
||||||
<color key="tintColor" systemColor="secondaryLabelColor"/>
|
|
||||||
<inset key="titleEdgeInsets" minX="4" minY="0.0" maxX="0.0" maxY="0.0"/>
|
|
||||||
<state key="normal" title="1" image="star" catalog="system">
|
|
||||||
<color key="titleColor" systemColor="secondaryLabelColor"/>
|
|
||||||
<preferredSymbolConfiguration key="preferredSymbolConfiguration" scale="small"/>
|
|
||||||
</state>
|
|
||||||
</button>
|
|
||||||
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageSizeForAccessibilityContentSizeCategory="YES" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="zAD-2Z-vhu">
|
|
||||||
<rect key="frame" x="358.5" y="0.0" width="119.5" height="18.5"/>
|
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleCaption2"/>
|
|
||||||
<color key="tintColor" systemColor="secondaryLabelColor"/>
|
|
||||||
<state key="normal" image="square.and.arrow.up" catalog="system">
|
|
||||||
<color key="titleColor" systemColor="secondaryLabelColor"/>
|
|
||||||
<preferredSymbolConfiguration key="preferredSymbolConfiguration" scale="small"/>
|
|
||||||
</state>
|
|
||||||
</button>
|
|
||||||
</subviews>
|
|
||||||
</stackView>
|
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="dcp-zF-sHI">
|
|
||||||
<rect key="frame" x="0.0" y="759" width="478" height="105"/>
|
|
||||||
<subviews>
|
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="hTG-pM-6Kn">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="478" height="16"/>
|
|
||||||
<subviews>
|
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6Fo-vD-qjJ">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="33" height="16"/>
|
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleFootnote"/>
|
|
||||||
<color key="textColor" systemColor="secondaryLabelColor"/>
|
|
||||||
<nil key="highlightedColor"/>
|
|
||||||
</label>
|
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="•" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hYj-vy-Net">
|
|
||||||
<rect key="frame" x="37" y="0.0" width="6.5" height="16"/>
|
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleFootnote"/>
|
|
||||||
<color key="textColor" systemColor="secondaryLabelColor"/>
|
|
||||||
<nil key="highlightedColor"/>
|
|
||||||
</label>
|
|
||||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="leading" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Rdt-TR-8S5">
|
|
||||||
<rect key="frame" x="47.5" y="0.0" width="430.5" height="16"/>
|
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleFootnote"/>
|
|
||||||
<state key="normal" title="Button"/>
|
|
||||||
<state key="disabled">
|
|
||||||
<color key="titleColor" systemColor="secondaryLabelColor"/>
|
|
||||||
</state>
|
|
||||||
</button>
|
|
||||||
</subviews>
|
|
||||||
</stackView>
|
|
||||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="4eO-Vd-vy5">
|
|
||||||
<rect key="frame" x="0.0" y="24" width="478" height="1"/>
|
|
||||||
<color key="backgroundColor" systemColor="separatorColor"/>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstAttribute="height" constant="1" id="H9G-jZ-cek"/>
|
|
||||||
</constraints>
|
|
||||||
</view>
|
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" translatesAutoresizingMaskIntoConstraints="NO" id="M1E-qU-AAW">
|
|
||||||
<rect key="frame" x="0.0" y="33" width="478" height="33"/>
|
|
||||||
<subviews>
|
|
||||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="leading" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="OaH-fg-fwa">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="239" height="33"/>
|
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
|
||||||
<color key="tintColor" systemColor="secondaryLabelColor"/>
|
|
||||||
<state key="normal" title="1">
|
|
||||||
<color key="titleColor" systemColor="secondaryLabelColor"/>
|
|
||||||
</state>
|
|
||||||
<state key="highlighted">
|
|
||||||
<color key="titleColor" systemColor="tertiaryLabelColor"/>
|
|
||||||
</state>
|
|
||||||
</button>
|
|
||||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="leading" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="dCB-Ba-lgt">
|
|
||||||
<rect key="frame" x="239" y="0.0" width="239" height="33"/>
|
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
|
||||||
<state key="normal" title="1">
|
|
||||||
<color key="titleColor" systemColor="secondaryLabelColor"/>
|
|
||||||
</state>
|
|
||||||
<state key="highlighted">
|
|
||||||
<color key="titleColor" systemColor="tertiaryLabelColor"/>
|
|
||||||
</state>
|
|
||||||
</button>
|
|
||||||
</subviews>
|
|
||||||
</stackView>
|
|
||||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="zAt-7g-Zg4">
|
|
||||||
<rect key="frame" x="0.0" y="74" width="478" height="1"/>
|
|
||||||
<color key="backgroundColor" systemColor="separatorColor"/>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstAttribute="height" constant="1" id="VEz-6j-37B"/>
|
|
||||||
</constraints>
|
|
||||||
</view>
|
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="3d0-Jf-WT4">
|
|
||||||
<rect key="frame" x="0.0" y="83" width="478" height="22"/>
|
|
||||||
<subviews>
|
|
||||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="v8s-eL-K9J">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="89" height="22"/>
|
|
||||||
<color key="tintColor" systemColor="secondaryLabelColor"/>
|
|
||||||
<state key="normal" image="bubble.right" catalog="system">
|
|
||||||
<preferredSymbolConfiguration key="preferredSymbolConfiguration" scale="medium"/>
|
|
||||||
</state>
|
|
||||||
</button>
|
|
||||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="c9q-Xj-ZhU">
|
|
||||||
<rect key="frame" x="97" y="0.0" width="89.5" height="22"/>
|
|
||||||
<color key="tintColor" systemColor="secondaryLabelColor"/>
|
|
||||||
<state key="normal" image="arrow.2.squarepath" catalog="system">
|
|
||||||
<preferredSymbolConfiguration key="preferredSymbolConfiguration" scale="medium"/>
|
|
||||||
</state>
|
|
||||||
</button>
|
|
||||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="vKK-ho-Mc8">
|
|
||||||
<rect key="frame" x="194.5" y="0.0" width="89" height="22"/>
|
|
||||||
<color key="tintColor" systemColor="secondaryLabelColor"/>
|
|
||||||
<state key="normal" image="star" catalog="system">
|
|
||||||
<preferredSymbolConfiguration key="preferredSymbolConfiguration" scale="medium"/>
|
|
||||||
</state>
|
|
||||||
</button>
|
|
||||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="jXx-KF-3pu">
|
|
||||||
<rect key="frame" x="291.5" y="0.0" width="89.5" height="22"/>
|
|
||||||
<color key="tintColor" systemColor="secondaryLabelColor"/>
|
|
||||||
<state key="normal" image="square.and.arrow.up" catalog="system">
|
|
||||||
<preferredSymbolConfiguration key="preferredSymbolConfiguration" scale="medium"/>
|
|
||||||
</state>
|
|
||||||
</button>
|
|
||||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fN1-ao-eiV">
|
|
||||||
<rect key="frame" x="389" y="0.0" width="89" height="22"/>
|
|
||||||
<color key="tintColor" systemColor="secondaryLabelColor"/>
|
|
||||||
<state key="normal" image="ellipsis" catalog="system">
|
|
||||||
<preferredSymbolConfiguration key="preferredSymbolConfiguration" scale="medium"/>
|
|
||||||
</state>
|
|
||||||
</button>
|
|
||||||
</subviews>
|
|
||||||
</stackView>
|
|
||||||
</subviews>
|
|
||||||
</stackView>
|
|
||||||
</subviews>
|
|
||||||
</stackView>
|
|
||||||
</subviews>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstItem="aO2-AK-zwO" firstAttribute="centerY" secondItem="FMa-fP-vr2" secondAttribute="centerY" id="7BM-p3-f6D"/>
|
|
||||||
<constraint firstItem="5nP-eN-kWB" firstAttribute="top" secondItem="svp-hj-Xn6" secondAttribute="top" constant="4" id="RnL-bC-GDa"/>
|
|
||||||
</constraints>
|
|
||||||
</stackView>
|
|
||||||
</subviews>
|
|
||||||
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
|
|
||||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstItem="EJV-En-WBg" firstAttribute="bottom" secondItem="H9l-Fc-4W4" secondAttribute="bottom" placeholder="YES" id="Lth-9x-m02"/>
|
|
||||||
<constraint firstItem="B6h-6a-Lty" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="RT6-M5-ebc"/>
|
|
||||||
<constraint firstItem="H9l-Fc-4W4" firstAttribute="top" secondItem="gwb-UL-Eqa" secondAttribute="top" placeholder="YES" id="XC0-mr-t3K"/>
|
|
||||||
<constraint firstAttribute="trailing" secondItem="B6h-6a-Lty" secondAttribute="trailing" id="bec-RP-T0Q"/>
|
|
||||||
<constraint firstItem="B6h-6a-Lty" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="lcG-od-cwq"/>
|
|
||||||
<constraint firstAttribute="bottom" secondItem="B6h-6a-Lty" secondAttribute="bottom" id="ub9-zr-Efi"/>
|
|
||||||
</constraints>
|
|
||||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
|
||||||
<point key="canvasLocation" x="125" y="60"/>
|
|
||||||
</view>
|
|
||||||
</objects>
|
|
||||||
<resources>
|
|
||||||
<image name="arrow.2.squarepath" catalog="system" width="128" height="89"/>
|
|
||||||
<image name="bubble.right" catalog="system" width="128" height="110"/>
|
|
||||||
<image name="ellipsis" catalog="system" width="128" height="37"/>
|
|
||||||
<image name="square.and.arrow.up" catalog="system" width="115" height="128"/>
|
|
||||||
<image name="star" catalog="system" width="128" height="116"/>
|
|
||||||
<systemColor name="linkColor">
|
|
||||||
<color red="0.0" green="0.47843137254901963" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
|
||||||
</systemColor>
|
|
||||||
<systemColor name="quaternaryLabelColor">
|
|
||||||
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.17999999999999999" colorSpace="custom" customColorSpace="sRGB"/>
|
|
||||||
</systemColor>
|
|
||||||
<systemColor name="secondaryLabelColor">
|
|
||||||
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
|
||||||
</systemColor>
|
|
||||||
<systemColor name="separatorColor">
|
|
||||||
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.28999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
|
||||||
</systemColor>
|
|
||||||
<systemColor name="systemBackgroundColor">
|
|
||||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
|
||||||
</systemColor>
|
|
||||||
<systemColor name="tertiaryLabelColor">
|
|
||||||
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.29999999999999999" colorSpace="custom" customColorSpace="sRGB"/>
|
|
||||||
</systemColor>
|
|
||||||
</resources>
|
|
||||||
</document>
|
|
|
@ -6,7 +6,9 @@ extension CGFloat {
|
||||||
static let defaultSpacing: Self = 8
|
static let defaultSpacing: Self = 8
|
||||||
static let compactSpacing: Self = 4
|
static let compactSpacing: Self = 4
|
||||||
static let defaultCornerRadius: Self = 8
|
static let defaultCornerRadius: Self = 8
|
||||||
|
static let avatarDimension: Self = 50
|
||||||
static let hairline = 1 / UIScreen.main.scale
|
static let hairline = 1 / UIScreen.main.scale
|
||||||
|
static let minimumButtonDimension: Self = 44
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TimeInterval {
|
extension TimeInterval {
|
||||||
|
@ -16,3 +18,7 @@ extension TimeInterval {
|
||||||
extension UIImage {
|
extension UIImage {
|
||||||
static let highlightedButtonBackground = UIColor(white: 0, alpha: 0.5).image()
|
static let highlightedButtonBackground = UIColor(white: 0, alpha: 0.5).image()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension UILayoutPriority {
|
||||||
|
static let justBelowMax: Self = .init(999)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue