From d9abf3ec09463b3a7894cdbac4bfc2bd621ac050 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Thu, 5 Sep 2019 23:16:45 -0400 Subject: [PATCH] Show list of accounts based on grouped notifications --- Tusker.xcodeproj/project.pbxproj | 16 +++ .../AccountListTableViewController.swift | 4 + .../AccountListTableViewController.xib | 16 ++- ...ActionAccountListTableViewController.swift | 125 ++++++++++++++++++ ...usActionAccountListTableViewController.xib | 28 ++++ Tusker/TuskerNavigationDelegate.swift | 15 +++ .../Account Cell/AccountTableViewCell.swift | 3 +- ...ActionNotificationGroupTableViewCell.swift | 21 +++ 8 files changed, 220 insertions(+), 8 deletions(-) create mode 100644 Tusker/Screens/Status Action Account List/StatusActionAccountListTableViewController.swift create mode 100644 Tusker/Screens/Status Action Account List/StatusActionAccountListTableViewController.xib diff --git a/Tusker.xcodeproj/project.pbxproj b/Tusker.xcodeproj/project.pbxproj index 9ad4e37a..c8cabdc1 100644 --- a/Tusker.xcodeproj/project.pbxproj +++ b/Tusker.xcodeproj/project.pbxproj @@ -152,6 +152,8 @@ D6A3BC862321F6C100FD64D5 /* AccountListTableViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6A3BC842321F6C100FD64D5 /* AccountListTableViewController.xib */; }; D6A3BC8A2321F79B00FD64D5 /* AccountTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A3BC882321F79B00FD64D5 /* AccountTableViewCell.swift */; }; D6A3BC8B2321F79B00FD64D5 /* AccountTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6A3BC892321F79B00FD64D5 /* AccountTableViewCell.xib */; }; + D6A3BC8F2321FFB900FD64D5 /* StatusActionAccountListTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A3BC8D2321FFB900FD64D5 /* StatusActionAccountListTableViewController.swift */; }; + D6A3BC902321FFB900FD64D5 /* StatusActionAccountListTableViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6A3BC8E2321FFB900FD64D5 /* StatusActionAccountListTableViewController.xib */; }; D6A5FAF1217B7E05003DB2D9 /* ComposeViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6A5FAF0217B7E05003DB2D9 /* ComposeViewController.xib */; }; D6A5FAFB217B86CE003DB2D9 /* OnboardingViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6A5FAFA217B86CE003DB2D9 /* OnboardingViewController.xib */; }; D6AEBB3E2321638100E5038B /* UIActivity+Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6AEBB3D2321638100E5038B /* UIActivity+Types.swift */; }; @@ -397,6 +399,8 @@ D6A3BC842321F6C100FD64D5 /* AccountListTableViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AccountListTableViewController.xib; sourceTree = ""; }; D6A3BC882321F79B00FD64D5 /* AccountTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountTableViewCell.swift; sourceTree = ""; }; D6A3BC892321F79B00FD64D5 /* AccountTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AccountTableViewCell.xib; sourceTree = ""; }; + D6A3BC8D2321FFB900FD64D5 /* StatusActionAccountListTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusActionAccountListTableViewController.swift; sourceTree = ""; }; + D6A3BC8E2321FFB900FD64D5 /* StatusActionAccountListTableViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = StatusActionAccountListTableViewController.xib; sourceTree = ""; }; D6A5FAF0217B7E05003DB2D9 /* ComposeViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ComposeViewController.xib; sourceTree = ""; }; D6A5FAFA217B86CE003DB2D9 /* OnboardingViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = OnboardingViewController.xib; sourceTree = ""; }; D6AEBB3D2321638100E5038B /* UIActivity+Types.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIActivity+Types.swift"; sourceTree = ""; }; @@ -683,6 +687,7 @@ 0411610422B4571E0030A9B7 /* Attachment */, 0411610522B457290030A9B7 /* Gallery */, D6A3BC822321F69400FD64D5 /* Account List */, + D6A3BC8C2321FF9B00FD64D5 /* Status Action Account List */, D641C789213DD87E004B4513 /* Preferences */, ); path = Screens; @@ -968,6 +973,15 @@ path = "Account Cell"; sourceTree = ""; }; + D6A3BC8C2321FF9B00FD64D5 /* Status Action Account List */ = { + isa = PBXGroup; + children = ( + D6A3BC8D2321FFB900FD64D5 /* StatusActionAccountListTableViewController.swift */, + D6A3BC8E2321FFB900FD64D5 /* StatusActionAccountListTableViewController.xib */, + ); + path = "Status Action Account List"; + sourceTree = ""; + }; D6AEBB3F2321640F00E5038B /* Activities */ = { isa = PBXGroup; children = ( @@ -1380,6 +1394,7 @@ D627FF79217E950100CC0648 /* DraftsTableViewController.xib in Resources */, D67C57B221E28FAD00C3118B /* ComposeStatusReplyView.xib in Resources */, 0411610122B442870030A9B7 /* AttachmentViewController.xib in Resources */, + D6A3BC902321FFB900FD64D5 /* StatusActionAccountListTableViewController.xib in Resources */, D6A3BC812321B7E600FD64D5 /* FollowNotificationGroupTableViewCell.xib in Resources */, D60C07E421E8176B0057FAA8 /* ComposeMediaView.xib in Resources */, D667E5E12134937B0057A976 /* StatusTableViewCell.xib in Resources */, @@ -1503,6 +1518,7 @@ D67C57B421E2910700C3118B /* ComposeStatusReplyView.swift in Sources */, 04DACE8E212CC7CC009840C4 /* ImageCache.swift in Sources */, D627FF7B217E951500CC0648 /* DraftsTableViewController.swift in Sources */, + D6A3BC8F2321FFB900FD64D5 /* StatusActionAccountListTableViewController.swift in Sources */, D6AEBB4823216B1D00E5038B /* AccountActivity.swift in Sources */, D6333B772138D94E00CE884A /* ComposeMediaView.swift in Sources */, 04ED00B121481ED800567C53 /* SteppedProgressView.swift in Sources */, diff --git a/Tusker/Screens/Account List/AccountListTableViewController.swift b/Tusker/Screens/Account List/AccountListTableViewController.swift index 00e5fc05..9892fb38 100644 --- a/Tusker/Screens/Account List/AccountListTableViewController.swift +++ b/Tusker/Screens/Account List/AccountListTableViewController.swift @@ -30,6 +30,10 @@ class AccountListTableViewController: UITableViewController { tableView.register(UINib(nibName: "AccountTableViewCell", bundle: .main), forCellReuseIdentifier: accountCell) tableView.rowHeight = 66 + + tableView.alwaysBounceVertical = true + + tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: CGFloat.leastNormalMagnitude)) } // MARK: - Table view data source diff --git a/Tusker/Screens/Account List/AccountListTableViewController.xib b/Tusker/Screens/Account List/AccountListTableViewController.xib index 40a14c3b..73ce32eb 100644 --- a/Tusker/Screens/Account List/AccountListTableViewController.xib +++ b/Tusker/Screens/Account List/AccountListTableViewController.xib @@ -1,26 +1,28 @@ - - + + + - + - + - - + + - + + diff --git a/Tusker/Screens/Status Action Account List/StatusActionAccountListTableViewController.swift b/Tusker/Screens/Status Action Account List/StatusActionAccountListTableViewController.swift new file mode 100644 index 00000000..b01d305b --- /dev/null +++ b/Tusker/Screens/Status Action Account List/StatusActionAccountListTableViewController.swift @@ -0,0 +1,125 @@ +// +// StatusActionAccountListTableViewController.swift +// Tusker +// +// Created by Shadowfacts on 9/5/19. +// Copyright © 2019 Shadowfacts. All rights reserved. +// + +import UIKit + +class StatusActionAccountListTableViewController: UITableViewController { + + private let statusCell = "statusCell" + private let accountCell = "accountCell" + + let statusID: String + let accountIDs: [String] + + init(statusID: String, accountIDs: [String]) { + self.statusID = statusID + self.accountIDs = accountIDs + + super.init(nibName: "StatusActionAccountListTableViewController", bundle: .main) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + + tableView.register(UINib(nibName: "StatusTableViewCell", bundle: .main), forCellReuseIdentifier: statusCell) + tableView.register(UINib(nibName: "AccountTableViewCell", bundle: .main), forCellReuseIdentifier: accountCell) + + tableView.rowHeight = UITableView.automaticDimension + tableView.estimatedRowHeight = 66 // height of account cell, which will be the most common + + tableView.alwaysBounceVertical = true + + tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: CGFloat.leastNormalMagnitude)) + } + + // MARK: - Table view data source + + override func numberOfSections(in tableView: UITableView) -> Int { + return 2 + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + switch section { + case 0: // status + return 1 + case 1: // accounts + return accountIDs.count + default: + fatalError("Invalid section \(section)") + } + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + switch indexPath.section { + case 0: + guard let cell = tableView.dequeueReusableCell(withIdentifier: statusCell, for: indexPath) as? StatusTableViewCell else { fatalError() } + cell.updateUI(statusID: statusID) + cell.delegate = self + return cell + case 1: + guard let cell = tableView.dequeueReusableCell(withIdentifier: accountCell, for: indexPath) as? AccountTableViewCell else { fatalError() } + cell.updateUI(accountID: accountIDs[indexPath.row]) + cell.delegate = self + return cell + default: + fatalError("Invalid section \(indexPath.section)") + } + } + + /* + // Override to support conditional editing of the table view. + override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { + // Return false if you do not want the specified item to be editable. + return true + } + */ + + /* + // Override to support editing the table view. + override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { + if editingStyle == .delete { + // Delete the row from the data source + tableView.deleteRows(at: [indexPath], with: .fade) + } else if editingStyle == .insert { + // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view + } + } + */ + + /* + // Override to support rearranging the table view. + override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) { + + } + */ + + /* + // Override to support conditional rearranging of the table view. + override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool { + // Return false if you do not want the item to be re-orderable. + return true + } + */ + + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + // Get the new view controller using segue.destination. + // Pass the selected object to the new view controller. + } + */ + +} + +extension StatusActionAccountListTableViewController: StatusTableViewCellDelegate {} diff --git a/Tusker/Screens/Status Action Account List/StatusActionAccountListTableViewController.xib b/Tusker/Screens/Status Action Account List/StatusActionAccountListTableViewController.xib new file mode 100644 index 00000000..49e9972e --- /dev/null +++ b/Tusker/Screens/Status Action Account List/StatusActionAccountListTableViewController.xib @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tusker/TuskerNavigationDelegate.swift b/Tusker/TuskerNavigationDelegate.swift index 299977fc..5915ba57 100644 --- a/Tusker/TuskerNavigationDelegate.swift +++ b/Tusker/TuskerNavigationDelegate.swift @@ -43,6 +43,8 @@ protocol TuskerNavigationDelegate { func showMoreOptions(forURL url: URL) func showFollowedByList(accountIDs: [String]) + + func showStatusActionAccountList(statusID: String, accountIDs: [String], action: Pachyderm.Notification.Kind) } extension TuskerNavigationDelegate where Self: UIViewController { @@ -177,4 +179,17 @@ extension TuskerNavigationDelegate where Self: UIViewController { show(vc, sender: self) } + func showStatusActionAccountList(statusID: String, accountIDs: [String], action: Pachyderm.Notification.Kind) { + let vc = StatusActionAccountListTableViewController(statusID: statusID, accountIDs: accountIDs) + switch action { + case .favourite: + vc.title = NSLocalizedString("Favorited By", comment: "status favorited by accounts list title") + case .reblog: + vc.title = NSLocalizedString("Reblogged By", comment: "status reblogged by accounts list title") + default: + fatalError("Invalid notification type for action account list, only favourite and relog are allowed") + } + show(vc, sender: self) + } + } diff --git a/Tusker/Views/Account Cell/AccountTableViewCell.swift b/Tusker/Views/Account Cell/AccountTableViewCell.swift index d602dbef..66cff934 100644 --- a/Tusker/Views/Account Cell/AccountTableViewCell.swift +++ b/Tusker/Views/Account Cell/AccountTableViewCell.swift @@ -51,8 +51,9 @@ class AccountTableViewCell: UITableViewCell { } } - displayNameLabel.text = account.realDisplayName usernameLabel.text = "@\(account.acct)" + + updateUIForPrefrences() } override func setSelected(_ selected: Bool, animated: Bool) { diff --git a/Tusker/Views/Notifications/ActionNotificationGroupTableViewCell.swift b/Tusker/Views/Notifications/ActionNotificationGroupTableViewCell.swift index e32e9cdf..1fbcfffb 100644 --- a/Tusker/Views/Notifications/ActionNotificationGroupTableViewCell.swift +++ b/Tusker/Views/Notifications/ActionNotificationGroupTableViewCell.swift @@ -138,5 +138,26 @@ class ActionNotificationGroupTableViewCell: UITableViewCell { } actionLabel.text = "\(verb) by \(peopleStr)" } + + override func prepareForReuse() { + super.prepareForReuse() + + if let authorAvatarURL = authorAvatarURL { + ImageCache.avatars.cancel(authorAvatarURL) + } + + updateTimestampWorkItem?.cancel() + updateTimestampWorkItem = nil + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + if selected { + let notifications = group.notificationIDs.compactMap(MastodonCache.notification(for:)) + let accountIDs = notifications.compactMap { $0.account.id } + delegate?.showStatusActionAccountList(statusID: statusID, accountIDs: accountIDs, action: notifications.first!.kind) + } + } }