From 76bc6a665c874671797feba2469a82e921ca1b60 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Thu, 5 Sep 2019 22:30:58 -0400 Subject: [PATCH] Show list of accounts for grouped follow notifications --- Tusker.xcodeproj/project.pbxproj | 32 +++++++++ .../AccountListTableViewController.swift | 57 ++++++++++++++++ .../AccountListTableViewController.xib | 26 ++++++++ Tusker/TuskerNavigationDelegate.swift | 8 +++ .../Account Cell/AccountTableViewCell.swift | 66 +++++++++++++++++++ .../Account Cell/AccountTableViewCell.xib | 63 ++++++++++++++++++ ...FollowNotificationGroupTableViewCell.swift | 18 ++++- 7 files changed, 269 insertions(+), 1 deletion(-) create mode 100644 Tusker/Screens/Account List/AccountListTableViewController.swift create mode 100644 Tusker/Screens/Account List/AccountListTableViewController.xib create mode 100644 Tusker/Views/Account Cell/AccountTableViewCell.swift create mode 100644 Tusker/Views/Account Cell/AccountTableViewCell.xib diff --git a/Tusker.xcodeproj/project.pbxproj b/Tusker.xcodeproj/project.pbxproj index c7067e0bbd..9ad4e37a21 100644 --- a/Tusker.xcodeproj/project.pbxproj +++ b/Tusker.xcodeproj/project.pbxproj @@ -148,6 +148,10 @@ D6A3BC7D232195C600FD64D5 /* ActionNotificationGroupTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6A3BC7B232195C600FD64D5 /* ActionNotificationGroupTableViewCell.xib */; }; D6A3BC802321B7E600FD64D5 /* FollowNotificationGroupTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A3BC7E2321B7E600FD64D5 /* FollowNotificationGroupTableViewCell.swift */; }; D6A3BC812321B7E600FD64D5 /* FollowNotificationGroupTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6A3BC7F2321B7E600FD64D5 /* FollowNotificationGroupTableViewCell.xib */; }; + D6A3BC852321F6C100FD64D5 /* AccountListTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A3BC832321F6C100FD64D5 /* AccountListTableViewController.swift */; }; + 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 */; }; 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 */; }; @@ -389,6 +393,10 @@ D6A3BC7B232195C600FD64D5 /* ActionNotificationGroupTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ActionNotificationGroupTableViewCell.xib; sourceTree = ""; }; D6A3BC7E2321B7E600FD64D5 /* FollowNotificationGroupTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowNotificationGroupTableViewCell.swift; sourceTree = ""; }; D6A3BC7F2321B7E600FD64D5 /* FollowNotificationGroupTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FollowNotificationGroupTableViewCell.xib; sourceTree = ""; }; + D6A3BC832321F6C100FD64D5 /* AccountListTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountListTableViewController.swift; sourceTree = ""; }; + 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 = ""; }; 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 = ""; }; @@ -674,6 +682,7 @@ D641C788213DD86D004B4513 /* Large Image */, 0411610422B4571E0030A9B7 /* Attachment */, 0411610522B457290030A9B7 /* Gallery */, + D6A3BC822321F69400FD64D5 /* Account List */, D641C789213DD87E004B4513 /* Preferences */, ); path = Screens; @@ -941,6 +950,24 @@ path = Utilities; sourceTree = ""; }; + D6A3BC822321F69400FD64D5 /* Account List */ = { + isa = PBXGroup; + children = ( + D6A3BC832321F6C100FD64D5 /* AccountListTableViewController.swift */, + D6A3BC842321F6C100FD64D5 /* AccountListTableViewController.xib */, + ); + path = "Account List"; + sourceTree = ""; + }; + D6A3BC872321F78000FD64D5 /* Account Cell */ = { + isa = PBXGroup; + children = ( + D6A3BC882321F79B00FD64D5 /* AccountTableViewCell.swift */, + D6A3BC892321F79B00FD64D5 /* AccountTableViewCell.xib */, + ); + path = "Account Cell"; + sourceTree = ""; + }; D6AEBB3F2321640F00E5038B /* Activities */ = { isa = PBXGroup; children = ( @@ -977,6 +1004,7 @@ D6C7D27B22B6EBE200071952 /* Attachments */, D641C78B213DD92F004B4513 /* Profile Header */, D641C78C213DD937004B4513 /* Notifications */, + D6A3BC872321F78000FD64D5 /* Account Cell */, ); path = Views; sourceTree = ""; @@ -1338,6 +1366,8 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + D6A3BC862321F6C100FD64D5 /* AccountListTableViewController.xib in Resources */, + D6A3BC8B2321F79B00FD64D5 /* AccountTableViewCell.xib in Resources */, D627FF7D217E958900CC0648 /* DraftTableViewCell.xib in Resources */, D6A3BC7D232195C600FD64D5 /* ActionNotificationGroupTableViewCell.xib in Resources */, D667E5E921349EE50057A976 /* ProfileHeaderTableViewCell.xib in Resources */, @@ -1453,6 +1483,7 @@ D6C693F92162E4DB007D6A6D /* StatusContentLabel.swift in Sources */, D6D58DF922074B74009C8DD9 /* LinkLabel.swift in Sources */, 0454DDAF22B462EF00B8BB8E /* GalleryExpandAnimationController.swift in Sources */, + D6A3BC8A2321F79B00FD64D5 /* AccountTableViewCell.swift in Sources */, 0450531F22B0097E00100BA2 /* Timline+UI.swift in Sources */, D667E5F52135BCD50057A976 /* ConversationTableViewController.swift in Sources */, D6C7D27D22B6EBF800071952 /* AttachmentsContainerView.swift in Sources */, @@ -1465,6 +1496,7 @@ D62D2422217AA7E1005076CC /* UserActivityManager.swift in Sources */, D62D2424217ABF3F005076CC /* NSUserActivity+Extensions.swift in Sources */, D646C958213B367000269FB5 /* LargeImageShrinkAnimationController.swift in Sources */, + D6A3BC852321F6C100FD64D5 /* AccountListTableViewController.swift in Sources */, D646C956213B365700269FB5 /* LargeImageExpandAnimationController.swift in Sources */, 0454DDB122B467AA00B8BB8E /* GalleryShrinkAnimationController.swift in Sources */, D667E5F82135C3040057A976 /* Mastodon+Equatable.swift in Sources */, diff --git a/Tusker/Screens/Account List/AccountListTableViewController.swift b/Tusker/Screens/Account List/AccountListTableViewController.swift new file mode 100644 index 0000000000..00e5fc0525 --- /dev/null +++ b/Tusker/Screens/Account List/AccountListTableViewController.swift @@ -0,0 +1,57 @@ +// +// AccountListTableViewController.swift +// Tusker +// +// Created by Shadowfacts on 9/5/19. +// Copyright © 2019 Shadowfacts. All rights reserved. +// + +import UIKit + +class AccountListTableViewController: UITableViewController { + + private let accountCell = "accountCell" + + let accountIDs: [String] + + init(accountIDs: [String]) { + self.accountIDs = accountIDs + + super.init(nibName: "AccountListTableViewController", bundle: .main) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + + tableView.register(UINib(nibName: "AccountTableViewCell", bundle: .main), forCellReuseIdentifier: accountCell) + + tableView.rowHeight = 66 + } + + // MARK: - Table view data source + + override func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return accountIDs.count + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + guard let cell = tableView.dequeueReusableCell(withIdentifier: accountCell, for: indexPath) as? AccountTableViewCell else { fatalError() } + + let id = accountIDs[indexPath.row] + cell.updateUI(accountID: id) + cell.delegate = self + + return cell + } + +} + +extension AccountListTableViewController: TuskerNavigationDelegate {} diff --git a/Tusker/Screens/Account List/AccountListTableViewController.xib b/Tusker/Screens/Account List/AccountListTableViewController.xib new file mode 100644 index 0000000000..40a14c3bdf --- /dev/null +++ b/Tusker/Screens/Account List/AccountListTableViewController.xib @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tusker/TuskerNavigationDelegate.swift b/Tusker/TuskerNavigationDelegate.swift index a6ae82b25a..299977fccc 100644 --- a/Tusker/TuskerNavigationDelegate.swift +++ b/Tusker/TuskerNavigationDelegate.swift @@ -41,6 +41,8 @@ protocol TuskerNavigationDelegate { func showMoreOptions(forStatus statusID: String) func showMoreOptions(forURL url: URL) + + func showFollowedByList(accountIDs: [String]) } extension TuskerNavigationDelegate where Self: UIViewController { @@ -169,4 +171,10 @@ extension TuskerNavigationDelegate where Self: UIViewController { present(moreOptions(forURL: url), animated: true) } + func showFollowedByList(accountIDs: [String]) { + let vc = AccountListTableViewController(accountIDs: accountIDs) + vc.title = NSLocalizedString("Followed By", comment: "followed by accounts list title") + show(vc, sender: self) + } + } diff --git a/Tusker/Views/Account Cell/AccountTableViewCell.swift b/Tusker/Views/Account Cell/AccountTableViewCell.swift new file mode 100644 index 0000000000..d602dbefe7 --- /dev/null +++ b/Tusker/Views/Account Cell/AccountTableViewCell.swift @@ -0,0 +1,66 @@ +// +// AccountTableViewCell.swift +// Tusker +// +// Created by Shadowfacts on 9/5/19. +// Copyright © 2019 Shadowfacts. All rights reserved. +// + +import UIKit + +class AccountTableViewCell: UITableViewCell { + + var delegate: TuskerNavigationDelegate? + + @IBOutlet weak var avatarImageView: UIImageView! + @IBOutlet weak var displayNameLabel: UILabel! + @IBOutlet weak var usernameLabel: UILabel! + + var accountID: String! + + var avatarURL: URL? + + override func awakeFromNib() { + super.awakeFromNib() + + avatarImageView.layer.masksToBounds = true + + NotificationCenter.default.addObserver(self, selector: #selector(updateUIForPrefrences), name: .preferencesChanged, object: nil) + } + + @objc func updateUIForPrefrences() { + avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: avatarImageView) + + guard let account = MastodonCache.account(for: accountID) else { + fatalError("Missing cached account \(accountID!)") + } + displayNameLabel.text = account.realDisplayName + } + + func updateUI(accountID: String) { + self.accountID = accountID + guard let account = MastodonCache.account(for: accountID) else { + fatalError("Missing cached account \(accountID)") + } + + self.avatarURL = account.avatar + ImageCache.avatars.get(account.avatar) { (data) in + guard let data = data, self.avatarURL == account.avatar else { return } + DispatchQueue.main.async { + self.avatarImageView.image = UIImage(data: data) + } + } + + displayNameLabel.text = account.realDisplayName + usernameLabel.text = "@\(account.acct)" + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + if selected { + delegate?.selected(account: accountID) + } + } + +} diff --git a/Tusker/Views/Account Cell/AccountTableViewCell.xib b/Tusker/Views/Account Cell/AccountTableViewCell.xib new file mode 100644 index 0000000000..71f6e12162 --- /dev/null +++ b/Tusker/Views/Account Cell/AccountTableViewCell.xib @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tusker/Views/Notifications/FollowNotificationGroupTableViewCell.swift b/Tusker/Views/Notifications/FollowNotificationGroupTableViewCell.swift index ab07991193..1cc5e268c7 100644 --- a/Tusker/Views/Notifications/FollowNotificationGroupTableViewCell.swift +++ b/Tusker/Views/Notifications/FollowNotificationGroupTableViewCell.swift @@ -67,7 +67,7 @@ class FollowNotificationGroupTableViewCell: UITableViewCell { func updateActionLabel(people: [Account]) { // todo: figure out how to localize this let peopleStr: String - switch (people.count) { + switch people.count { case 1: peopleStr = people.first!.realDisplayName case 2: @@ -113,4 +113,20 @@ class FollowNotificationGroupTableViewCell: UITableViewCell { updateTimestampWorkItem = nil } + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + if selected { + let people = group.notificationIDs.compactMap(MastodonCache.notification(for:)).map { $0.account.id } + switch people.count { + case 0: + return + case 1: + delegate?.selected(account: people.first!) + default: + delegate?.showFollowedByList(accountIDs: people) + } + } + } + }