From 14f32f24faca6bec33971177f7519a09353f47ea Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Wed, 8 Nov 2023 16:37:12 -0500 Subject: [PATCH] visionOS: Use bordered prominent style for status actions --- ...ersationMainStatusCollectionViewCell.swift | 40 ++++++++++-- .../TimelineStatusCollectionViewCell.swift | 61 +++++++++++++++++-- Tusker/Views/ToggleableButton.swift | 7 ++- 3 files changed, 96 insertions(+), 12 deletions(-) diff --git a/Tusker/Views/Status/ConversationMainStatusCollectionViewCell.swift b/Tusker/Views/Status/ConversationMainStatusCollectionViewCell.swift index ea0fcbb7..f87da664 100644 --- a/Tusker/Views/Status/ConversationMainStatusCollectionViewCell.swift +++ b/Tusker/Views/Status/ConversationMainStatusCollectionViewCell.swift @@ -198,27 +198,51 @@ class ConversationMainStatusCollectionViewCell: UICollectionViewListCell, Status } private(set) lazy var replyButton = UIButton().configure { + #if os(visionOS) + var config = UIButton.Configuration.borderedProminent() + config.image = UIImage(systemName: "arrowshape.turn.up.left.fill") + $0.configuration = config + #else $0.setImage(UIImage(systemName: "arrowshape.turn.up.left.fill"), for: .normal) - $0.addTarget(self, action: #selector(replyPressed), for: .touchUpInside) $0.addInteraction(UIPointerInteraction(delegate: self)) + #endif + $0.addTarget(self, action: #selector(replyPressed), for: .touchUpInside) } private(set) lazy var favoriteButton = ToggleableButton(activeColor: UIColor(displayP3Red: 1, green: 0.8, blue: 0, alpha: 1)).configure { + #if os(visionOS) + var config = UIButton.Configuration.borderedProminent() + config.image = UIImage(systemName: "star.fill") + $0.configuration = config + #else $0.setImage(UIImage(systemName: "star.fill"), for: .normal) - $0.addTarget(self, action: #selector(favoritePressed), for: .touchUpInside) $0.addInteraction(UIPointerInteraction(delegate: self)) + #endif + $0.addTarget(self, action: #selector(favoritePressed), for: .touchUpInside) } private(set) lazy var reblogButton = ToggleableButton(activeColor: UIColor(displayP3Red: 1, green: 0.8, blue: 0, alpha: 1)).configure { + #if os(visionOS) + var config = UIButton.Configuration.borderedProminent() + config.image = UIImage(systemName: "repeat") + $0.configuration = config + #else $0.setImage(UIImage(systemName: "repeat"), for: .normal) - $0.addTarget(self, action: #selector(reblogPressed), for: .touchUpInside) $0.addInteraction(UIPointerInteraction(delegate: self)) + #endif + $0.addTarget(self, action: #selector(reblogPressed), for: .touchUpInside) } private(set) lazy var moreButton = UIButton().configure { + #if os(visionOS) + var config = UIButton.Configuration.borderedProminent() + config.image = UIImage(systemName: "ellipsis") + $0.configuration = config + #else $0.setImage(UIImage(systemName: "ellipsis"), for: .normal) - $0.showsMenuAsPrimaryAction = true $0.addInteraction(UIPointerInteraction(delegate: self)) + #endif + $0.showsMenuAsPrimaryAction = true } private var actionButtons: [UIButton] { @@ -233,9 +257,13 @@ class ConversationMainStatusCollectionViewCell: UICollectionViewListCell, Status ]).configure { $0.axis = .horizontal $0.distribution = .fillEqually + #if os(visionOS) + $0.spacing = 8 + #else NSLayoutConstraint.activate([ $0.heightAnchor.constraint(equalToConstant: 26), ]) + #endif } private let accountDetailToContentWarningSpacer = UIView().configure { @@ -278,8 +306,10 @@ class ConversationMainStatusCollectionViewCell: UICollectionViewListCell, Status contentContainer.widthAnchor.constraint(equalTo: $0.widthAnchor), firstSeparator.widthAnchor.constraint(equalTo: $0.widthAnchor), secondSeparator.widthAnchor.constraint(equalTo: $0.widthAnchor), - actionsHStack.widthAnchor.constraint(equalTo: $0.widthAnchor), ]) + #if !os(visionOS) + actionsHStack.widthAnchor.constraint(equalTo: $0.widthAnchor).isActive = true + #endif } var prevThreadLinkView: UIView? diff --git a/Tusker/Views/Status/TimelineStatusCollectionViewCell.swift b/Tusker/Views/Status/TimelineStatusCollectionViewCell.swift index d1edccd4..d79ee6ee 100644 --- a/Tusker/Views/Status/TimelineStatusCollectionViewCell.swift +++ b/Tusker/Views/Status/TimelineStatusCollectionViewCell.swift @@ -205,6 +205,17 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti contentContainer.pollView } + #if os(visionOS) + private lazy var actionsContainer = UIStackView(arrangedSubviews: [ + replyButton, + favoriteButton, + reblogButton, + moreButton, + ]).configure { + $0.axis = .horizontal + $0.spacing = 8 + } + #else private var placeholderReplyButtonLeadingConstraint: NSLayoutConstraint! private lazy var actionsContainer = UIView().configure { replyButton.translatesAutoresizingMaskIntoConstraints = false @@ -239,29 +250,54 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti moreButton.bottomAnchor.constraint(equalTo: $0.bottomAnchor), ]) } + #endif private(set) lazy var replyButton = UIButton().configure { + #if os(visionOS) + var config = UIButton.Configuration.borderedProminent() + config.image = UIImage(systemName: "arrowshape.turn.up.left.fill") + $0.configuration = config + #else $0.setImage(UIImage(systemName: "arrowshape.turn.up.left.fill"), for: .normal) - $0.addTarget(self, action: #selector(replyPressed), for: .touchUpInside) $0.addInteraction(UIPointerInteraction(delegate: self)) + #endif + $0.addTarget(self, action: #selector(replyPressed), for: .touchUpInside) } private(set) lazy var favoriteButton = ToggleableButton(activeColor: UIColor(displayP3Red: 1, green: 0.8, blue: 0, alpha: 1)).configure { + #if os(visionOS) + var config = UIButton.Configuration.borderedProminent() + config.image = UIImage(systemName: "star.fill") + $0.configuration = config + #else $0.setImage(UIImage(systemName: "star.fill"), for: .normal) - $0.addTarget(self, action: #selector(favoritePressed), for: .touchUpInside) $0.addInteraction(UIPointerInteraction(delegate: self)) + #endif + $0.addTarget(self, action: #selector(favoritePressed), for: .touchUpInside) } private(set) lazy var reblogButton = ToggleableButton(activeColor: UIColor(displayP3Red: 1, green: 0.8, blue: 0, alpha: 1)).configure { + #if os(visionOS) + var config = UIButton.Configuration.borderedProminent() + config.image = UIImage(systemName: "repeat") + $0.configuration = config + #else $0.setImage(UIImage(systemName: "repeat"), for: .normal) - $0.addTarget(self, action: #selector(reblogPressed), for: .touchUpInside) $0.addInteraction(UIPointerInteraction(delegate: self)) + #endif + $0.addTarget(self, action: #selector(reblogPressed), for: .touchUpInside) } private(set) lazy var moreButton = UIButton().configure { + #if os(visionOS) + var config = UIButton.Configuration.borderedProminent() + config.image = UIImage(systemName: "ellipsis") + $0.configuration = config + #else $0.setImage(UIImage(systemName: "ellipsis"), for: .normal) - $0.showsMenuAsPrimaryAction = true $0.addInteraction(UIPointerInteraction(delegate: self)) + #endif + $0.showsMenuAsPrimaryAction = true } private var actionButtons: [UIButton] { @@ -306,7 +342,9 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti private var rebloggerID: String? private var filterReason: String? + #if !os(visionOS) private var firstLayout = true + #endif var isGrayscale = false private var updateTimestampWorkItem: DispatchWorkItem? private var hasCreatedObservers = false @@ -339,14 +377,23 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti mainContainer.trailingAnchor.constraint(equalTo: statusContainer.trailingAnchor, constant: -16), mainContainerBottomToActionsConstraint, - actionsContainer.leadingAnchor.constraint(equalTo: statusContainer.leadingAnchor, constant: 16), - actionsContainer.trailingAnchor.constraint(equalTo: statusContainer.trailingAnchor, constant: -16), // yes, this is deliberately 6. 4 looks to cramped, 8 looks uneven actionsContainer.bottomAnchor.constraint(equalTo: statusContainer.bottomAnchor, constant: -6), metaIndicatorsView.bottomAnchor.constraint(lessThanOrEqualTo: statusContainer.bottomAnchor, constant: -6), ]) + #if os(visionOS) + NSLayoutConstraint.activate([ + actionsContainer.leadingAnchor.constraint(equalTo: contentVStack.leadingAnchor), + ]) + #else + NSLayoutConstraint.activate([ + actionsContainer.leadingAnchor.constraint(equalTo: statusContainer.leadingAnchor, constant: 16), + actionsContainer.trailingAnchor.constraint(equalTo: statusContainer.trailingAnchor, constant: -16), + ]) + #endif + updateActionsVisibility() NotificationCenter.default.addObserver(self, selector: #selector(preferencesChanged), name: .preferencesChanged, object: nil) @@ -359,6 +406,7 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti override func layoutSubviews() { super.layoutSubviews() + #if !os(visionOS) if firstLayout { firstLayout = false @@ -368,6 +416,7 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti placeholderReplyButtonLeadingConstraint.isActive = false replyButton.imageView!.leadingAnchor.constraint(equalTo: contentTextView.leadingAnchor).isActive = true } + #endif } override func updateConfiguration(using state: UICellConfigurationState) { diff --git a/Tusker/Views/ToggleableButton.swift b/Tusker/Views/ToggleableButton.swift index e380b8f9..0984ff5c 100644 --- a/Tusker/Views/ToggleableButton.swift +++ b/Tusker/Views/ToggleableButton.swift @@ -14,7 +14,12 @@ class ToggleableButton: UIButton { var active: Bool { didSet { - tintColor = active ? activeColor : nil + if var config = self.configuration { + config.baseForegroundColor = active ? activeColor : nil + self.configuration = config + } else { + tintColor = active ? activeColor : nil + } } }