diff --git a/Tusker/Screens/Conversation/ConversationTableViewController.swift b/Tusker/Screens/Conversation/ConversationTableViewController.swift index 2b5ccfc9ec..9b7117fe44 100644 --- a/Tusker/Screens/Conversation/ConversationTableViewController.swift +++ b/Tusker/Screens/Conversation/ConversationTableViewController.swift @@ -119,7 +119,13 @@ class ConversationTableViewController: EnhancedTableViewController { } -extension ConversationTableViewController: StatusTableViewCellDelegate {} +extension ConversationTableViewController: StatusTableViewCellDelegate { + func statusCollapsedStateChanged() { + // causes the table view to recalculate the cell heights + tableView.beginUpdates() + tableView.endUpdates() + } +} extension ConversationTableViewController: UITableViewDataSourcePrefetching { func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) { diff --git a/Tusker/Screens/Notifications/NotificationsTableViewController.swift b/Tusker/Screens/Notifications/NotificationsTableViewController.swift index 6b1399da1f..36cd5bb991 100644 --- a/Tusker/Screens/Notifications/NotificationsTableViewController.swift +++ b/Tusker/Screens/Notifications/NotificationsTableViewController.swift @@ -173,7 +173,13 @@ class NotificationsTableViewController: EnhancedTableViewController { } -extension NotificationsTableViewController: StatusTableViewCellDelegate {} +extension NotificationsTableViewController: StatusTableViewCellDelegate { + func statusCollapsedStateChanged() { + // causes the table view to recalculate the cell heights + tableView.beginUpdates() + tableView.endUpdates() + } +} extension NotificationsTableViewController: UITableViewDataSourcePrefetching { func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) { diff --git a/Tusker/Screens/Profile/ProfileTableViewController.swift b/Tusker/Screens/Profile/ProfileTableViewController.swift index 9f10661256..c826472895 100644 --- a/Tusker/Screens/Profile/ProfileTableViewController.swift +++ b/Tusker/Screens/Profile/ProfileTableViewController.swift @@ -205,7 +205,14 @@ class ProfileTableViewController: EnhancedTableViewController { } -extension ProfileTableViewController: StatusTableViewCellDelegate {} +extension ProfileTableViewController: StatusTableViewCellDelegate { + func statusCollapsedStateChanged() { + // causes the table view to recalculate the cell heights + tableView.beginUpdates() + tableView.endUpdates() + } +} + extension ProfileTableViewController: ProfileHeaderTableViewCellDelegate { func showMoreOptions() { let account = MastodonCache.account(for: accountID)! diff --git a/Tusker/Screens/Status Action Account List/StatusActionAccountListTableViewController.swift b/Tusker/Screens/Status Action Account List/StatusActionAccountListTableViewController.swift index 1a38cb7a4c..ade0d579b3 100644 --- a/Tusker/Screens/Status Action Account List/StatusActionAccountListTableViewController.swift +++ b/Tusker/Screens/Status Action Account List/StatusActionAccountListTableViewController.swift @@ -134,4 +134,10 @@ class StatusActionAccountListTableViewController: EnhancedTableViewController { } -extension StatusActionAccountListTableViewController: StatusTableViewCellDelegate {} +extension StatusActionAccountListTableViewController: StatusTableViewCellDelegate { + func statusCollapsedStateChanged() { + // causes the table view to recalculate the cell heights + tableView.beginUpdates() + tableView.endUpdates() + } +} diff --git a/Tusker/Screens/Timeline/TimelineTableViewController.swift b/Tusker/Screens/Timeline/TimelineTableViewController.swift index 04da25ae14..1c4822781f 100644 --- a/Tusker/Screens/Timeline/TimelineTableViewController.swift +++ b/Tusker/Screens/Timeline/TimelineTableViewController.swift @@ -151,7 +151,13 @@ class TimelineTableViewController: EnhancedTableViewController { } -extension TimelineTableViewController: StatusTableViewCellDelegate {} +extension TimelineTableViewController: StatusTableViewCellDelegate { + func statusCollapsedStateChanged() { + // causes the table view to recalculate the cell heights + tableView.beginUpdates() + tableView.endUpdates() + } +} extension TimelineTableViewController: UITableViewDataSourcePrefetching { func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) { diff --git a/Tusker/Views/Status/ConversationMainStatusTableViewCell.swift b/Tusker/Views/Status/ConversationMainStatusTableViewCell.swift index 32abc28614..243b750193 100644 --- a/Tusker/Views/Status/ConversationMainStatusTableViewCell.swift +++ b/Tusker/Views/Status/ConversationMainStatusTableViewCell.swift @@ -27,6 +27,8 @@ class ConversationMainStatusTableViewCell: UITableViewCell { @IBOutlet weak var displayNameLabel: UILabel! @IBOutlet weak var usernameLabel: UILabel! + @IBOutlet weak var contentWarningLabel: UILabel! + @IBOutlet weak var collapseButton: UIButton! @IBOutlet weak var contentLabel: StatusContentLabel! @IBOutlet weak var avatarImageView: UIImageView! @IBOutlet weak var totalFavoritesButton: UIButton! @@ -54,6 +56,13 @@ class ConversationMainStatusTableViewCell: UITableViewCell { } } + var collapsible = false { + didSet { + collapseButton.isHidden = !collapsible + } + } + var collapsed = false + var avatarURL: URL? var statusUpdater: Cancellable? @@ -72,6 +81,8 @@ class ConversationMainStatusTableViewCell: UITableViewCell { attachmentsView.delegate = self attachmentsView.layer.cornerRadius = 5 attachmentsView.layer.masksToBounds = true + collapseButton.layer.masksToBounds = true + collapseButton.layer.cornerRadius = 5 NotificationCenter.default.addObserver(self, selector: #selector(updateUIForPreferences), name: .preferencesChanged, object: nil) @@ -107,13 +118,17 @@ class ConversationMainStatusTableViewCell: UITableViewCell { } timestampAndClientLabel.text = timestampAndClientText - attachmentsView.updateUI(status: status) let realStatus = status.reblog ?? status updateStatusState(status: realStatus) contentLabel.statusID = statusID + + collapsible = !status.spoilerText.isEmpty + setCollapsed(collapsible, animated: false) + contentWarningLabel.text = status.spoilerText + contentWarningLabel.isHidden = status.spoilerText.isEmpty } private func updateStatusState(status: Status) { @@ -156,6 +171,37 @@ class ConversationMainStatusTableViewCell: UITableViewCell { delegate?.selected(account: accountID) } + @IBAction func collapsePressed(_ sender: Any) { + setCollapsed(!collapsed, animated: true) + delegate?.statusCollapsedStateChanged() + } + + func setCollapsed(_ collapsed: Bool, animated: Bool) { + self.collapsed = collapsed + + contentLabel.isHidden = collapsed + attachmentsView.isHidden = attachmentsView.attachments.count == 0 || collapsed + + let buttonImage = UIImage(systemName: collapsed ? "chevron.down" : "chevron.up") + + if animated, let buttonImageView = collapseButton.imageView { + // see comment in StatusTableViewCell.setCollapsed + UIView.animateKeyframes(withDuration: 0.2, delay: 0, options: .calculationModeLinear, animations: { + UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.5) { + buttonImageView.transform = CGAffineTransform(rotationAngle: collapsed ? .pi / 2 : -.pi / 2) + } + UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5) { + buttonImageView.transform = CGAffineTransform(rotationAngle: .pi) + } + }, completion: { (finished) in + buttonImageView.transform = .identity + self.collapseButton.setImage(buttonImage, for: .normal) + }) + } else { + collapseButton.setImage(buttonImage, for: .normal) + } + } + @IBAction func replyPressed(_ sender: Any) { delegate?.reply(to: statusID) } diff --git a/Tusker/Views/Status/ConversationMainStatusTableViewCell.xib b/Tusker/Views/Status/ConversationMainStatusTableViewCell.xib index 466d65fa82..32eb227ace 100644 --- a/Tusker/Views/Status/ConversationMainStatusTableViewCell.xib +++ b/Tusker/Views/Status/ConversationMainStatusTableViewCell.xib @@ -10,14 +10,14 @@ - + - + - + @@ -38,45 +38,62 @@ - - - - + - + + + - + - + + - - - + - - - - - - - + + + -