Show post visibility indicator

This commit is contained in:
Natalia Ossipova 2023-02-13 13:36:04 +01:00
parent 065906c3d1
commit 21d1a59e7b
5 changed files with 67 additions and 414 deletions

View File

@ -390,7 +390,6 @@
DB9F58EC26EF435000E7BBE9 /* AccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9F58EB26EF435000E7BBE9 /* AccountViewController.swift */; };
DB9F58EF26EF491E00E7BBE9 /* AccountListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9F58EE26EF491E00E7BBE9 /* AccountListViewModel.swift */; };
DB9F58F126EF512300E7BBE9 /* AccountListTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9F58F026EF512300E7BBE9 /* AccountListTableViewCell.swift */; };
DBA0A11325FB3FC10079C110 /* ComposeToolbarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA0A11225FB3FC10079C110 /* ComposeToolbarView.swift */; };
DBA4B0F626C269880077136E /* Intents.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = DBA4B0F926C269880077136E /* Intents.stringsdict */; };
DBA4B0F726C269880077136E /* Intents.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = DBA4B0F926C269880077136E /* Intents.stringsdict */; };
DBA5A53126F08EF000CACBAA /* DragIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA5A53026F08EF000CACBAA /* DragIndicatorView.swift */; };
@ -1087,7 +1086,6 @@
DB9F58EB26EF435000E7BBE9 /* AccountViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountViewController.swift; sourceTree = "<group>"; };
DB9F58EE26EF491E00E7BBE9 /* AccountListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountListViewModel.swift; sourceTree = "<group>"; };
DB9F58F026EF512300E7BBE9 /* AccountListTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountListTableViewCell.swift; sourceTree = "<group>"; };
DBA0A11225FB3FC10079C110 /* ComposeToolbarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeToolbarView.swift; sourceTree = "<group>"; };
DBA4B0D326BD10AC0077136E /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Intents.strings"; sourceTree = "<group>"; };
DBA4B0D626BD10AD0077136E /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
DBA4B0D726BD10F40077136E /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/Intents.strings; sourceTree = "<group>"; };
@ -2164,7 +2162,6 @@
DB55D32225FB4D320002F825 /* View */ = {
isa = PBXGroup;
children = (
DBA0A11225FB3FC10079C110 /* ComposeToolbarView.swift */,
DB8190C52601FF0400020C08 /* AttachmentContainerView.swift */,
DB9A486B26032AC1008B817C /* AttachmentContainerView+EmptyStateView.swift */,
DBC7A671260C897100E57475 /* StatusContentWarningEditorView.swift */,
@ -3839,7 +3836,6 @@
DB45FAB625CA5485005A8AC7 /* UIAlertController.swift in Sources */,
DBE0821525CD382600FD6BBD /* MastodonRegisterViewController.swift in Sources */,
DBEFCD74282A130400C0ABEA /* ReportReasonViewModel.swift in Sources */,
DBA0A11325FB3FC10079C110 /* ComposeToolbarView.swift in Sources */,
DBFEEC96279BDC67004F81DD /* ProfileAboutViewController.swift in Sources */,
DB63F74F2799405600455B82 /* SearchHistoryViewModel+Diffable.swift in Sources */,
DB0EF72B26FDB1D200347686 /* SidebarListCollectionViewCell.swift in Sources */,

View File

@ -1,384 +0,0 @@
//
// ComposeToolbarView.swift
// Mastodon
//
// Created by MainasuK Cirno on 2021-3-12.
//
import os.log
import UIKit
import Combine
import MastodonSDK
import MastodonAsset
import MastodonCore
import MastodonUI
import MastodonLocalization
protocol ComposeToolbarViewDelegate: AnyObject {
func composeToolbarView(_ composeToolbarView: ComposeToolbarView, mediaButtonDidPressed sender: Any, mediaSelectionType type: ComposeToolbarView.MediaSelectionType)
func composeToolbarView(_ composeToolbarView: ComposeToolbarView, pollButtonDidPressed sender: Any)
func composeToolbarView(_ composeToolbarView: ComposeToolbarView, emojiButtonDidPressed sender: Any)
func composeToolbarView(_ composeToolbarView: ComposeToolbarView, contentWarningButtonDidPressed sender: Any)
func composeToolbarView(_ composeToolbarView: ComposeToolbarView, visibilityButtonDidPressed sender: Any, visibilitySelectionType type: ComposeToolbarView.VisibilitySelectionType)
}
final class ComposeToolbarView: UIView {
var disposeBag = Set<AnyCancellable>()
static let toolbarButtonSize: CGSize = CGSize(width: 44, height: 44)
static let toolbarHeight: CGFloat = 44
weak var delegate: ComposeToolbarViewDelegate?
// barButtonItem
private(set) lazy var mediaBarButtonItem: UIBarButtonItem = {
let barButtonItem = UIBarButtonItem()
barButtonItem.image = UIImage(systemName: "photo")
barButtonItem.accessibilityLabel = L10n.Scene.Compose.Accessibility.appendAttachment
return barButtonItem
}()
let pollBarButtonItem: UIBarButtonItem = {
let barButtonItem = UIBarButtonItem()
barButtonItem.image = UIImage(systemName: "list.bullet")
barButtonItem.accessibilityLabel = L10n.Scene.Compose.Accessibility.appendPoll
return barButtonItem
}()
let contentWarningBarButtonItem: UIBarButtonItem = {
let barButtonItem = UIBarButtonItem()
barButtonItem.image = UIImage(systemName: "exclamationmark.shield")
barButtonItem.accessibilityLabel = L10n.Scene.Compose.Accessibility.enableContentWarning
return barButtonItem
}()
let visibilityBarButtonItem: UIBarButtonItem = {
let barButtonItem = UIBarButtonItem()
barButtonItem.image = UIImage(systemName: "person.3")
barButtonItem.accessibilityLabel = L10n.Scene.Compose.Accessibility.postVisibilityMenu
return barButtonItem
}()
// button
let mediaButton: UIButton = {
let button = HighlightDimmableButton()
ComposeToolbarView.configureToolbarButtonAppearance(button: button)
button.setImage(UIImage(systemName: "photo", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .regular)), for: .normal)
button.accessibilityLabel = L10n.Scene.Compose.Accessibility.appendAttachment
return button
}()
let pollButton: UIButton = {
let button = HighlightDimmableButton(type: .custom)
ComposeToolbarView.configureToolbarButtonAppearance(button: button)
button.setImage(UIImage(systemName: "list.bullet", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .medium)), for: .normal)
button.accessibilityLabel = L10n.Scene.Compose.Accessibility.appendPoll
return button
}()
let emojiButton: UIButton = {
let button = HighlightDimmableButton()
ComposeToolbarView.configureToolbarButtonAppearance(button: button)
let image = Asset.Human.faceSmilingAdaptive.image
.af.imageScaled(to: CGSize(width: 20, height: 20))
.withRenderingMode(.alwaysTemplate)
button.setImage(image, for: .normal)
button.accessibilityLabel = L10n.Scene.Compose.Accessibility.customEmojiPicker
return button
}()
let contentWarningButton: UIButton = {
let button = HighlightDimmableButton()
ComposeToolbarView.configureToolbarButtonAppearance(button: button)
button.setImage(UIImage(systemName: "exclamationmark.shield", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .regular)), for: .normal)
button.accessibilityLabel = L10n.Scene.Compose.Accessibility.enableContentWarning
return button
}()
let visibilityButton: UIButton = {
let button = HighlightDimmableButton()
ComposeToolbarView.configureToolbarButtonAppearance(button: button)
button.setImage(UIImage(systemName: "person.3", withConfiguration: UIImage.SymbolConfiguration(pointSize: 15, weight: .medium)), for: .normal)
button.accessibilityLabel = L10n.Scene.Compose.Accessibility.postVisibilityMenu
return button
}()
let characterCountLabel: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 15, weight: .regular)
label.text = "500"
label.textColor = Asset.Colors.Label.secondary.color
label.accessibilityLabel = L10n.A11y.Plural.Count.inputLimitRemains(500)
return label
}()
let activeVisibilityType = CurrentValueSubject<VisibilitySelectionType, Never>(.public)
override init(frame: CGRect) {
super.init(frame: frame)
_init()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
_init()
}
}
extension ComposeToolbarView {
private func _init() {
setupBackgroundColor(theme: ThemeService.shared.currentTheme.value)
ThemeService.shared.currentTheme
.receive(on: DispatchQueue.main)
.sink { [weak self] theme in
guard let self = self else { return }
self.setupBackgroundColor(theme: theme)
}
.store(in: &disposeBag)
let stackView = UIStackView()
stackView.axis = .horizontal
stackView.spacing = 0
stackView.distribution = .fillEqually
stackView.translatesAutoresizingMaskIntoConstraints = false
addSubview(stackView)
NSLayoutConstraint.activate([
stackView.centerYAnchor.constraint(equalTo: centerYAnchor),
layoutMarginsGuide.leadingAnchor.constraint(equalTo: stackView.leadingAnchor, constant: 8), // tweak button margin offset
])
let buttons = [
mediaButton,
pollButton,
emojiButton,
contentWarningButton,
visibilityButton,
]
buttons.forEach { button in
button.translatesAutoresizingMaskIntoConstraints = false
stackView.addArrangedSubview(button)
NSLayoutConstraint.activate([
button.widthAnchor.constraint(equalToConstant: 44),
button.heightAnchor.constraint(equalToConstant: 44),
])
}
characterCountLabel.translatesAutoresizingMaskIntoConstraints = false
addSubview(characterCountLabel)
NSLayoutConstraint.activate([
characterCountLabel.topAnchor.constraint(equalTo: topAnchor),
characterCountLabel.leadingAnchor.constraint(greaterThanOrEqualTo: stackView.trailingAnchor, constant: 8),
characterCountLabel.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),
characterCountLabel.bottomAnchor.constraint(equalTo: bottomAnchor),
])
characterCountLabel.setContentHuggingPriority(.defaultHigh, for: .horizontal)
mediaBarButtonItem.menu = createMediaContextMenu()
mediaButton.menu = createMediaContextMenu()
mediaButton.showsMenuAsPrimaryAction = true
pollBarButtonItem.target = self
pollBarButtonItem.action = #selector(ComposeToolbarView.pollButtonDidPressed(_:))
pollButton.addTarget(self, action: #selector(ComposeToolbarView.pollButtonDidPressed(_:)), for: .touchUpInside)
emojiButton.addTarget(self, action: #selector(ComposeToolbarView.emojiButtonDidPressed(_:)), for: .touchUpInside)
contentWarningBarButtonItem.target = self
contentWarningBarButtonItem.action = #selector(ComposeToolbarView.contentWarningButtonDidPressed(_:))
contentWarningButton.addTarget(self, action: #selector(ComposeToolbarView.contentWarningButtonDidPressed(_:)), for: .touchUpInside)
visibilityBarButtonItem.menu = createVisibilityContextMenu(interfaceStyle: traitCollection.userInterfaceStyle)
visibilityButton.menu = createVisibilityContextMenu(interfaceStyle: traitCollection.userInterfaceStyle)
visibilityButton.showsMenuAsPrimaryAction = true
updateToolbarButtonUserInterfaceStyle()
// update menu when selected visibility type changed
activeVisibilityType
.receive(on: RunLoop.main)
.sink { [weak self] type in
guard let self = self else { return }
self.visibilityBarButtonItem.menu = self.createVisibilityContextMenu(interfaceStyle: self.traitCollection.userInterfaceStyle)
self.visibilityButton.menu = self.createVisibilityContextMenu(interfaceStyle: self.traitCollection.userInterfaceStyle)
}
.store(in: &disposeBag)
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
updateToolbarButtonUserInterfaceStyle()
}
}
extension ComposeToolbarView {
enum MediaSelectionType: String {
case camera
case photoLibrary
case browse
}
enum VisibilitySelectionType: String, CaseIterable {
case `public`
// TODO: remove unlisted option from codebase
// case unlisted
case `private`
case direct
var title: String {
switch self {
case .public: return L10n.Scene.Compose.Visibility.public
// case .unlisted: return L10n.Scene.Compose.Visibility.unlisted
case .private: return L10n.Scene.Compose.Visibility.private
case .direct: return L10n.Scene.Compose.Visibility.direct
}
}
func image(interfaceStyle: UIUserInterfaceStyle) -> UIImage {
switch self {
case .public: return UIImage(systemName: "globe", withConfiguration: UIImage.SymbolConfiguration(pointSize: 19, weight: .medium))!
// case .unlisted: return UIImage(systemName: "eye.slash", withConfiguration: UIImage.SymbolConfiguration(pointSize: 18, weight: .regular))!
case .private:
switch interfaceStyle {
case .light: return UIImage(systemName: "person.3", withConfiguration: UIImage.SymbolConfiguration(pointSize: 15, weight: .medium))!
default: return UIImage(systemName: "person.3.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 15, weight: .medium))!
}
case .direct: return UIImage(systemName: "at", withConfiguration: UIImage.SymbolConfiguration(pointSize: 19, weight: .regular))!
}
}
var visibility: Mastodon.Entity.Status.Visibility {
switch self {
case .public: return .public
// case .unlisted: return .unlisted
case .private: return .private
case .direct: return .direct
}
}
}
}
extension ComposeToolbarView {
private func setupBackgroundColor(theme: Theme) {
backgroundColor = theme.composeToolbarBackgroundColor
}
private static func configureToolbarButtonAppearance(button: UIButton) {
button.tintColor = ThemeService.tintColor
button.setBackgroundImage(.placeholder(size: ComposeToolbarView.toolbarButtonSize, color: .systemFill), for: .highlighted)
button.layer.masksToBounds = true
button.layer.cornerRadius = 5
button.layer.cornerCurve = .continuous
}
private func updateToolbarButtonUserInterfaceStyle() {
// reset emoji
let emojiButtonImage = Asset.Human.faceSmilingAdaptive.image
.af.imageScaled(to: CGSize(width: 20, height: 20))
.withRenderingMode(.alwaysTemplate)
emojiButton.setImage(emojiButtonImage, for: .normal)
switch traitCollection.userInterfaceStyle {
case .light:
mediaBarButtonItem.image = UIImage(systemName: "photo")
mediaButton.setImage(UIImage(systemName: "photo", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .regular))!, for: .normal)
contentWarningBarButtonItem.image = UIImage(systemName: "exclamationmark.shield")
contentWarningButton.setImage(UIImage(systemName: "exclamationmark.shield", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .regular))!, for: .normal)
case .dark:
mediaBarButtonItem.image = UIImage(systemName: "photo.fill")
mediaButton.setImage(UIImage(systemName: "photo.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .regular))!, for: .normal)
contentWarningBarButtonItem.image = UIImage(systemName: "exclamationmark.shield.fill")
contentWarningButton.setImage(UIImage(systemName: "exclamationmark.shield.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .regular))!, for: .normal)
default:
assertionFailure()
}
visibilityBarButtonItem.menu = createVisibilityContextMenu(interfaceStyle: traitCollection.userInterfaceStyle)
visibilityButton.menu = createVisibilityContextMenu(interfaceStyle: traitCollection.userInterfaceStyle)
}
private func createMediaContextMenu() -> UIMenu {
var children: [UIMenuElement] = []
let photoLibraryAction = UIAction(title: L10n.Scene.Compose.MediaSelection.photoLibrary, image: UIImage(systemName: "rectangle.on.rectangle"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak self] _ in
guard let self = self else { return }
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: mediaSelectionType: .photoLibrary", ((#file as NSString).lastPathComponent), #line, #function)
self.delegate?.composeToolbarView(self, mediaButtonDidPressed: self.mediaButton, mediaSelectionType: .photoLibrary)
}
children.append(photoLibraryAction)
if UIImagePickerController.isSourceTypeAvailable(.camera) {
let cameraAction = UIAction(title: L10n.Scene.Compose.MediaSelection.camera, image: UIImage(systemName: "camera"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off, handler: { [weak self] _ in
guard let self = self else { return }
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: mediaSelectionType: .camera", ((#file as NSString).lastPathComponent), #line, #function)
self.delegate?.composeToolbarView(self, mediaButtonDidPressed: self.mediaButton, mediaSelectionType: .camera)
})
children.append(cameraAction)
}
let browseAction = UIAction(title: L10n.Scene.Compose.MediaSelection.browse, image: UIImage(systemName: "ellipsis"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak self] _ in
guard let self = self else { return }
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: mediaSelectionType: .browse", ((#file as NSString).lastPathComponent), #line, #function)
self.delegate?.composeToolbarView(self, mediaButtonDidPressed: self.mediaButton, mediaSelectionType: .browse)
}
children.append(browseAction)
return UIMenu(title: "", image: nil, identifier: nil, options: .displayInline, children: children)
}
private func createVisibilityContextMenu(interfaceStyle: UIUserInterfaceStyle) -> UIMenu {
let children: [UIMenuElement] = VisibilitySelectionType.allCases.map { type in
let state: UIMenuElement.State = activeVisibilityType.value == type ? .on : .off
return UIAction(title: type.title, image: type.image(interfaceStyle: interfaceStyle), identifier: nil, discoverabilityTitle: nil, attributes: [], state: state) { [weak self] action in
guard let self = self else { return }
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: visibilitySelectionType: %s", ((#file as NSString).lastPathComponent), #line, #function, type.rawValue)
self.delegate?.composeToolbarView(self, visibilityButtonDidPressed: self.visibilityButton, visibilitySelectionType: type)
}
}
return UIMenu(title: "", image: nil, identifier: nil, options: .displayInline, children: children)
}
}
extension ComposeToolbarView {
@objc private func pollButtonDidPressed(_ sender: Any) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
delegate?.composeToolbarView(self, pollButtonDidPressed: sender)
}
@objc private func emojiButtonDidPressed(_ sender: Any) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
delegate?.composeToolbarView(self, emojiButtonDidPressed: sender)
}
@objc private func contentWarningButtonDidPressed(_ sender: Any) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
delegate?.composeToolbarView(self, contentWarningButtonDidPressed: sender)
}
}
#if canImport(SwiftUI) && DEBUG
import SwiftUI
struct ComposeToolbarView_Previews: PreviewProvider {
static var previews: some View {
UIViewPreview(width: 375) {
let toolbarView = ComposeToolbarView()
toolbarView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
toolbarView.widthAnchor.constraint(equalToConstant: 375).priority(.defaultHigh),
toolbarView.heightAnchor.constraint(equalToConstant: 64).priority(.defaultHigh),
])
return toolbarView
}
.previewLayout(.fixed(width: 375, height: 100))
}
}
#endif

View File

@ -131,7 +131,6 @@ extension ComposeContentViewController {
toolbarHostingView.view.heightAnchor.constraint(equalToConstant: ComposeContentToolbarView.toolbarHeight),
])
toolbarHostingView.view.preservesSuperviewLayoutMargins = true
//composeToolbarView.delegate = self
composeContentToolbarBackgroundView.translatesAutoresizingMaskIntoConstraints = false
view.insertSubview(composeContentToolbarBackgroundView, belowSubview: toolbarHostingView.view)

View File

@ -41,9 +41,23 @@ public class StatusAuthorView: UIStackView {
// timestamp
public let dateLabel = MetaLabel(style: .statusUsername)
public let dateTrailingDotLabel: MetaLabel = {
let label = MetaLabel(style: .statusUsername)
label.configure(content: PlaintextMetaContent(string: "·"))
return label
}()
let visibilityIconImageView: UIImageView = {
let imageView = UIImageView()
imageView.tintColor = Asset.Colors.Label.secondary.color
imageView.contentMode = .scaleAspectFit
imageView.image = Asset.Scene.Compose.earth.image.withRenderingMode(.alwaysTemplate)
return imageView
}()
public let menuButton: UIButton = {
let button = HitTestExpandedButton(type: .system)
button.expandEdgeInsets = UIEdgeInsets(top: -20, left: -10, bottom: -5, right: -10)
button.expandEdgeInsets = UIEdgeInsets(top: -20, left: -10, bottom: -10, right: -10)
button.tintColor = Asset.Colors.Label.secondary.color
let image = UIImage(systemName: "ellipsis", withConfiguration: UIImage.SymbolConfiguration(font: .systemFont(ofSize: 15)))
button.setImage(image, for: .normal)
@ -53,11 +67,10 @@ public class StatusAuthorView: UIStackView {
public let contentSensitiveeToggleButton: UIButton = {
let button = HitTestExpandedButton(type: .system)
button.expandEdgeInsets = UIEdgeInsets(top: -5, left: -10, bottom: -20, right: -10)
button.expandEdgeInsets = UIEdgeInsets(top: -20, left: -10, bottom: -10, right: -10)
button.tintColor = Asset.Colors.Label.secondary.color
button.imageView?.contentMode = .scaleAspectFill
button.imageView?.clipsToBounds = false
let image = UIImage(systemName: "eye.slash.fill", withConfiguration: UIImage.SymbolConfiguration(font: .systemFont(ofSize: 15)))
button.imageView?.contentMode = .scaleAspectFit
let image = UIImage(systemName: "eye.slash.fill")
button.setImage(image, for: .normal)
return button
}()
@ -137,6 +150,8 @@ extension StatusAuthorView {
// dateLabel
dateLabel.isUserInteractionEnabled = false
visibilityIconImageView.isUserInteractionEnabled = false
}
}
@ -245,47 +260,59 @@ extension StatusAuthorView {
// authorPrimaryMetaContainer: H - [ authorNameLabel | (padding) | menuButton ]
let authorPrimaryMetaContainer = UIStackView()
authorPrimaryMetaContainer.axis = .horizontal
authorPrimaryMetaContainer.spacing = 10
authorPrimaryMetaContainer.alignment = .center
authorPrimaryMetaContainer.spacing = 8
authorMetaContainer.addArrangedSubview(authorPrimaryMetaContainer)
// authorNameLabel
authorPrimaryMetaContainer.addArrangedSubview(authorNameLabel)
authorNameLabel.setContentHuggingPriority(.required - 10, for: .horizontal)
authorNameLabel.setContentCompressionResistancePriority(.required - 10, for: .horizontal)
authorNameLabel.setContentHuggingPriority(.required - 1, for: .vertical)
authorNameLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
authorPrimaryMetaContainer.addArrangedSubview(UIView())
authorPrimaryMetaContainer.addArrangedSubview(contentSensitiveeToggleButton)
NSLayoutConstraint.activate([
contentSensitiveeToggleButton.heightAnchor.constraint(equalToConstant: 18),
])
authorPrimaryMetaContainer.setCustomSpacing(16, after: contentSensitiveeToggleButton)
// menuButton
authorPrimaryMetaContainer.addArrangedSubview(menuButton)
menuButton.setContentHuggingPriority(.required - 2, for: .horizontal)
menuButton.setContentCompressionResistancePriority(.required - 2, for: .horizontal)
menuButton.setContentHuggingPriority(.required - 1, for: .horizontal)
menuButton.setContentCompressionResistancePriority(.required - 1, for: .horizontal)
// authorSecondaryMetaContainer: H - [ authorUsername | usernameTrialingDotLabel | dateLabel | (padding) | contentSensitiveeToggleButton ]
let authorSecondaryMetaContainer = UIStackView()
authorSecondaryMetaContainer.axis = .horizontal
authorSecondaryMetaContainer.alignment = .center
authorSecondaryMetaContainer.spacing = 4
authorMetaContainer.addArrangedSubview(authorSecondaryMetaContainer)
authorSecondaryMetaContainer.addArrangedSubview(authorUsernameLabel)
authorUsernameLabel.setContentHuggingPriority(.required - 8, for: .horizontal)
authorUsernameLabel.setContentCompressionResistancePriority(.required - 8, for: .horizontal)
authorUsernameLabel.setContentHuggingPriority(.required - 1, for: .vertical)
authorUsernameLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
authorSecondaryMetaContainer.addArrangedSubview(usernameTrialingDotLabel)
usernameTrialingDotLabel.setContentHuggingPriority(.required - 2, for: .horizontal)
usernameTrialingDotLabel.setContentCompressionResistancePriority(.required - 2, for: .horizontal)
usernameTrialingDotLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
authorSecondaryMetaContainer.addArrangedSubview(dateLabel)
dateLabel.setContentHuggingPriority(.required - 1, for: .horizontal)
dateLabel.setContentCompressionResistancePriority(.required - 1, for: .horizontal)
authorSecondaryMetaContainer.addArrangedSubview(UIView())
contentSensitiveeToggleButton.translatesAutoresizingMaskIntoConstraints = false
authorSecondaryMetaContainer.addArrangedSubview(contentSensitiveeToggleButton)
authorSecondaryMetaContainer.addArrangedSubview(dateTrailingDotLabel)
dateTrailingDotLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
authorSecondaryMetaContainer.addArrangedSubview(visibilityIconImageView)
NSLayoutConstraint.activate([
contentSensitiveeToggleButton.heightAnchor.constraint(equalTo: authorUsernameLabel.heightAnchor, multiplier: 1.0).priority(.required - 1),
contentSensitiveeToggleButton.widthAnchor.constraint(equalTo: contentSensitiveeToggleButton.heightAnchor, multiplier: 1.0).priority(.required - 1),
visibilityIconImageView.heightAnchor.constraint(equalTo: authorUsernameLabel.heightAnchor),
visibilityIconImageView.widthAnchor.constraint(equalTo: visibilityIconImageView.heightAnchor),
])
authorUsernameLabel.setContentHuggingPriority(.required - 1, for: .vertical)
authorUsernameLabel.setContentCompressionResistancePriority(.required - 1, for: .vertical)
contentSensitiveeToggleButton.setContentHuggingPriority(.defaultLow, for: .vertical)
contentSensitiveeToggleButton.setContentHuggingPriority(.defaultLow, for: .horizontal)
contentSensitiveeToggleButton.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
contentSensitiveeToggleButton.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
authorSecondaryMetaContainer.setCustomSpacing(0, after: visibilityIconImageView)
authorSecondaryMetaContainer.addArrangedSubview(UIView())
}
func layoutReport() {

View File

@ -283,6 +283,21 @@ extension StatusView.ViewModel {
authorView.dateLabel.configure(content: PlaintextMetaContent(string: text))
}
.store(in: &disposeBag)
$visibility
.map {
switch $0 {
case .public: return Asset.Scene.Compose.earth
case .unlisted: return Asset.Scene.Compose.people
case .private: return Asset.Scene.Compose.peopleAdd
case .direct: return Asset.Scene.Compose.mention
case ._other: return Asset.Scene.Compose.more
}
}
.sink {
authorView.visibilityIconImageView.image = $0.image.withRenderingMode(.alwaysTemplate)
}
.store(in: &disposeBag)
}
private func bindContent(statusView: StatusView) {