diff --git a/Tusker.xcodeproj/project.pbxproj b/Tusker.xcodeproj/project.pbxproj index 3fa118b2..6f2ebe98 100644 --- a/Tusker.xcodeproj/project.pbxproj +++ b/Tusker.xcodeproj/project.pbxproj @@ -80,6 +80,7 @@ D627943523A5525100D38C68 /* StatusActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627943423A5525100D38C68 /* StatusActivity.swift */; }; D627943723A552C200D38C68 /* BookmarkStatusActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627943623A552C200D38C68 /* BookmarkStatusActivity.swift */; }; D627943923A553B600D38C68 /* UnbookmarkStatusActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627943823A553B600D38C68 /* UnbookmarkStatusActivity.swift */; }; + D627943B23A55BA600D38C68 /* NavigableTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627943A23A55BA600D38C68 /* NavigableTableViewCell.swift */; }; D627FF76217E923E00CC0648 /* DraftsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627FF75217E923E00CC0648 /* DraftsManager.swift */; }; D627FF79217E950100CC0648 /* DraftsTableViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D627FF78217E950100CC0648 /* DraftsTableViewController.xib */; }; D627FF7B217E951500CC0648 /* DraftsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627FF7A217E951500CC0648 /* DraftsTableViewController.swift */; }; @@ -347,6 +348,7 @@ D627943423A5525100D38C68 /* StatusActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusActivity.swift; sourceTree = ""; }; D627943623A552C200D38C68 /* BookmarkStatusActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkStatusActivity.swift; sourceTree = ""; }; D627943823A553B600D38C68 /* UnbookmarkStatusActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnbookmarkStatusActivity.swift; sourceTree = ""; }; + D627943A23A55BA600D38C68 /* NavigableTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigableTableViewCell.swift; sourceTree = ""; }; D627FF75217E923E00CC0648 /* DraftsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftsManager.swift; sourceTree = ""; }; D627FF78217E950100CC0648 /* DraftsTableViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DraftsTableViewController.xib; sourceTree = ""; }; D627FF7A217E951500CC0648 /* DraftsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftsTableViewController.swift; sourceTree = ""; }; @@ -1093,6 +1095,7 @@ D6C693F82162E4DB007D6A6D /* StatusContentLabel.swift */, D641C77E213DC78A004B4513 /* InlineTextAttachment.swift */, 04ED00B021481ED800567C53 /* SteppedProgressView.swift */, + D627943A23A55BA600D38C68 /* NavigableTableViewCell.swift */, D627943123A5466600D38C68 /* SelectableTableViewCell.swift */, D67C57A721E2649B00C3118B /* Account Detail */, D67C57B021E28F9400C3118B /* Compose Status Reply */, @@ -1639,6 +1642,7 @@ D6C94D872139E62700CB5196 /* LargeImageViewController.swift in Sources */, D6434EB3215B1856001A919A /* XCBRequest.swift in Sources */, D663626221360B1900C9CBA2 /* Preferences.swift in Sources */, + D627943B23A55BA600D38C68 /* NavigableTableViewCell.swift in Sources */, D6333B792139AEFD00CE884A /* Date+TimeAgo.swift in Sources */, D641C77F213DC78A004B4513 /* InlineTextAttachment.swift in Sources */, D627943523A5525100D38C68 /* StatusActivity.swift in Sources */, diff --git a/Tusker/Screens/Profile/ProfileTableViewController.swift b/Tusker/Screens/Profile/ProfileTableViewController.swift index 326ddbfd..ecf12bfd 100644 --- a/Tusker/Screens/Profile/ProfileTableViewController.swift +++ b/Tusker/Screens/Profile/ProfileTableViewController.swift @@ -247,17 +247,10 @@ extension ProfileTableViewController: ProfileHeaderTableViewCellDelegate { MastodonCache.relationship(for: account.id) { [weak self] (relationship) in guard let self = self else { return } - let customActivities: [UIActivity] + var customActivities: [UIActivity] = [OpenInSafariActivity()] if let relationship = relationship { let toggleFollowActivity = relationship.following ? UnfollowAccountActivity() : FollowAccountActivity() - customActivities = [ - toggleFollowActivity, - OpenInSafariActivity() - ] - } else { - customActivities = [ - OpenInSafariActivity() - ] + customActivities.insert(toggleFollowActivity, at: 0) } DispatchQueue.main.async { diff --git a/Tusker/Screens/Utilities/Previewing.swift b/Tusker/Screens/Utilities/Previewing.swift index 0cef0294..2c20e4e7 100644 --- a/Tusker/Screens/Utilities/Previewing.swift +++ b/Tusker/Screens/Utilities/Previewing.swift @@ -14,27 +14,25 @@ protocol MenuPreviewProvider { typealias PreviewProviders = (content: UIContextMenuContentPreviewProvider, actions: () -> [UIAction]) + var navigationDelegate: TuskerNavigationDelegate? { get } + func getPreviewProviders(for location: CGPoint, sourceViewController: UIViewController) -> PreviewProviders? } extension MenuPreviewProvider { - fileprivate func present(_ vc: UIViewController) { - UIApplication.shared.keyWindow!.rootViewController!.present(vc, animated: true) - } - func actionsForProfile(accountID: String) -> [UIAction] { guard let account = MastodonCache.account(for: accountID) else { return [] } return [ createAction(identifier: "openinsafari", title: "Open in Safari", systemImageName: "safari", handler: { (_) in - self.present(SFSafariViewController(url: account.url)) + self.navigationDelegate?.selected(url: account.url) }), createAction(identifier: "sendmessage", title: "Send Message", systemImageName: "envelope", handler: { (_) in - self.present(UINavigationController(rootViewController: ComposeViewController(mentioningAcct: account.acct))) + self.navigationDelegate?.compose(mentioning: account.acct) }), createAction(identifier: "share", title: "Share...", systemImageName: "square.and.arrow.up", handler: { (_) in - self.present(UIActivityViewController(activityItems: [account.url], applicationActivities: nil)) + self.navigationDelegate?.showMoreOptions(forAccount: accountID) }) ] } @@ -42,10 +40,10 @@ extension MenuPreviewProvider { func actionsForURL(_ url: URL) -> [UIAction] { return [ createAction(identifier: "openinsafari", title: "Open in Safari", systemImageName: "safari", handler: { (_) in - self.present(SFSafariViewController(url: url)) + self.navigationDelegate?.selected(url: url) }), createAction(identifier: "share", title: "Share...", systemImageName: "square.and.arrow.up", handler: { (_) in - self.present(UIActivityViewController(activityItems: [url], applicationActivities: nil)) + self.navigationDelegate?.showMoreOptions(forURL: url) }) ] } @@ -58,13 +56,13 @@ extension MenuPreviewProvider { guard let status = MastodonCache.status(for: statusID) else { return [] } return [ createAction(identifier: "reply", title: "Reply", systemImageName: "arrowshape.turn.up.left", handler: { (_) in - self.present(UINavigationController(rootViewController: ComposeViewController(inReplyTo: statusID))) + self.navigationDelegate?.reply(to: statusID) }), createAction(identifier: "openinsafari", title: "Open in Safari", systemImageName: "safari", handler: { (_) in - self.present(SFSafariViewController(url: status.url!)) + self.navigationDelegate?.selected(url: status.url!) }), createAction(identifier: "share", title: "Share...", systemImageName: "square.and.arrow.up", handler: { (_) in - self.present(UIActivityViewController(activityItems: [status.url!], applicationActivities: nil)) + self.navigationDelegate?.showMoreOptions(forStatus: statusID) }) ] } diff --git a/Tusker/TuskerNavigationDelegate.swift b/Tusker/TuskerNavigationDelegate.swift index 7a7d7426..87931b7a 100644 --- a/Tusker/TuskerNavigationDelegate.swift +++ b/Tusker/TuskerNavigationDelegate.swift @@ -28,6 +28,8 @@ protocol TuskerNavigationDelegate { func compose() + func compose(mentioning: String?) + func reply(to statusID: String) func largeImage(_ image: UIImage, description: String?, sourceView: UIImageView) -> LargeImageViewController @@ -44,6 +46,8 @@ protocol TuskerNavigationDelegate { func showMoreOptions(forStatus statusID: String) + func showMoreOptions(forAccount accountID: String) + func showMoreOptions(forURL url: URL) func showFollowedByList(accountIDs: [String]) @@ -112,8 +116,13 @@ extension TuskerNavigationDelegate where Self: UIViewController { show(ConversationTableViewController(for: statusID, state: state), sender: self) } + // protocols can't have parameter defaults, so this stub is necessary to fulfill the protocol req func compose() { - let compose = ComposeViewController() + compose(mentioning: nil) + } + + func compose(mentioning: String? = nil) { + let compose = ComposeViewController( mentioningAcct: mentioning) let vc = UINavigationController(rootViewController: compose) vc.presentationController?.delegate = compose present(vc, animated: true) @@ -185,10 +194,10 @@ extension TuskerNavigationDelegate where Self: UIViewController { private func moreOptions(forStatus statusID: String) -> UIViewController { guard let status = MastodonCache.status(for: statusID) else { fatalError("Missing cached status \(statusID)") } guard let url = status.url else { fatalError("Missing url for status \(statusID)") } - var customActivites = [UIActivity]() + var customActivites: [UIActivity] = [OpenInSafariActivity()] if let bookmarked = status.bookmarked { - customActivites.append(bookmarked ? UnbookmarkStatusActivity() : BookmarkStatusActivity()) + customActivites.insert(bookmarked ? UnbookmarkStatusActivity() : BookmarkStatusActivity(), at: 0) } let activityController = UIActivityViewController(activityItems: [url, status], applicationActivities: customActivites) @@ -196,6 +205,11 @@ extension TuskerNavigationDelegate where Self: UIViewController { return activityController } + private func moreOptions(forAccount accountID: String) -> UIViewController { + guard let account = MastodonCache.account(for: accountID) else { fatalError("Missing cached account \(accountID)") } + return moreOptions(forURL: account.url) + } + func showMoreOptions(forStatus statusID: String) { present(moreOptions(forStatus: statusID), animated: true) } @@ -204,6 +218,10 @@ extension TuskerNavigationDelegate where Self: UIViewController { present(moreOptions(forURL: url), animated: true) } + func showMoreOptions(forAccount accountID: String) { + present(moreOptions(forAccount: accountID), animated: true) + } + func showFollowedByList(accountIDs: [String]) { let vc = AccountListTableViewController(accountIDs: accountIDs) vc.title = NSLocalizedString("Followed By", comment: "followed by accounts list title") diff --git a/Tusker/Views/Account Cell/AccountTableViewCell.swift b/Tusker/Views/Account Cell/AccountTableViewCell.swift index bbb04a21..e933d335 100644 --- a/Tusker/Views/Account Cell/AccountTableViewCell.swift +++ b/Tusker/Views/Account Cell/AccountTableViewCell.swift @@ -65,9 +65,9 @@ extension AccountTableViewCell: SelectableTableViewCell { } extension AccountTableViewCell: MenuPreviewProvider { + var navigationDelegate: TuskerNavigationDelegate? { return delegate } func getPreviewProviders(for location: CGPoint, sourceViewController: UIViewController) -> PreviewProviders? { return (content: { ProfileTableViewController(accountID: self.accountID) }, actions: { self.actionsForProfile(accountID: self.accountID) }) } - } diff --git a/Tusker/Views/NavigableTableViewCell.swift b/Tusker/Views/NavigableTableViewCell.swift new file mode 100644 index 00000000..c571a1ea --- /dev/null +++ b/Tusker/Views/NavigableTableViewCell.swift @@ -0,0 +1,13 @@ +// +// NavigableTableViewCell.swift +// Tusker +// +// Created by Shadowfacts on 12/14/19. +// Copyright © 2019 Shadowfacts. All rights reserved. +// + +import Foundation + +protocol NavigableTableViewCell { + var navigationDelegate: TuskerNavigationDelegate? { get } +} diff --git a/Tusker/Views/Notifications/ActionNotificationGroupTableViewCell.swift b/Tusker/Views/Notifications/ActionNotificationGroupTableViewCell.swift index bddfa518..33483d06 100644 --- a/Tusker/Views/Notifications/ActionNotificationGroupTableViewCell.swift +++ b/Tusker/Views/Notifications/ActionNotificationGroupTableViewCell.swift @@ -172,6 +172,7 @@ extension ActionNotificationGroupTableViewCell: SelectableTableViewCell { } extension ActionNotificationGroupTableViewCell: MenuPreviewProvider { + var navigationDelegate: TuskerNavigationDelegate? { return delegate } func getPreviewProviders(for location: CGPoint, sourceViewController: UIViewController) -> PreviewProviders? { return (content: { @@ -191,5 +192,4 @@ extension ActionNotificationGroupTableViewCell: MenuPreviewProvider { return [] }) } - } diff --git a/Tusker/Views/Notifications/FollowNotificationGroupTableViewCell.swift b/Tusker/Views/Notifications/FollowNotificationGroupTableViewCell.swift index 84849595..cafb5c13 100644 --- a/Tusker/Views/Notifications/FollowNotificationGroupTableViewCell.swift +++ b/Tusker/Views/Notifications/FollowNotificationGroupTableViewCell.swift @@ -130,6 +130,7 @@ extension FollowNotificationGroupTableViewCell: SelectableTableViewCell { } extension FollowNotificationGroupTableViewCell: MenuPreviewProvider { + var navigationDelegate: TuskerNavigationDelegate? { return delegate } func getPreviewProviders(for location: CGPoint, sourceViewController: UIViewController) -> PreviewProviders? { return (content: { @@ -143,5 +144,4 @@ extension FollowNotificationGroupTableViewCell: MenuPreviewProvider { return [] }) } - } diff --git a/Tusker/Views/Profile Header/ProfileHeaderTableViewCell.swift b/Tusker/Views/Profile Header/ProfileHeaderTableViewCell.swift index 0d8edaa7..a3517792 100644 --- a/Tusker/Views/Profile Header/ProfileHeaderTableViewCell.swift +++ b/Tusker/Views/Profile Header/ProfileHeaderTableViewCell.swift @@ -151,6 +151,7 @@ class ProfileHeaderTableViewCell: UITableViewCell { } extension ProfileHeaderTableViewCell: MenuPreviewProvider { + var navigationDelegate: TuskerNavigationDelegate? { return delegate } func getPreviewProviders(for location: CGPoint, sourceViewController: UIViewController) -> PreviewProviders? { let noteLabelPoint = noteLabel.convert(location, from: self) if noteLabel.bounds.contains(noteLabelPoint), diff --git a/Tusker/Views/Status/BaseStatusTableViewCell.swift b/Tusker/Views/Status/BaseStatusTableViewCell.swift index 7816e5c8..f17fe0ac 100644 --- a/Tusker/Views/Status/BaseStatusTableViewCell.swift +++ b/Tusker/Views/Status/BaseStatusTableViewCell.swift @@ -15,13 +15,12 @@ protocol StatusTableViewCellDelegate: TuskerNavigationDelegate { } class BaseStatusTableViewCell: UITableViewCell { - var delegate: StatusTableViewCellDelegate? { didSet { contentLabel.navigationDelegate = delegate } } - + @IBOutlet weak var avatarImageView: UIImageView! @IBOutlet weak var displayNameLabel: UILabel! @IBOutlet weak var usernameLabel: UILabel! @@ -311,6 +310,8 @@ extension BaseStatusTableViewCell: AttachmentViewDelegate { } extension BaseStatusTableViewCell: MenuPreviewProvider { + var navigationDelegate: TuskerNavigationDelegate? { return delegate } + func getPreviewProviders(for location: CGPoint, sourceViewController: UIViewController) -> PreviewProviders? { if avatarImageView.frame.contains(location) { return (content: { ProfileTableViewController(accountID: self.accountID)}, actions: { self.actionsForProfile(accountID: self.accountID) })