From 911e66a159bfb9bef0f99c7fa398590de5146519 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sun, 13 Sep 2020 15:51:06 -0400 Subject: [PATCH] Allow more browsing of instance public timelines Closes #74 --- Tusker/Activities/OpenInSafariActivity.swift | 4 +-- Tusker/Controllers/MastodonController.swift | 4 +++ .../Screens/FindInstanceViewController.swift | 1 + .../Profile/ProfileViewController.swift | 2 +- .../InstanceTimelineViewController.swift | 29 ++++--------------- .../TimelineTableViewController.swift | 12 ++++---- Tusker/Screens/Utilities/Previewing.swift | 21 ++++++++++++++ Tusker/TuskerNavigationDelegate.swift | 6 ++-- .../Profile Header/ProfileHeaderView.swift | 2 +- .../Status/BaseStatusTableViewCell.swift | 5 +++- .../Status/TimelineStatusTableViewCell.swift | 22 +++++++++----- 11 files changed, 63 insertions(+), 45 deletions(-) diff --git a/Tusker/Activities/OpenInSafariActivity.swift b/Tusker/Activities/OpenInSafariActivity.swift index 848bc0c944..41f4b62e26 100644 --- a/Tusker/Activities/OpenInSafariActivity.swift +++ b/Tusker/Activities/OpenInSafariActivity.swift @@ -36,10 +36,10 @@ class OpenInSafariActivity: UIActivity { activityDidFinish(true) } - static func completionHandler(viewController: UIViewController, url: URL) -> UIActivityViewController.CompletionWithItemsHandler { + static func completionHandler(navigator: TuskerNavigationDelegate, url: URL) -> UIActivityViewController.CompletionWithItemsHandler { return { (activityType, _, _, _) in if activityType == .openInSafari { - viewController.present(SFSafariViewController(url: url), animated: true) + navigator.show(SFSafariViewController(url: url)) } } } diff --git a/Tusker/Controllers/MastodonController.swift b/Tusker/Controllers/MastodonController.swift index 38da3a1649..e7ee37f623 100644 --- a/Tusker/Controllers/MastodonController.swift +++ b/Tusker/Controllers/MastodonController.swift @@ -44,6 +44,10 @@ class MastodonController { var account: Account! var instance: Instance! + + var loggedIn: Bool { + accountInfo != nil + } init(instanceURL: URL, transient: Bool = false) { self.instanceURL = instanceURL diff --git a/Tusker/Screens/FindInstanceViewController.swift b/Tusker/Screens/FindInstanceViewController.swift index abe07e4309..9526dd8988 100644 --- a/Tusker/Screens/FindInstanceViewController.swift +++ b/Tusker/Screens/FindInstanceViewController.swift @@ -46,6 +46,7 @@ extension FindInstanceViewController: InstanceSelectorTableViewControllerDelegat func didSelectInstance(url: URL) { let instanceTimelineController = InstanceTimelineViewController(for: url, parentMastodonController: parentMastodonController!) instanceTimelineController.delegate = instanceTimelineDelegate + instanceTimelineController.browsingEnabled = false show(instanceTimelineController, sender: self) } } diff --git a/Tusker/Screens/Profile/ProfileViewController.swift b/Tusker/Screens/Profile/ProfileViewController.swift index 9d1c78f8f1..955895c4d6 100644 --- a/Tusker/Screens/Profile/ProfileViewController.swift +++ b/Tusker/Screens/Profile/ProfileViewController.swift @@ -211,7 +211,7 @@ extension ProfileViewController: ProfileHeaderViewDelegate { func showActivityController(activities: [UIActivity]) { let activityController = UIActivityViewController(activityItems: [account.url, AccountActivityItemSource(account)], applicationActivities: activities) - activityController.completionWithItemsHandler = OpenInSafariActivity.completionHandler(viewController: self, url: account.url) + activityController.completionWithItemsHandler = OpenInSafariActivity.completionHandler(navigator: self, url: account.url) activityController.popoverPresentationController?.sourceView = sourceView self.present(activityController, animated: true) } diff --git a/Tusker/Screens/Timeline/InstanceTimelineViewController.swift b/Tusker/Screens/Timeline/InstanceTimelineViewController.swift index 5852d1a619..9f33be9f40 100644 --- a/Tusker/Screens/Timeline/InstanceTimelineViewController.swift +++ b/Tusker/Screens/Timeline/InstanceTimelineViewController.swift @@ -31,6 +31,8 @@ class InstanceTimelineViewController: TimelineTableViewController { } } + var browsingEnabled = true + init(for url: URL, parentMastodonController: MastodonController) { self.parentMastodonController = parentMastodonController @@ -66,36 +68,15 @@ class InstanceTimelineViewController: TimelineTableViewController { override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = super.tableView(tableView, cellForRowAt: indexPath) as! TimelineStatusTableViewCell - cell.delegate = nil - cell.overrideMastodonController = mastodonController + cell.delegate = browsingEnabled ? self : nil return cell } // MARK: - Table view delegate override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - // no-op, we don't currently support viewing whole conversations from other instances - } - - override func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? { - // don't show other screens or actions for other instances - return nil - } - - override func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { - // don't show swipe actions for other instances - return nil - } - - override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { - // only show more actions for other instances - let more = UIContextualAction(style: .normal, title: "More") { (action, view, completion) in - completion(true) - self.showMoreOptions(forStatus: self.timelineSegments[indexPath.section][indexPath.row].id, sourceView: tableView.cellForRow(at: indexPath)) - } - more.image = UIImage(systemName: "ellipsis.circle.fill") - more.backgroundColor = .lightGray - return UISwipeActionsConfiguration(actions: [more]) + guard browsingEnabled else { return } + super.tableView(tableView, didSelectRowAt: indexPath) } // MARK: - Interaction diff --git a/Tusker/Screens/Timeline/TimelineTableViewController.swift b/Tusker/Screens/Timeline/TimelineTableViewController.swift index e1f3117f4f..171a984952 100644 --- a/Tusker/Screens/Timeline/TimelineTableViewController.swift +++ b/Tusker/Screens/Timeline/TimelineTableViewController.swift @@ -9,7 +9,7 @@ import UIKit import Pachyderm -class TimelineTableViewController: EnhancedTableViewController { +class TimelineTableViewController: EnhancedTableViewController, StatusTableViewCellDelegate { var timeline: Timeline! weak var mastodonController: MastodonController! @@ -206,7 +206,7 @@ class TimelineTableViewController: EnhancedTableViewController { return (tableView.cellForRow(at: indexPath) as? TableViewSwipeActionProvider)?.trailingSwipeActionsConfiguration() } - // MARK: Interaction + // MARK: - Interaction @objc func refreshStatuses(_ sender: Any) { guard let newer = newer else { return } @@ -244,16 +244,18 @@ class TimelineTableViewController: EnhancedTableViewController { compose() } -} - -extension TimelineTableViewController: StatusTableViewCellDelegate { + // MARK: - TuskerNavigationDelegate + var apiController: MastodonController { mastodonController } + // MARK: - StatusTableViewCellDelegate + func statusCellCollapsedStateChanged(_ cell: BaseStatusTableViewCell) { // causes the table view to recalculate the cell heights tableView.beginUpdates() tableView.endUpdates() } + } extension TimelineTableViewController: UITableViewDataSourcePrefetching { diff --git a/Tusker/Screens/Utilities/Previewing.swift b/Tusker/Screens/Utilities/Previewing.swift index b02e22103d..0f14180795 100644 --- a/Tusker/Screens/Utilities/Previewing.swift +++ b/Tusker/Screens/Utilities/Previewing.swift @@ -37,6 +37,16 @@ extension MenuPreviewProvider { guard let mastodonController = mastodonController, let account = mastodonController.persistentContainer.account(for: accountID) else { return [] } + guard mastodonController.loggedIn else { + return [ + openInSafariAction(url: account.url), + createAction(identifier: "share", title: "Share...", systemImageName: "square.and.arrow.up", handler: { [weak self] (_) in + guard let self = self else { return } + self.navigationDelegate?.showMoreOptions(forAccount: accountID, sourceView: sourceView) + }) + ] + } + var actionsSection: [UIMenuElement] = [ createAction(identifier: "sendmessage", title: "Send Message", systemImageName: "envelope", handler: { [weak self] (_) in guard let self = self else { return } @@ -123,6 +133,17 @@ extension MenuPreviewProvider { func actionsForStatus(statusID: String, sourceView: UIView?) -> [UIMenuElement] { guard let mastodonController = mastodonController, let status = mastodonController.persistentContainer.status(for: statusID) else { return [] } + + guard mastodonController.loggedIn else { + return [ + openInSafariAction(url: status.url!), + createAction(identifier: "share", title: "Share...", systemImageName: "square.and.arrow.up", handler: { [weak self] (_) in + guard let self = self else { return } + self.navigationDelegate?.showMoreOptions(forStatus: statusID, sourceView: sourceView) + }) + ] + } + let bookmarked = status.bookmarked ?? false let muted = status.muted diff --git a/Tusker/TuskerNavigationDelegate.swift b/Tusker/TuskerNavigationDelegate.swift index bb9f45837e..800d5ec6de 100644 --- a/Tusker/TuskerNavigationDelegate.swift +++ b/Tusker/TuskerNavigationDelegate.swift @@ -118,7 +118,7 @@ extension TuskerNavigationDelegate { OpenInSafariActivity() ] let activityController = UIActivityViewController(activityItems: [url], applicationActivities: customActivites) - activityController.completionWithItemsHandler = OpenInSafariActivity.completionHandler(viewController: self, url: url) + activityController.completionWithItemsHandler = OpenInSafariActivity.completionHandler(navigator: self, url: url) return activityController } @@ -142,7 +142,7 @@ extension TuskerNavigationDelegate { } let activityController = UIActivityViewController(activityItems: [url, StatusActivityItemSource(status)], applicationActivities: customActivites) - activityController.completionWithItemsHandler = OpenInSafariActivity.completionHandler(viewController: self, url: url) + activityController.completionWithItemsHandler = OpenInSafariActivity.completionHandler(navigator: self, url: url) return activityController } } @@ -158,7 +158,7 @@ extension TuskerNavigationDelegate { ] let activityController = UIActivityViewController(activityItems: [account.url, AccountActivityItemSource(account)], applicationActivities: customActivities) - activityController.completionWithItemsHandler = OpenInSafariActivity.completionHandler(viewController: self, url: account.url) + activityController.completionWithItemsHandler = OpenInSafariActivity.completionHandler(navigator: self, url: account.url) return activityController } } diff --git a/Tusker/Views/Profile Header/ProfileHeaderView.swift b/Tusker/Views/Profile Header/ProfileHeaderView.swift index 94f1c3c559..b4219e85d6 100644 --- a/Tusker/Views/Profile Header/ProfileHeaderView.swift +++ b/Tusker/Views/Profile Header/ProfileHeaderView.swift @@ -114,7 +114,7 @@ class ProfileHeaderView: UIView { noteTextView.setEmojis(account.emojis) // don't show relationship label for the user's own account - if accountID != mastodonController.account.id { + if accountID != mastodonController.account?.id { let request = Client.getRelationships(accounts: [accountID]) mastodonController.run(request) { [weak self] (response) in guard let self = self, diff --git a/Tusker/Views/Status/BaseStatusTableViewCell.swift b/Tusker/Views/Status/BaseStatusTableViewCell.swift index 4d83d09507..eb03b1f4c1 100644 --- a/Tusker/Views/Status/BaseStatusTableViewCell.swift +++ b/Tusker/Views/Status/BaseStatusTableViewCell.swift @@ -162,7 +162,10 @@ class BaseStatusTableViewCell: UITableViewCell { // Pleroma allows 'Boost to original audience' for your own private posts reblogDisabled = status.visibility == .direct || (status.visibility == .private && status.account.id != mastodonController.account.id) } - reblogButton.isEnabled = !reblogDisabled + reblogButton.isEnabled = !reblogDisabled && mastodonController.loggedIn + + favoriteButton.isEnabled = mastodonController.loggedIn + replyButton.isEnabled = mastodonController.loggedIn updateStatusIconsForPreferences(status) diff --git a/Tusker/Views/Status/TimelineStatusTableViewCell.swift b/Tusker/Views/Status/TimelineStatusTableViewCell.swift index 4a3242c5c4..367f242995 100644 --- a/Tusker/Views/Status/TimelineStatusTableViewCell.swift +++ b/Tusker/Views/Status/TimelineStatusTableViewCell.swift @@ -196,7 +196,8 @@ extension TimelineStatusTableViewCell: SelectableTableViewCell { extension TimelineStatusTableViewCell: TableViewSwipeActionProvider { func leadingSwipeActionsConfiguration() -> UISwipeActionsConfiguration? { - guard let mastodonController = mastodonController else { return nil } + guard let mastodonController = mastodonController, + mastodonController.loggedIn else { return nil } guard let status = mastodonController.persistentContainer.status(for: statusID) else { fatalError("Missing cached status \(statusID!)") } let favoriteTitle: String @@ -258,13 +259,6 @@ extension TimelineStatusTableViewCell: TableViewSwipeActionProvider { } func trailingSwipeActionsConfiguration() -> UISwipeActionsConfiguration? { - let reply = UIContextualAction(style: .normal, title: "Reply") { (action, view, completion) in - completion(true) - self.reply() - } - reply.image = UIImage(systemName: "arrowshape.turn.up.left.fill") - reply.backgroundColor = tintColor - let moreTitle: String let moreImage: UIImage // on iOS 14+, more actions are in the context menu so display this as 'Share' @@ -284,6 +278,18 @@ extension TimelineStatusTableViewCell: TableViewSwipeActionProvider { } more.image = moreImage more.backgroundColor = .lightGray + + guard mastodonController.loggedIn else { + return UISwipeActionsConfiguration(actions: [more]) + } + + let reply = UIContextualAction(style: .normal, title: "Reply") { (action, view, completion) in + completion(true) + self.reply() + } + reply.image = UIImage(systemName: "arrowshape.turn.up.left.fill") + reply.backgroundColor = tintColor + return UISwipeActionsConfiguration(actions: [reply, more]) }