From e68100eb7138b648b4ce7c8d629c5afb5dc751a9 Mon Sep 17 00:00:00 2001 From: Fahim Farook Date: Wed, 25 Jan 2023 10:00:34 +0400 Subject: [PATCH 1/3] Duckable Issue * IF you have the .testTarget enabled, on Xcode 14.2 you get an error about the test target source needing to be under the "Tests" folder or something similar --- Packages/Duckable/Package.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Packages/Duckable/Package.swift b/Packages/Duckable/Package.swift index 2e7a085d..ca4e3570 100644 --- a/Packages/Duckable/Package.swift +++ b/Packages/Duckable/Package.swift @@ -24,8 +24,8 @@ let package = Package( .target( name: "Duckable", dependencies: []), - .testTarget( - name: "DuckableTests", - dependencies: ["Duckable"]), +// .testTarget( +// name: "DuckableTests", +// dependencies: ["Duckable"]), ] ) -- 2.34.1 From ea30b9866d0ddd271b31a43154f05ac2d21f8789 Mon Sep 17 00:00:00 2001 From: Fahim Farook Date: Wed, 25 Jan 2023 15:25:53 +0400 Subject: [PATCH 2/3] Collapsible Cells * Change the look of the collapsible cell * Add a reason to the collapsed cell --- .../Pachyderm/Utilities/CollapseState.swift | 1 + Tusker/Extensions/StatusStateResolver.swift | 8 +- ...ersationMainStatusCollectionViewCell.swift | 13 +-- .../Views/Status/StatusCollapseButton.swift | 91 ++++++++++++++++--- .../Status/StatusCollectionViewCell.swift | 5 +- .../TimelineStatusCollectionViewCell.swift | 16 +--- 6 files changed, 95 insertions(+), 39 deletions(-) diff --git a/Packages/Pachyderm/Sources/Pachyderm/Utilities/CollapseState.swift b/Packages/Pachyderm/Sources/Pachyderm/Utilities/CollapseState.swift index 6370d7e9..89799ad8 100644 --- a/Packages/Pachyderm/Sources/Pachyderm/Utilities/CollapseState.swift +++ b/Packages/Pachyderm/Sources/Pachyderm/Utilities/CollapseState.swift @@ -11,6 +11,7 @@ import Foundation public class CollapseState: Equatable { public var collapsible: Bool? public var collapsed: Bool? + public var reason = "" public var unknown: Bool { collapsible == nil || collapsed == nil diff --git a/Tusker/Extensions/StatusStateResolver.swift b/Tusker/Extensions/StatusStateResolver.swift index 4c5901bd..e7f1160f 100644 --- a/Tusker/Extensions/StatusStateResolver.swift +++ b/Tusker/Extensions/StatusStateResolver.swift @@ -16,6 +16,7 @@ extension CollapseState { if Preferences.shared.collapseLongPosts, height > 600 || (textLength != nil && textLength! > 500) { longEnoughToCollapse = true + self.reason = "Read More ..." } else { longEnoughToCollapse = false } @@ -25,13 +26,16 @@ extension CollapseState { let collapseDueToContentWarning: Bool? if contentWarningCollapsible { let lowercased = status.spoilerText.lowercased() - let opposite = Preferences.shared.oppositeCollapseKeywords.contains { lowercased.contains($0.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()) } - + let opposite = Preferences.shared.oppositeCollapseKeywords.contains { lowercased.contains($0.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()) + } if Preferences.shared.expandAllContentWarnings { collapseDueToContentWarning = opposite } else { collapseDueToContentWarning = !opposite } + if let collapse = collapseDueToContentWarning, collapse { + self.reason = "Content Warning" + } } else { collapseDueToContentWarning = nil } diff --git a/Tusker/Views/Status/ConversationMainStatusCollectionViewCell.swift b/Tusker/Views/Status/ConversationMainStatusCollectionViewCell.swift index 279c7d26..0991e697 100644 --- a/Tusker/Views/Status/ConversationMainStatusCollectionViewCell.swift +++ b/Tusker/Views/Status/ConversationMainStatusCollectionViewCell.swift @@ -104,16 +104,9 @@ class ConversationMainStatusCollectionViewCell: UICollectionViewListCell, Status $0.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(collapseButtonPressed))) } - private(set) lazy var collapseButton = StatusCollapseButton(configuration: { - var config = UIButton.Configuration.filled() - config.image = UIImage(systemName: "chevron.down") - return config - }()).configure { - // this button is so big that dimming its background color is visually distracting - $0.tintAdjustmentMode = .normal - $0.setContentHuggingPriority(.defaultHigh, for: .vertical) - $0.addTarget(self, action: #selector(collapseButtonPressed), for: .touchUpInside) - } + private(set) lazy var collapseButton = StatusCollapseButton { + self.toggleCollapse() + } let contentContainer = StatusContentContainer(useTopSpacer: true).configure { $0.contentTextView.defaultFont = ConversationMainStatusCollectionViewCell.contentFont diff --git a/Tusker/Views/Status/StatusCollapseButton.swift b/Tusker/Views/Status/StatusCollapseButton.swift index a0a2d513..d4830170 100644 --- a/Tusker/Views/Status/StatusCollapseButton.swift +++ b/Tusker/Views/Status/StatusCollapseButton.swift @@ -8,18 +8,85 @@ import UIKit -class StatusCollapseButton: UIButton { +class StatusCollapseButton: UIView { + var title: String { + get { + return lblTitle.text ?? "" + } + set { + lblTitle.text = newValue + } + } + + private var action: (()->Void)! + private var lblTitle = UILabel() + private var imgView = UIImageView() + private var isCollapsed = true + + convenience init(action: @escaping (()->Void)) { + self.init(frame: CGRect.zero) + self.action = action + } - private var interactionBounds: CGRect! - - override func layoutSubviews() { - super.layoutSubviews() - - interactionBounds = bounds.inset(by: UIEdgeInsets(top: -8, left: 0, bottom: 0, right: 0)) - } - - override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { - return interactionBounds.contains(point) - } + override init(frame: CGRect) { + super.init(frame: frame) + setup() + } + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + override func touchesBegan(_ touches: Set, with event: UIEvent?) { + // Eat event + } + + override func touchesMoved(_ touches: Set, with event: UIEvent?) { + // Eat event + } + + override func touchesCancelled(_ touches: Set, with event: UIEvent?) { + // Eat event + } + + override func touchesEnded(_ touches: Set, with event: UIEvent?) { + if isCollapsed { + imgView.image = UIImage(systemName: "chevron.compact.up") + } else { + imgView.image = UIImage(systemName: "chevron.compact.down") + } + isCollapsed.toggle() + action() + } + + // MARK: - Private Methods + private func setup() { + self.isUserInteractionEnabled = true + layer.cornerRadius = 8 + backgroundColor = .lightGray + // Title + lblTitle.translatesAutoresizingMaskIntoConstraints = false + lblTitle.textColor = .white + lblTitle.textAlignment = .center + addSubview(lblTitle) + // Chevron + imgView.translatesAutoresizingMaskIntoConstraints = false + imgView.tintColor = .white + imgView.image = UIImage(systemName: "chevron.compact.down") + addSubview(imgView) + NSLayoutConstraint.activate([ + // Main view + heightAnchor.constraint(equalToConstant: 30), + // Title + lblTitle.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8), + lblTitle.topAnchor.constraint(equalTo: topAnchor, constant: 8), + lblTitle.trailingAnchor.constraint(equalTo: imgView.leadingAnchor, constant: -4), + lblTitle.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8), + // Chevron + imgView.widthAnchor.constraint(equalToConstant: 20), + imgView.topAnchor.constraint(equalTo: topAnchor, constant: 5), + imgView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8), + imgView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -5) + ]) + } } diff --git a/Tusker/Views/Status/StatusCollectionViewCell.swift b/Tusker/Views/Status/StatusCollectionViewCell.swift index 9a27d04a..751e0238 100644 --- a/Tusker/Views/Status/StatusCollectionViewCell.swift +++ b/Tusker/Views/Status/StatusCollectionViewCell.swift @@ -113,17 +113,16 @@ extension StatusCollectionViewCell { if statusState.collapsible! && showStatusAutomatically { statusState.collapsed = false } - } + } + collapseButton.title = statusState.reason collapseButton.isHidden = !statusState.collapsible! contentContainer.setCollapsed(statusState.collapsed!) if statusState.collapsed! { contentContainer.alpha = 0 // TODO: is this accessing the image view before the button's been laid out? - collapseButton.imageView!.transform = CGAffineTransform(rotationAngle: 0) collapseButton.accessibilityLabel = NSLocalizedString("Expand Status", comment: "expand status button accessibility label") } else { contentContainer.alpha = 1 - collapseButton.imageView!.transform = CGAffineTransform(rotationAngle: .pi) collapseButton.accessibilityLabel = NSLocalizedString("Collapse Status", comment: "collapse status button accessibility label") } } diff --git a/Tusker/Views/Status/TimelineStatusCollectionViewCell.swift b/Tusker/Views/Status/TimelineStatusCollectionViewCell.swift index b02b475d..524a1974 100644 --- a/Tusker/Views/Status/TimelineStatusCollectionViewCell.swift +++ b/Tusker/Views/Status/TimelineStatusCollectionViewCell.swift @@ -14,7 +14,6 @@ private let reblogIcon = UIImage(systemName: "repeat") private let hashtagIcon = UIImage(systemName: "number") class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollectionViewCell { - static let separatorInsets = NSDirectionalEdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 0) static let contentFont = UIFontMetrics.default.scaledFont(for: .systemFont(ofSize: 16)) static let monospaceFont = UIFontMetrics.default.scaledFont(for: .monospacedSystemFont(ofSize: 16, weight: .regular)) @@ -154,17 +153,10 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti $0.isUserInteractionEnabled = true $0.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(collapseButtonPressed))) } - - private(set) lazy var collapseButton = StatusCollapseButton(configuration: { - var config = UIButton.Configuration.filled() - config.image = UIImage(systemName: "chevron.down") - return config - }()).configure { - // this button is so big that dimming its background color is visually distracting - $0.tintAdjustmentMode = .normal - $0.setContentHuggingPriority(.defaultHigh, for: .vertical) - $0.addTarget(self, action: #selector(collapseButtonPressed), for: .touchUpInside) - } + + private(set) lazy var collapseButton = StatusCollapseButton { + self.toggleCollapse() + } let contentContainer = StatusContentContainer(useTopSpacer: false).configure { $0.contentTextView.defaultFont = TimelineStatusCollectionViewCell.contentFont -- 2.34.1 From 80f21cb2f18e3b817d3b92e754e33b0bc6f21efb Mon Sep 17 00:00:00 2001 From: Fahim Farook Date: Wed, 25 Jan 2023 17:06:47 +0400 Subject: [PATCH 3/3] Collapsible Table Cells * Fix the table cell instances to use the new collapsible button * Add accessibility label to StatusCollapseButton and change button to allow setting action --- .../Status/BaseStatusTableViewCell.swift | 42 ++----------------- .../Views/Status/StatusCollapseButton.swift | 7 +++- .../Status/TimelineStatusTableViewCell.swift | 2 + .../Status/TimelineStatusTableViewCell.xib | 32 +++----------- 4 files changed, 17 insertions(+), 66 deletions(-) diff --git a/Tusker/Views/Status/BaseStatusTableViewCell.swift b/Tusker/Views/Status/BaseStatusTableViewCell.swift index 37f20974..c6c935eb 100644 --- a/Tusker/Views/Status/BaseStatusTableViewCell.swift +++ b/Tusker/Views/Status/BaseStatusTableViewCell.swift @@ -31,7 +31,7 @@ class BaseStatusTableViewCell: UITableViewCell { @IBOutlet weak var usernameLabel: UILabel! @IBOutlet weak var metaIndicatorsView: StatusMetaIndicatorsView! @IBOutlet weak var contentWarningLabel: EmojiLabel! - @IBOutlet weak var collapseButton: UIButton! + @IBOutlet weak var collapseButton: StatusCollapseButton! @IBOutlet weak var contentTextView: StatusContentTextView! @IBOutlet weak var cardView: StatusCardView! @IBOutlet weak var attachmentsView: AttachmentsContainerView! @@ -91,10 +91,7 @@ class BaseStatusTableViewCell: UITableViewCell { avatarImageView.addInteraction(UIDragInteraction(delegate: self)) attachmentsView.delegate = self - - collapseButton.layer.masksToBounds = true - collapseButton.layer.cornerRadius = 5 - + accessibilityElements = [displayNameLabel!, contentWarningLabel!, collapseButton!, contentTextView!, attachmentsView!, pollView!] moreButton.showsMenuAsPrimaryAction = true @@ -188,6 +185,7 @@ class BaseStatusTableViewCell: UITableViewCell { state.collapsed = false } } + collapseButton.title = statusState.reason collapsible = state.collapsible! setCollapsed(state.collapsed!, animated: false) } @@ -360,40 +358,6 @@ class BaseStatusTableViewCell: UITableViewCell { pollView.isHidden = pollView.poll == nil || collapsed let buttonImage = UIImage(systemName: collapsed ? "chevron.down" : "chevron.up")! - - if let buttonImageView = collapseButton.imageView { - collapseButton.setImage(buttonImage, for: .normal) - - if animated { - buttonImageView.layer.opacity = 0 - - // this whole hack is necessary because when just rotating buttonImageView, it moves to the left of the button and then animates back to the center - let imageView = UIImageView(image: buttonImageView.image) - imageView.translatesAutoresizingMaskIntoConstraints = false - contentView.addSubview(imageView) - NSLayoutConstraint.activate([ - imageView.widthAnchor.constraint(equalTo: buttonImageView.widthAnchor), - imageView.heightAnchor.constraint(equalTo: buttonImageView.heightAnchor), - imageView.centerXAnchor.constraint(equalTo: collapseButton.centerXAnchor), - imageView.centerYAnchor.constraint(equalTo: collapseButton.centerYAnchor), - ]) - imageView.tintColor = .white - - UIView.animate(withDuration: 0.3, delay: 0) { - imageView.transform = CGAffineTransform(rotationAngle: .pi) - } completion: { _ in - imageView.removeFromSuperview() - buttonImageView.layer.opacity = 1 - } - } - } - - if collapsed { - collapseButton.accessibilityLabel = NSLocalizedString("Expand Status", comment: "expand status button accessibility label") - } else { - collapseButton.accessibilityLabel = NSLocalizedString("Collapse Status", comment: "collapse status button accessibility label") - } - } @IBAction func replyPressed() { diff --git a/Tusker/Views/Status/StatusCollapseButton.swift b/Tusker/Views/Status/StatusCollapseButton.swift index d4830170..3cfc74f4 100644 --- a/Tusker/Views/Status/StatusCollapseButton.swift +++ b/Tusker/Views/Status/StatusCollapseButton.swift @@ -9,6 +9,8 @@ import UIKit class StatusCollapseButton: UIView { + var action: (()->Void)! + var title: String { get { return lblTitle.text ?? "" @@ -18,7 +20,6 @@ class StatusCollapseButton: UIView { } } - private var action: (()->Void)! private var lblTitle = UILabel() private var imgView = UIImageView() private var isCollapsed = true @@ -35,6 +36,7 @@ class StatusCollapseButton: UIView { required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) + setup() } override func touchesBegan(_ touches: Set, with event: UIEvent?) { @@ -52,8 +54,10 @@ class StatusCollapseButton: UIView { override func touchesEnded(_ touches: Set, with event: UIEvent?) { if isCollapsed { imgView.image = UIImage(systemName: "chevron.compact.up") + accessibilityLabel = NSLocalizedString("Collapse Status", comment: "collapse status button accessibility label") } else { imgView.image = UIImage(systemName: "chevron.compact.down") + accessibilityLabel = NSLocalizedString("Expand Status", comment: "expand status button accessibility label") } isCollapsed.toggle() action() @@ -64,6 +68,7 @@ class StatusCollapseButton: UIView { self.isUserInteractionEnabled = true layer.cornerRadius = 8 backgroundColor = .lightGray + accessibilityLabel = NSLocalizedString("Expand Status", comment: "expand status button accessibility label") // Title lblTitle.translatesAutoresizingMaskIntoConstraints = false lblTitle.textColor = .white diff --git a/Tusker/Views/Status/TimelineStatusTableViewCell.swift b/Tusker/Views/Status/TimelineStatusTableViewCell.swift index 971aeac9..9a8c9ddc 100644 --- a/Tusker/Views/Status/TimelineStatusTableViewCell.swift +++ b/Tusker/Views/Status/TimelineStatusTableViewCell.swift @@ -83,6 +83,8 @@ class TimelineStatusTableViewCell: BaseStatusTableViewCell { ]), size: 0) contentWarningLabel.adjustsFontForContentSizeCategory = true + collapseButton.action = collapseButtonPressed + contentTextView.defaultFont = UIFontMetrics.default.scaledFont(for: .systemFont(ofSize: 16)) contentTextView.monospaceFont = UIFontMetrics.default.scaledFont(for: .monospacedSystemFont(ofSize: 16, weight: .regular)) contentTextView.adjustsFontForContentSizeCategory = true diff --git a/Tusker/Views/Status/TimelineStatusTableViewCell.xib b/Tusker/Views/Status/TimelineStatusTableViewCell.xib index 1ce14e1d..45300c71 100644 --- a/Tusker/Views/Status/TimelineStatusTableViewCell.xib +++ b/Tusker/Views/Status/TimelineStatusTableViewCell.xib @@ -103,28 +103,12 @@ - + + + + - + Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. @@ -257,7 +241,7 @@ - + @@ -278,7 +262,6 @@ - @@ -295,8 +278,5 @@ - - - -- 2.34.1