diff --git a/Tusker.xcodeproj/project.pbxproj b/Tusker.xcodeproj/project.pbxproj index 9dd15d8b..44d85d1e 100644 --- a/Tusker.xcodeproj/project.pbxproj +++ b/Tusker.xcodeproj/project.pbxproj @@ -118,6 +118,7 @@ D64BC18A23C16487000D0238 /* UnpinStatusActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64BC18923C16487000D0238 /* UnpinStatusActivity.swift */; }; D64BC18F23C18B9D000D0238 /* FollowRequestNotificationTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64BC18D23C18B9D000D0238 /* FollowRequestNotificationTableViewCell.swift */; }; D64BC19023C18B9D000D0238 /* FollowRequestNotificationTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D64BC18E23C18B9D000D0238 /* FollowRequestNotificationTableViewCell.xib */; }; + D64BC19223C271D9000D0238 /* MastodonActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64BC19123C271D9000D0238 /* MastodonActivity.swift */; }; D64D0AAD2128D88B005A6F37 /* LocalData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64D0AAC2128D88B005A6F37 /* LocalData.swift */; }; D64D0AB12128D9AE005A6F37 /* OnboardingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64D0AB02128D9AE005A6F37 /* OnboardingViewController.swift */; }; D64F80E2215875CC00BEF393 /* XCBActionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64F80E1215875CC00BEF393 /* XCBActionType.swift */; }; @@ -388,6 +389,7 @@ D64BC18923C16487000D0238 /* UnpinStatusActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnpinStatusActivity.swift; sourceTree = ""; }; D64BC18D23C18B9D000D0238 /* FollowRequestNotificationTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowRequestNotificationTableViewCell.swift; sourceTree = ""; }; D64BC18E23C18B9D000D0238 /* FollowRequestNotificationTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FollowRequestNotificationTableViewCell.xib; sourceTree = ""; }; + D64BC19123C271D9000D0238 /* MastodonActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonActivity.swift; sourceTree = ""; }; D64D0AAC2128D88B005A6F37 /* LocalData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalData.swift; sourceTree = ""; }; D64D0AB02128D9AE005A6F37 /* OnboardingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewController.swift; sourceTree = ""; }; D64F80E1215875CC00BEF393 /* XCBActionType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCBActionType.swift; sourceTree = ""; }; @@ -1056,6 +1058,7 @@ children = ( D6AEBB3D2321638100E5038B /* UIActivity+Types.swift */, D6AEBB422321685E00E5038B /* OpenInSafariActivity.swift */, + D64BC19123C271D9000D0238 /* MastodonActivity.swift */, D6AEBB4623216B0C00E5038B /* Account Activities */, D627943323A5523800D38C68 /* Status Activities */, ); @@ -1670,6 +1673,7 @@ D63661C02381C144004B9E16 /* PreferencesNavigationController.swift in Sources */, D6B053A223BD2C0600A066FA /* AssetPickerViewController.swift in Sources */, D627944A23A6AD6100D38C68 /* BookmarksTableViewController.swift in Sources */, + D64BC19223C271D9000D0238 /* MastodonActivity.swift in Sources */, D6945C3A23AC75E2005C403C /* FindInstanceViewController.swift in Sources */, D6AEBB4523216AF800E5038B /* FollowAccountActivity.swift in Sources */, D6538945214D6D7500E3CEFC /* TableViewSwipeActionProvider.swift in Sources */, diff --git a/Tusker/Activities/Account Activities/AccountActivity.swift b/Tusker/Activities/Account Activities/AccountActivity.swift index e12e2233..1b91a98e 100644 --- a/Tusker/Activities/Account Activities/AccountActivity.swift +++ b/Tusker/Activities/Account Activities/AccountActivity.swift @@ -9,7 +9,7 @@ import UIKit import Pachyderm -class AccountActivity: UIActivity { +class AccountActivity: MastodonActivity { override class var activityCategory: UIActivity.Category { return .action diff --git a/Tusker/Activities/Account Activities/FollowAccountActivity.swift b/Tusker/Activities/Account Activities/FollowAccountActivity.swift index f0dc74f2..7beb3523 100644 --- a/Tusker/Activities/Account Activities/FollowAccountActivity.swift +++ b/Tusker/Activities/Account Activities/FollowAccountActivity.swift @@ -28,7 +28,7 @@ class FollowAccountActivity: AccountActivity { UIImpactFeedbackGenerator(style: .medium).impactOccurred() let request = Account.follow(account.id) - MastodonController.run(request) { (response) in + mastodonController.run(request) { (response) in if case let .success(relationship, _) = response { MastodonCache.add(relationship: relationship) } else { diff --git a/Tusker/Activities/Account Activities/SendMesasgeActivity.swift b/Tusker/Activities/Account Activities/SendMesasgeActivity.swift index 0238b0ab..ea67c0b0 100644 --- a/Tusker/Activities/Account Activities/SendMesasgeActivity.swift +++ b/Tusker/Activities/Account Activities/SendMesasgeActivity.swift @@ -28,7 +28,7 @@ class SendMessageActivity: AccountActivity { override var activityViewController: UIViewController? { guard let account = account else { return nil } - return UINavigationController(rootViewController: ComposeViewController(mentioningAcct: account.acct)) + return UINavigationController(rootViewController: ComposeViewController(mentioningAcct: account.acct, mastodonController: mastodonController)) } } diff --git a/Tusker/Activities/Account Activities/UnfollowAccountActivity.swift b/Tusker/Activities/Account Activities/UnfollowAccountActivity.swift index 94daf756..344387d7 100644 --- a/Tusker/Activities/Account Activities/UnfollowAccountActivity.swift +++ b/Tusker/Activities/Account Activities/UnfollowAccountActivity.swift @@ -28,7 +28,7 @@ class UnfollowAccountActivity: AccountActivity { UIImpactFeedbackGenerator(style: .medium).impactOccurred() let request = Account.unfollow(account.id) - MastodonController.run(request) { (response) in + mastodonController.run(request) { (response) in if case let .success(relationship, _) = response { MastodonCache.add(relationship: relationship) } else { diff --git a/Tusker/Activities/MastodonActivity.swift b/Tusker/Activities/MastodonActivity.swift new file mode 100644 index 00000000..32275951 --- /dev/null +++ b/Tusker/Activities/MastodonActivity.swift @@ -0,0 +1,15 @@ +// +// MastodonActivity.swift +// Tusker +// +// Created by Shadowfacts on 1/5/20. +// Copyright © 2020 Shadowfacts. All rights reserved. +// + +import UIKit + +class MastodonActivity: UIActivity { + var mastodonController: MastodonController { + MastodonController.shared + } +} diff --git a/Tusker/Activities/Status Activities/BookmarkStatusActivity.swift b/Tusker/Activities/Status Activities/BookmarkStatusActivity.swift index df1fcfc9..8c64f007 100644 --- a/Tusker/Activities/Status Activities/BookmarkStatusActivity.swift +++ b/Tusker/Activities/Status Activities/BookmarkStatusActivity.swift @@ -27,7 +27,7 @@ class BookmarkStatusActivity: StatusActivity { guard let status = status else { return } let request = Status.bookmark(status) - MastodonController.run(request) { (response) in + mastodonController.run(request) { (response) in if case let .success(status, _) = response { MastodonCache.add(status: status) } else { diff --git a/Tusker/Activities/Status Activities/PinStatusActivity.swift b/Tusker/Activities/Status Activities/PinStatusActivity.swift index f73d0474..3714a453 100644 --- a/Tusker/Activities/Status Activities/PinStatusActivity.swift +++ b/Tusker/Activities/Status Activities/PinStatusActivity.swift @@ -26,7 +26,7 @@ class PinStatusActivity: StatusActivity { guard let status = status else { return } let request = Status.pin(status) - MastodonController.run(request) { (response) in + mastodonController.run(request) { (response) in if case let .success(status, _) = response { MastodonCache.add(status: status) } else { diff --git a/Tusker/Activities/Status Activities/StatusActivity.swift b/Tusker/Activities/Status Activities/StatusActivity.swift index 715b0a6e..3469b789 100644 --- a/Tusker/Activities/Status Activities/StatusActivity.swift +++ b/Tusker/Activities/Status Activities/StatusActivity.swift @@ -9,7 +9,7 @@ import UIKit import Pachyderm -class StatusActivity: UIActivity { +class StatusActivity: MastodonActivity { override class var activityCategory: UIActivity.Category { return .action diff --git a/Tusker/Activities/Status Activities/UnbookmarkStatusActivity.swift b/Tusker/Activities/Status Activities/UnbookmarkStatusActivity.swift index e88a3549..be22c5e1 100644 --- a/Tusker/Activities/Status Activities/UnbookmarkStatusActivity.swift +++ b/Tusker/Activities/Status Activities/UnbookmarkStatusActivity.swift @@ -27,7 +27,7 @@ class UnbookmarkStatusActivity: StatusActivity { guard let status = status else { return } let request = Status.unbookmark(status) - MastodonController.run(request) { (response) in + mastodonController.run(request) { (response) in if case let .success(status, _) = response { MastodonCache.add(status: status) } else { diff --git a/Tusker/Activities/Status Activities/UnpinStatusActivity.swift b/Tusker/Activities/Status Activities/UnpinStatusActivity.swift index 134e852d..cbb717cb 100644 --- a/Tusker/Activities/Status Activities/UnpinStatusActivity.swift +++ b/Tusker/Activities/Status Activities/UnpinStatusActivity.swift @@ -26,7 +26,7 @@ class UnpinStatusActivity: StatusActivity { guard let status = status else { return } let request = Status.unpin(status) - MastodonController.run(request) { (response) in + mastodonController.run(request) { (response) in if case let .success(status, _) = response { MastodonCache.add(status: status) } else { diff --git a/Tusker/AppDelegate.swift b/Tusker/AppDelegate.swift index 68e6c4a8..6f7521aa 100644 --- a/Tusker/AppDelegate.swift +++ b/Tusker/AppDelegate.swift @@ -12,6 +12,8 @@ import UIKit class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? + + let mastodonController = MastodonController.shared func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { AppShortcutItem.createItems(for: application) @@ -95,11 +97,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } func showAppUI() { - MastodonController.createClient() - MastodonController.getOwnAccount() - MastodonController.getOwnInstance() + mastodonController.createClient() + mastodonController.getOwnAccount() + mastodonController.getOwnInstance() - let tabBarController = MainTabBarViewController() + let tabBarController = MainTabBarViewController(mastodonController: mastodonController) window!.rootViewController = tabBarController } diff --git a/Tusker/Controllers/MastodonController.swift b/Tusker/Controllers/MastodonController.swift index 6c841c49..a916d777 100644 --- a/Tusker/Controllers/MastodonController.swift +++ b/Tusker/Controllers/MastodonController.swift @@ -11,32 +11,33 @@ import Pachyderm class MastodonController { - private static var client: Client! + @available(*, deprecated, message: "Use dependency injection to obtain an instance") + static let shared = MastodonController() - static var account: Account! - static var instance: Instance! + private var client: Client! - static var accessToken: String? { + var account: Account! + var instance: Instance! + + var accessToken: String? { client?.accessToken } - private init() {} - - static func createClient() { - guard let url = LocalData.shared.instanceURL else { fatalError("Can't connect without instance URL") } + func createClient(instanceURL: URL = LocalData.shared.instanceURL!) { + client = Client(baseURL: instanceURL) - client = Client(baseURL: url) - - client.clientID = LocalData.shared.clientID - client.clientSecret = LocalData.shared.clientSecret - client.accessToken = LocalData.shared.accessToken + if instanceURL == LocalData.shared.instanceURL { + client.clientID = LocalData.shared.clientID + client.clientSecret = LocalData.shared.clientSecret + client.accessToken = LocalData.shared.accessToken + } } - static func run(_ request: Request, completion: @escaping Client.Callback) { + func run(_ request: Request, completion: @escaping Client.Callback) { client.run(request, completion: completion) } - static func registerApp(completion: @escaping () -> Void) { + func registerApp(completion: @escaping () -> Void) { guard LocalData.shared.clientID == nil, LocalData.shared.clientSecret == nil else { completion() @@ -51,7 +52,7 @@ class MastodonController { } } - static func authorize(authorizationCode: String, completion: @escaping () -> Void) { + func authorize(authorizationCode: String, completion: @escaping () -> Void) { client.getAccessToken(authorizationCode: authorizationCode, redirectURI: "tusker://oauth") { response in guard case let .success(settings, _) = response else { fatalError() } LocalData.shared.accessToken = settings.accessToken @@ -59,7 +60,7 @@ class MastodonController { } } - static func getOwnAccount(completion: ((Account) -> Void)? = nil) { + func getOwnAccount(completion: ((Account) -> Void)? = nil) { if account != nil { completion?(account) } else { @@ -73,7 +74,7 @@ class MastodonController { } } - static func getOwnInstance() { + func getOwnInstance() { let request = Client.getInstance() run(request) { (response) in guard case let .success(instance, _) = response else { fatalError() } diff --git a/Tusker/MastodonCache.swift b/Tusker/MastodonCache.swift index 70b5482d..1ac5eddf 100644 --- a/Tusker/MastodonCache.swift +++ b/Tusker/MastodonCache.swift @@ -20,6 +20,8 @@ class MastodonCache { static let statusSubject = PassthroughSubject() static let accountSubject = PassthroughSubject() + static var mastodonController: MastodonController { .shared } + // MARK: - Statuses static func status(for id: String) -> Status? { return statuses[id] @@ -38,7 +40,7 @@ class MastodonCache { static func status(for id: String, completion: @escaping (Status?) -> Void) { let request = Client.getStatus(id: id) - MastodonController.run(request) { response in + mastodonController.run(request) { response in guard case let .success(status, _) = response else { completion(nil) return @@ -68,7 +70,7 @@ class MastodonCache { static func account(for id: String, completion: @escaping (Account?) -> Void) { let request = Client.getAccount(id: id) - MastodonController.run(request) { response in + mastodonController.run(request) { response in guard case let .success(account, _) = response else { completion(nil) return @@ -97,7 +99,7 @@ class MastodonCache { static func relationship(for id: String, completion: @escaping (Relationship?) -> Void) { let request = Client.getRelationships(accounts: [id]) - MastodonController.run(request) { response in + mastodonController.run(request) { response in guard case let .success(relationships, _) = response, let relationship = relationships.first else { completion(nil) diff --git a/Tusker/Screens/Account List/AccountListTableViewController.swift b/Tusker/Screens/Account List/AccountListTableViewController.swift index 8635a017..36fe72e2 100644 --- a/Tusker/Screens/Account List/AccountListTableViewController.swift +++ b/Tusker/Screens/Account List/AccountListTableViewController.swift @@ -12,10 +12,13 @@ class AccountListTableViewController: EnhancedTableViewController { private let accountCell = "accountCell" + let mastodonController: MastodonController + let accountIDs: [String] - init(accountIDs: [String]) { + init(accountIDs: [String], mastodonController: MastodonController) { self.accountIDs = accountIDs + self.mastodonController = mastodonController super.init(style: .grouped) } @@ -58,4 +61,6 @@ class AccountListTableViewController: EnhancedTableViewController { } -extension AccountListTableViewController: TuskerNavigationDelegate {} +extension AccountListTableViewController: TuskerNavigationDelegate { + var apiController: MastodonController { mastodonController } +} diff --git a/Tusker/Screens/Bookmarks/BookmarksTableViewController.swift b/Tusker/Screens/Bookmarks/BookmarksTableViewController.swift index 142213af..a4370c05 100644 --- a/Tusker/Screens/Bookmarks/BookmarksTableViewController.swift +++ b/Tusker/Screens/Bookmarks/BookmarksTableViewController.swift @@ -13,6 +13,8 @@ class BookmarksTableViewController: EnhancedTableViewController { private let statusCell = "statusCell" + let mastodonController: MastodonController + var statuses: [(id: String, state: StatusState)] = [] { didSet { DispatchQueue.main.async { @@ -24,7 +26,9 @@ class BookmarksTableViewController: EnhancedTableViewController { var newer: RequestRange? var older: RequestRange? - init() { + init(mastodonController: MastodonController) { + self.mastodonController = mastodonController + super.init(style: .plain) title = NSLocalizedString("Bookmarks", comment: "bookmarks screen title") @@ -45,7 +49,7 @@ class BookmarksTableViewController: EnhancedTableViewController { tableView.prefetchDataSource = self let request = Client.getBookmarks() - MastodonController.run(request) { (response) in + mastodonController.run(request) { (response) in guard case let .success(statuses, pagination) = response else { fatalError() } MastodonCache.addAll(statuses: statuses) self.statuses.append(contentsOf: statuses.map { ($0.id, .unknown) }) @@ -82,7 +86,7 @@ class BookmarksTableViewController: EnhancedTableViewController { } let request = Client.getBookmarks(range: older) - MastodonController.run(request) { (response) in + mastodonController.run(request) { (response) in guard case let .success(newStatuses, pagination) = response else { fatalError() } self.older = pagination?.older MastodonCache.addAll(statuses: newStatuses) @@ -107,7 +111,7 @@ class BookmarksTableViewController: EnhancedTableViewController { let unbookmarkAction = UIContextualAction(style: .destructive, title: NSLocalizedString("Unbookmark", comment: "unbookmark action title")) { (action, view, completion) in let request = Status.unbookmark(status) - MastodonController.run(request) { (response) in + self.mastodonController.run(request) { (response) in guard case let .success(newStatus, _) = response else { fatalError() } MastodonCache.add(status: newStatus) self.statuses.remove(at: indexPath.row) @@ -131,7 +135,7 @@ class BookmarksTableViewController: EnhancedTableViewController { return [ UIAction(title: NSLocalizedString("Unbookmark", comment: "unbookmark action title"), image: UIImage(systemName: "bookmark.fill"), identifier: .init("unbookmark"), discoverabilityTitle: nil, attributes: [], state: .off, handler: { (_) in let request = Status.unbookmark(status) - MastodonController.run(request) { (response) in + self.mastodonController.run(request) { (response) in guard case let .success(newStatus, _) = response else { fatalError() } MastodonCache.add(status: newStatus) self.statuses.remove(at: indexPath.row) @@ -143,6 +147,8 @@ class BookmarksTableViewController: EnhancedTableViewController { } extension BookmarksTableViewController: StatusTableViewCellDelegate { + var apiController: MastodonController { mastodonController } + func statusCellCollapsedStateChanged(_ cell: BaseStatusTableViewCell) { tableView.beginUpdates() tableView.endUpdates() diff --git a/Tusker/Screens/Compose/ComposeViewController.swift b/Tusker/Screens/Compose/ComposeViewController.swift index 6dbabc22..07a68169 100644 --- a/Tusker/Screens/Compose/ComposeViewController.swift +++ b/Tusker/Screens/Compose/ComposeViewController.swift @@ -12,6 +12,8 @@ import Intents class ComposeViewController: UIViewController { + let mastodonController: MastodonController + var inReplyToID: String? var accountsToMention: [String] var initialText: String? @@ -64,7 +66,9 @@ class ComposeViewController: UIViewController { @IBOutlet weak var postProgressView: SteppedProgressView! - init(inReplyTo inReplyToID: String? = nil, mentioningAcct: String? = nil, text: String? = nil) { + init(inReplyTo inReplyToID: String? = nil, mentioningAcct: String? = nil, text: String? = nil, mastodonController: MastodonController) { + self.mastodonController = mastodonController + self.inReplyToID = inReplyToID if let inReplyToID = inReplyToID, let inReplyTo = MastodonCache.status(for: inReplyToID) { accountsToMention = [inReplyTo.account.acct] + inReplyTo.mentions.map { $0.acct } @@ -73,7 +77,7 @@ class ComposeViewController: UIViewController { } else { accountsToMention = [] } - if let ownAccount = MastodonController.account { + if let ownAccount = mastodonController.account { accountsToMention.removeAll(where: { acct in ownAccount.acct == acct }) } accountsToMention = accountsToMention.uniques() @@ -120,7 +124,7 @@ class ComposeViewController: UIViewController { statusTextView.text = accountsToMention.map({ acct in "@\(acct) " }).joined() initialText = statusTextView.text - MastodonController.getOwnAccount { (account) in + mastodonController.getOwnAccount { (account) in DispatchQueue.main.async { self.selfDetailView.update(account: account) } @@ -270,7 +274,7 @@ class ComposeViewController: UIViewController { // TODO: include CW char count let count = CharacterCounter.count(text: statusTextView.text) let cwCount = contentWarningEnabled ? (contentWarningTextField.text?.count ?? 0) : 0 - let remaining = (MastodonController.instance.maxStatusCharacters ?? 500) - count - cwCount + let remaining = (mastodonController.instance.maxStatusCharacters ?? 500) - count - cwCount if remaining < 0 { charactersRemainingLabel.textColor = .red postBarButtonItem.isEnabled = false @@ -296,7 +300,7 @@ class ComposeViewController: UIViewController { } func updateAddAttachmentButton() { - switch MastodonController.instance.instanceType { + switch mastodonController.instance.instanceType { case .pleroma: addAttachmentButton.isEnabled = true case .mastodon: @@ -481,7 +485,7 @@ class ComposeViewController: UIViewController { self.postProgressView.step() let request = Client.upload(attachment: FormAttachment(mimeType: mimeType, data: data, fileName: "file"), description: description) - MastodonController.run(request) { (response) in + self.mastodonController.run(request) { (response) in guard case let .success(attachment, _) = response else { fatalError() } attachments[index] = attachment @@ -507,7 +511,7 @@ class ComposeViewController: UIViewController { spoilerText: contentWarning, visibility: visibility, language: nil) - MastodonController.run(request) { (response) in + self.mastodonController.run(request) { (response) in guard case let .success(status, _) = response else { fatalError() } self.postedStatus = status MastodonCache.add(status: status) @@ -520,7 +524,7 @@ class ComposeViewController: UIViewController { self.postProgressView.step() self.dismiss(animated: true) - let conversationVC = ConversationTableViewController(for: status.id) + let conversationVC = ConversationTableViewController(for: status.id, mastodonController: self.mastodonController) self.show(conversationVC, sender: self) self.xcbSession?.complete(with: .success, additionalData: [ @@ -561,7 +565,7 @@ extension ComposeViewController: UITextViewDelegate { extension ComposeViewController: AssetPickerViewControllerDelegate { func assetPicker(_ assetPicker: AssetPickerViewController, shouldAllowAssetOfType type: CompositionAttachment.AttachmentType) -> Bool { - switch MastodonController.instance.instanceType { + switch mastodonController.instance.instanceType { case .pleroma: return true case .mastodon: diff --git a/Tusker/Screens/Conversation/ConversationTableViewController.swift b/Tusker/Screens/Conversation/ConversationTableViewController.swift index 92410f58..31bbc061 100644 --- a/Tusker/Screens/Conversation/ConversationTableViewController.swift +++ b/Tusker/Screens/Conversation/ConversationTableViewController.swift @@ -15,6 +15,8 @@ class ConversationTableViewController: EnhancedTableViewController { static let showPostsImage = UIImage(systemName: "eye.fill")! static let hidePostsImage = UIImage(systemName: "eye.slash.fill")! + let mastodonController: MastodonController + let mainStatusID: String let mainStatusState: StatusState var statuses: [(id: String, state: StatusState)] = [] { @@ -28,9 +30,10 @@ class ConversationTableViewController: EnhancedTableViewController { var showStatusesAutomatically = false var visibilityBarButtonItem: UIBarButtonItem! - init(for mainStatusID: String, state: StatusState = .unknown) { + init(for mainStatusID: String, state: StatusState = .unknown, mastodonController: MastodonController) { self.mainStatusID = mainStatusID self.mainStatusState = state + self.mastodonController = mastodonController super.init(style: .plain) } @@ -58,7 +61,7 @@ class ConversationTableViewController: EnhancedTableViewController { guard let mainStatus = MastodonCache.status(for: mainStatusID) else { fatalError("Missing cached status \(mainStatusID)") } let request = Status.getContext(mainStatus) - MastodonController.run(request) { response in + mastodonController.run(request) { response in guard case let .success(context, _) = response else { fatalError() } let parents = self.getDirectParents(of: mainStatus, from: context.ancestors) MastodonCache.addAll(statuses: parents) @@ -155,6 +158,7 @@ class ConversationTableViewController: EnhancedTableViewController { } extension ConversationTableViewController: StatusTableViewCellDelegate { + var apiController: MastodonController { mastodonController } func statusCellCollapsedStateChanged(_ cell: BaseStatusTableViewCell) { // causes the table view to recalculate the cell heights tableView.beginUpdates() diff --git a/Tusker/Screens/Explore/ExploreViewController.swift b/Tusker/Screens/Explore/ExploreViewController.swift index a7f6fc12..c278c2b4 100644 --- a/Tusker/Screens/Explore/ExploreViewController.swift +++ b/Tusker/Screens/Explore/ExploreViewController.swift @@ -12,12 +12,16 @@ import Pachyderm class ExploreViewController: EnhancedTableViewController { + let mastodonController: MastodonController + var dataSource: DataSource! var resultsController: SearchResultsViewController! var searchController: UISearchController! - init() { + init(mastodonController: MastodonController) { + self.mastodonController = mastodonController + super.init(style: .insetGrouped) title = NSLocalizedString("Explore", comment: "explore tab title") @@ -88,7 +92,7 @@ class ExploreViewController: EnhancedTableViewController { dataSource.apply(snapshot) } - resultsController = SearchResultsViewController() + resultsController = SearchResultsViewController(mastodonController: mastodonController) resultsController.exploreNavigationController = self.navigationController! searchController = UISearchController(searchResultsController: resultsController) searchController.searchResultsUpdater = resultsController @@ -107,7 +111,7 @@ class ExploreViewController: EnhancedTableViewController { func reloadLists() { let request = Client.getLists() - MastodonController.run(request) { (response) in + mastodonController.run(request) { (response) in guard case let .success(lists, _) = response else { fatalError() } @@ -143,7 +147,7 @@ class ExploreViewController: EnhancedTableViewController { alert.addAction(UIAlertAction(title: NSLocalizedString("Delete List", comment: "delete list alert confirm button"), style: .destructive, handler: { (_) in let request = List.delete(list) - MastodonController.run(request) { (response) in + self.mastodonController.run(request) { (response) in guard case .success(_, _) = response else { fatalError() } @@ -174,10 +178,10 @@ class ExploreViewController: EnhancedTableViewController { return case .bookmarks: - show(BookmarksTableViewController(), sender: nil) + show(BookmarksTableViewController(mastodonController: mastodonController), sender: nil) case let .list(list): - show(ListTimelineViewController(for: list), sender: nil) + show(ListTimelineViewController(for: list, mastodonController: mastodonController), sender: nil) case .addList: tableView.selectRow(at: nil, animated: true, scrollPosition: .none) @@ -190,13 +194,13 @@ class ExploreViewController: EnhancedTableViewController { } let request = Client.createList(title: title) - MastodonController.run(request) { (response) in + self.mastodonController.run(request) { (response) in guard case let .success(list, _) = response else { fatalError() } self.reloadLists() DispatchQueue.main.async { - let listTimelineController = ListTimelineViewController(for: list) + let listTimelineController = ListTimelineViewController(for: list, mastodonController: self.mastodonController) listTimelineController.presentEditOnAppear = true self.show(listTimelineController, sender: nil) } @@ -205,11 +209,11 @@ class ExploreViewController: EnhancedTableViewController { present(alert, animated: true) case let .savedHashtag(hashtag): - show(HashtagTimelineViewController(for: hashtag), sender: nil) + show(HashtagTimelineViewController(for: hashtag, mastodonController: mastodonController), sender: nil) case .addSavedHashtag: tableView.selectRow(at: nil, animated: true, scrollPosition: .none) - let navController = UINavigationController(rootViewController: AddSavedHashtagViewController()) + let navController = UINavigationController(rootViewController: AddSavedHashtagViewController(mastodonController: mastodonController)) present(navController, animated: true) case let .savedInstance(url): diff --git a/Tusker/Screens/Lists/EditListAccountsViewController.swift b/Tusker/Screens/Lists/EditListAccountsViewController.swift index 7484d1dd..796c58f4 100644 --- a/Tusker/Screens/Lists/EditListAccountsViewController.swift +++ b/Tusker/Screens/Lists/EditListAccountsViewController.swift @@ -11,6 +11,8 @@ import Pachyderm class EditListAccountsViewController: EnhancedTableViewController { + let mastodonController: MastodonController + let list: List var dataSource: DataSource! @@ -20,8 +22,9 @@ class EditListAccountsViewController: EnhancedTableViewController { var searchResultsController: SearchResultsViewController! var searchController: UISearchController! - init(list: List) { + init(list: List, mastodonController: MastodonController) { self.list = list + self.mastodonController = mastodonController super.init(style: .plain) @@ -49,7 +52,7 @@ class EditListAccountsViewController: EnhancedTableViewController { }) dataSource.editListAccountsController = self - searchResultsController = SearchResultsViewController() + searchResultsController = SearchResultsViewController(mastodonController: mastodonController) searchResultsController.delegate = self searchResultsController.onlySections = [.accounts] searchController = UISearchController(searchResultsController: searchResultsController) @@ -70,7 +73,7 @@ class EditListAccountsViewController: EnhancedTableViewController { func loadAccounts() { let request = List.getAccounts(list) - MastodonController.run(request) { (response) in + mastodonController.run(request) { (response) in guard case let .success(accounts, pagination) = response else { fatalError() } @@ -109,7 +112,7 @@ class EditListAccountsViewController: EnhancedTableViewController { fatalError() } let request = List.update(self.list, title: text) - MastodonController.run(request) { (response) in + self.mastodonController.run(request) { (response) in guard case .success(_, _) = response else { fatalError() } @@ -143,7 +146,7 @@ extension EditListAccountsViewController { } let request = List.remove(editListAccountsController!.list, accounts: [id]) - MastodonController.run(request) { (response) in + editListAccountsController!.mastodonController.run(request) { (response) in guard case .success(_, _) = response else { fatalError() } @@ -157,7 +160,7 @@ extension EditListAccountsViewController { extension EditListAccountsViewController: SearchResultsViewControllerDelegate { func selectedSearchResult(account accountID: String) { let request = List.add(list, accounts: [accountID]) - MastodonController.run(request) { (response) in + mastodonController.run(request) { (response) in guard case .success(_, _) = response else { fatalError() } diff --git a/Tusker/Screens/Lists/ListTimelineViewController.swift b/Tusker/Screens/Lists/ListTimelineViewController.swift index 664d65ee..bf8dbac3 100644 --- a/Tusker/Screens/Lists/ListTimelineViewController.swift +++ b/Tusker/Screens/Lists/ListTimelineViewController.swift @@ -15,10 +15,10 @@ class ListTimelineViewController: TimelineTableViewController { var presentEditOnAppear = false - init(for list: List) { + init(for list: List, mastodonController: MastodonController) { self.list = list - super.init(for: .list(id: list.id)) + super.init(for: .list(id: list.id), mastodonController: mastodonController) title = list.title } @@ -42,7 +42,7 @@ class ListTimelineViewController: TimelineTableViewController { } func presentEdit(animated: Bool) { - let editListAccountsController = EditListAccountsViewController(list: list) + let editListAccountsController = EditListAccountsViewController(list: list, mastodonController: mastodonController) editListAccountsController.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneButtonPressed)) let navController = UINavigationController(rootViewController: editListAccountsController) present(navController, animated: animated) diff --git a/Tusker/Screens/Main/MainTabBarViewController.swift b/Tusker/Screens/Main/MainTabBarViewController.swift index 02590765..d0d01655 100644 --- a/Tusker/Screens/Main/MainTabBarViewController.swift +++ b/Tusker/Screens/Main/MainTabBarViewController.swift @@ -9,18 +9,30 @@ import UIKit class MainTabBarViewController: UITabBarController, UITabBarControllerDelegate { - + + let mastodonController: MastodonController + + init(mastodonController: MastodonController) { + self.mastodonController = mastodonController + + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + override func viewDidLoad() { super.viewDidLoad() self.delegate = self viewControllers = [ - embedInNavigationController(TimelinesPageViewController()), - embedInNavigationController(NotificationsPageViewController()), - ComposeViewController(), - embedInNavigationController(ExploreViewController()), - embedInNavigationController(MyProfileTableViewController()), + embedInNavigationController(TimelinesPageViewController(mastodonController: mastodonController)), + embedInNavigationController(NotificationsPageViewController(mastodonController: mastodonController)), + ComposeViewController(mastodonController: mastodonController), + embedInNavigationController(ExploreViewController(mastodonController: mastodonController)), + embedInNavigationController(MyProfileTableViewController(mastodonController: mastodonController)), ] } @@ -41,7 +53,7 @@ class MainTabBarViewController: UITabBarController, UITabBarControllerDelegate { } func presentCompose() { - let compose = ComposeViewController() + let compose = ComposeViewController(mastodonController: mastodonController) let navigationController = embedInNavigationController(compose) navigationController.presentationController?.delegate = compose present(navigationController, animated: true) diff --git a/Tusker/Screens/Notifications/NotificationsPageViewController.swift b/Tusker/Screens/Notifications/NotificationsPageViewController.swift index 3e503e1b..ac66701a 100644 --- a/Tusker/Screens/Notifications/NotificationsPageViewController.swift +++ b/Tusker/Screens/Notifications/NotificationsPageViewController.swift @@ -13,13 +13,17 @@ class NotificationsPageViewController: SegmentedPageViewController { private let notificationsTitle = NSLocalizedString("Notifications", comment: "notifications tab title") private let mentionsTitle = NSLocalizedString("Mentions", comment: "mentions tab title") + + let mastodonController: MastodonController - init() { - let notifications = NotificationsTableViewController(allowedTypes: Pachyderm.Notification.Kind.allCases) + init(mastodonController: MastodonController) { + self.mastodonController = mastodonController + + let notifications = NotificationsTableViewController(allowedTypes: Pachyderm.Notification.Kind.allCases, mastodonController: mastodonController) notifications.title = notificationsTitle notifications.userActivity = UserActivityManager.checkNotificationsActivity() - let mentions = NotificationsTableViewController(allowedTypes: [.mention]) + let mentions = NotificationsTableViewController(allowedTypes: [.mention], mastodonController: mastodonController) mentions.title = mentionsTitle mentions.userActivity = UserActivityManager.checkMentionsActivity() diff --git a/Tusker/Screens/Notifications/NotificationsTableViewController.swift b/Tusker/Screens/Notifications/NotificationsTableViewController.swift index ae6ccf35..4bee64b2 100644 --- a/Tusker/Screens/Notifications/NotificationsTableViewController.swift +++ b/Tusker/Screens/Notifications/NotificationsTableViewController.swift @@ -16,6 +16,8 @@ class NotificationsTableViewController: EnhancedTableViewController { private let followGroupCell = "followGroupCell" private let followRequestCell = "followRequestCell" + let mastodonController: MastodonController + let excludedTypes: [Pachyderm.Notification.Kind] let groupTypes = [Notification.Kind.favourite, .reblog, .follow] @@ -30,8 +32,9 @@ class NotificationsTableViewController: EnhancedTableViewController { var newer: RequestRange? var older: RequestRange? - init(allowedTypes: [Pachyderm.Notification.Kind]) { + init(allowedTypes: [Pachyderm.Notification.Kind], mastodonController: MastodonController) { self.excludedTypes = Array(Set(Pachyderm.Notification.Kind.allCases).subtracting(allowedTypes)) + self.mastodonController = mastodonController super.init(style: .plain) @@ -57,7 +60,7 @@ class NotificationsTableViewController: EnhancedTableViewController { tableView.prefetchDataSource = self let request = Client.getNotifications(excludeTypes: excludedTypes) - MastodonController.run(request) { result in + mastodonController.run(request) { result in guard case let .success(notifications, pagination) = result else { fatalError() } let groups = NotificationGroup.createGroups(notifications: notifications, only: self.groupTypes) @@ -125,7 +128,7 @@ class NotificationsTableViewController: EnhancedTableViewController { guard let older = older else { return } let request = Client.getNotifications(excludeTypes: excludedTypes, range: older) - MastodonController.run(request) { result in + mastodonController.run(request) { result in guard case let .success(newNotifications, pagination) = result else { fatalError() } let groups = NotificationGroup.createGroups(notifications: newNotifications, only: self.groupTypes) @@ -182,7 +185,7 @@ class NotificationsTableViewController: EnhancedTableViewController { .map(Pachyderm.Notification.dismiss(id:)) .forEach { (request) in group.enter() - MastodonController.run(request) { (response) in + mastodonController.run(request) { (response) in group.leave() } } @@ -197,7 +200,7 @@ class NotificationsTableViewController: EnhancedTableViewController { guard let newer = newer else { return } let request = Client.getNotifications(excludeTypes: excludedTypes, range: newer) - MastodonController.run(request) { result in + mastodonController.run(request) { result in guard case let .success(newNotifications, pagination) = result else { fatalError() } let groups = NotificationGroup.createGroups(notifications: newNotifications, only: self.groupTypes) @@ -222,6 +225,7 @@ class NotificationsTableViewController: EnhancedTableViewController { } extension NotificationsTableViewController: StatusTableViewCellDelegate { + var apiController: MastodonController { mastodonController } func statusCellCollapsedStateChanged(_ cell: BaseStatusTableViewCell) { // causes the table view to recalculate the cell heights tableView.beginUpdates() diff --git a/Tusker/Screens/Onboarding/OnboardingViewController.swift b/Tusker/Screens/Onboarding/OnboardingViewController.swift index 7df60929..21daac5e 100644 --- a/Tusker/Screens/Onboarding/OnboardingViewController.swift +++ b/Tusker/Screens/Onboarding/OnboardingViewController.swift @@ -46,8 +46,9 @@ class OnboardingViewController: UINavigationController { extension OnboardingViewController: InstanceSelectorTableViewControllerDelegate { func didSelectInstance(url: URL) { LocalData.shared.instanceURL = url - MastodonController.createClient() - MastodonController.registerApp { + let mastodonController = MastodonController.shared + mastodonController.createClient() + mastodonController.registerApp { let clientID = LocalData.shared.clientID! let callbackURL = "tusker://oauth" @@ -69,7 +70,7 @@ extension OnboardingViewController: InstanceSelectorTableViewControllerDelegate let item = components.queryItems?.first(where: { $0.name == "code" }), let authCode = item.value else { return } - MastodonController.authorize(authorizationCode: authCode) { + mastodonController.authorize(authorizationCode: authCode) { DispatchQueue.main.async { self.onboardingDelegate?.didFinishOnboarding() } diff --git a/Tusker/Screens/Profile/MyProfileTableViewController.swift b/Tusker/Screens/Profile/MyProfileTableViewController.swift index 3e58ac59..7fef8706 100644 --- a/Tusker/Screens/Profile/MyProfileTableViewController.swift +++ b/Tusker/Screens/Profile/MyProfileTableViewController.swift @@ -11,14 +11,14 @@ import SwiftUI class MyProfileTableViewController: ProfileTableViewController { - init() { - super.init(accountID: nil) + init(mastodonController: MastodonController) { + super.init(accountID: nil, mastodonController: mastodonController) title = "My Profile" tabBarItem.image = UIImage(systemName: "person.fill") - MastodonController.getOwnAccount { (account) in + mastodonController.getOwnAccount { (account) in self.accountID = account.id ImageCache.avatars.get(account.avatar, completion: { (data) in diff --git a/Tusker/Screens/Profile/ProfileTableViewController.swift b/Tusker/Screens/Profile/ProfileTableViewController.swift index 45b520e0..e6b1d4b3 100644 --- a/Tusker/Screens/Profile/ProfileTableViewController.swift +++ b/Tusker/Screens/Profile/ProfileTableViewController.swift @@ -12,6 +12,8 @@ import SafariServices class ProfileTableViewController: EnhancedTableViewController { + let mastodonController: MastodonController + var accountID: String! { didSet { if shouldLoadOnAccountIDSet { @@ -43,7 +45,9 @@ class ProfileTableViewController: EnhancedTableViewController { var shouldLoadOnAccountIDSet = false var loadingVC: LoadingViewController? = nil - init(accountID: String?) { + init(accountID: String?, mastodonController: MastodonController) { + self.mastodonController = mastodonController + self.accountID = accountID super.init(style: .plain) @@ -130,12 +134,12 @@ class ProfileTableViewController: EnhancedTableViewController { func getStatuses(for range: RequestRange = .default, onlyPinned: Bool = false, completion: @escaping Client.Callback<[Status]>) { let request = Account.getStatuses(accountID, range: range, onlyMedia: false, pinned: onlyPinned, excludeReplies: !Preferences.shared.showRepliesInProfiles) - MastodonController.run(request, completion: completion) + mastodonController.run(request, completion: completion) } func sendMessageMentioning() { guard let account = MastodonCache.account(for: accountID) else { fatalError("Missing cached account \(accountID!)") } - let vc = UINavigationController(rootViewController: ComposeViewController(mentioningAcct: account.acct)) + let vc = UINavigationController(rootViewController: ComposeViewController(mentioningAcct: account.acct, mastodonController: mastodonController)) present(vc, animated: true) } @@ -233,6 +237,8 @@ class ProfileTableViewController: EnhancedTableViewController { } extension ProfileTableViewController: StatusTableViewCellDelegate { + var apiController: MastodonController { mastodonController } + func statusCellCollapsedStateChanged(_ cell: BaseStatusTableViewCell) { // causes the table view to recalculate the cell heights tableView.beginUpdates() diff --git a/Tusker/Screens/Search/SearchResultsViewController.swift b/Tusker/Screens/Search/SearchResultsViewController.swift index ad77eed3..45e97c4b 100644 --- a/Tusker/Screens/Search/SearchResultsViewController.swift +++ b/Tusker/Screens/Search/SearchResultsViewController.swift @@ -28,6 +28,8 @@ extension SearchResultsViewControllerDelegate { class SearchResultsViewController: EnhancedTableViewController { + let mastodonController: MastodonController! + weak var exploreNavigationController: UINavigationController? weak var delegate: SearchResultsViewControllerDelegate? @@ -40,7 +42,9 @@ class SearchResultsViewController: EnhancedTableViewController { let searchSubject = PassthroughSubject() var currentQuery: String? - init() { + init(mastodonController: MastodonController) { + self.mastodonController = mastodonController + super.init(style: .grouped) title = NSLocalizedString("Search", comment: "search screen title") @@ -118,7 +122,7 @@ class SearchResultsViewController: EnhancedTableViewController { } let request = Client.search(query: query, resolve: true, limit: 10) - MastodonController.run(request) { (response) in + mastodonController.run(request) { (response) in guard case let .success(results, _) = response else { fatalError() } DispatchQueue.main.async { @@ -217,6 +221,7 @@ extension SearchResultsViewController: UISearchBarDelegate { } extension SearchResultsViewController: StatusTableViewCellDelegate { + var apiController: MastodonController { mastodonController } func statusCellCollapsedStateChanged(_ cell: BaseStatusTableViewCell) { tableView.beginUpdates() tableView.endUpdates() diff --git a/Tusker/Screens/Status Action Account List/StatusActionAccountListTableViewController.swift b/Tusker/Screens/Status Action Account List/StatusActionAccountListTableViewController.swift index 9ccf9234..e0d9195c 100644 --- a/Tusker/Screens/Status Action Account List/StatusActionAccountListTableViewController.swift +++ b/Tusker/Screens/Status Action Account List/StatusActionAccountListTableViewController.swift @@ -14,6 +14,8 @@ class StatusActionAccountListTableViewController: EnhancedTableViewController { private let statusCell = "statusCell" private let accountCell = "accountCell" + let mastodonController: MastodonController + let actionType: ActionType let statusID: String var statusState: StatusState @@ -32,8 +34,11 @@ class StatusActionAccountListTableViewController: EnhancedTableViewController { - Parameter actionType The action that this VC is for. - Parameter statusID The ID of the status to show. - Parameter accountIDs The accounts that will be shown. If `nil` is passed, a request will be performed to load the accounts. + - Parameter mastodonController The `MastodonController` instance this view controller uses. */ - init(actionType: ActionType, statusID: String, statusState: StatusState, accountIDs: [String]?) { + init(actionType: ActionType, statusID: String, statusState: StatusState, accountIDs: [String]?, mastodonController: MastodonController) { + self.mastodonController = mastodonController + self.actionType = actionType self.statusID = statusID self.statusState = statusState @@ -75,7 +80,7 @@ class StatusActionAccountListTableViewController: EnhancedTableViewController { tableView.tableFooterView = UIActivityIndicatorView(style: .large) let request = actionType == .favorite ? Status.getFavourites(status) : Status.getReblogs(status) - MastodonController.run(request) { (response) in + mastodonController.run(request) { (response) in guard case let .success(accounts, _) = response else { fatalError() } MastodonCache.addAll(accounts: accounts) DispatchQueue.main.async { @@ -137,6 +142,7 @@ class StatusActionAccountListTableViewController: EnhancedTableViewController { } extension StatusActionAccountListTableViewController: StatusTableViewCellDelegate { + var apiController: MastodonController { mastodonController } func statusCellCollapsedStateChanged(_ cell: BaseStatusTableViewCell) { // causes the table view to recalculate the cell heights tableView.beginUpdates() diff --git a/Tusker/Screens/Timeline/HashtagTimelineViewController.swift b/Tusker/Screens/Timeline/HashtagTimelineViewController.swift index 0313a11e..3dcd8787 100644 --- a/Tusker/Screens/Timeline/HashtagTimelineViewController.swift +++ b/Tusker/Screens/Timeline/HashtagTimelineViewController.swift @@ -22,10 +22,10 @@ class HashtagTimelineViewController: TimelineTableViewController { } } - init(for hashtag: Hashtag) { + init(for hashtag: Hashtag, mastodonController: MastodonController) { self.hashtag = hashtag - super.init(for: .tag(hashtag: hashtag.name)) + super.init(for: .tag(hashtag: hashtag.name), mastodonController: mastodonController) } required init?(coder aDecoder: NSCoder) { diff --git a/Tusker/Screens/Timeline/InstanceTimelineViewController.swift b/Tusker/Screens/Timeline/InstanceTimelineViewController.swift index 405c998f..b5ee418d 100644 --- a/Tusker/Screens/Timeline/InstanceTimelineViewController.swift +++ b/Tusker/Screens/Timeline/InstanceTimelineViewController.swift @@ -31,7 +31,10 @@ class InstanceTimelineViewController: TimelineTableViewController { init(for url: URL) { self.instanceURL = url - super.init(for: .instance(instanceURL: url)) + let mastodonController = MastodonController() + mastodonController.createClient(instanceURL: url) + + super.init(for: .instance(instanceURL: url), mastodonController: mastodonController) } required init?(coder aDecoder: NSCoder) { diff --git a/Tusker/Screens/Timeline/TimelineTableViewController.swift b/Tusker/Screens/Timeline/TimelineTableViewController.swift index f38cacd2..f110638f 100644 --- a/Tusker/Screens/Timeline/TimelineTableViewController.swift +++ b/Tusker/Screens/Timeline/TimelineTableViewController.swift @@ -12,6 +12,7 @@ import Pachyderm class TimelineTableViewController: EnhancedTableViewController { var timeline: Timeline! + let mastodonController: MastodonController var timelineSegments: [[(id: String, state: StatusState)]] = [] { didSet { @@ -24,8 +25,9 @@ class TimelineTableViewController: EnhancedTableViewController { var newer: RequestRange? var older: RequestRange? - init(for timeline: Timeline) { + init(for timeline: Timeline, mastodonController: MastodonController) { self.timeline = timeline + self.mastodonController = mastodonController super.init(style: .plain) @@ -56,13 +58,13 @@ class TimelineTableViewController: EnhancedTableViewController { tableView.prefetchDataSource = self - guard MastodonController.accessToken != nil else { return } + guard mastodonController.accessToken != nil else { return } loadInitialStatuses() } func loadInitialStatuses() { let request = Client.getStatuses(timeline: timeline) - MastodonController.run(request) { response in + mastodonController.run(request) { response in guard case let .success(statuses, pagination) = response else { fatalError() } MastodonCache.addAll(statuses: statuses) self.timelineSegments.insert(statuses.map { ($0.id, .unknown) }, at: 0) @@ -100,7 +102,7 @@ class TimelineTableViewController: EnhancedTableViewController { guard let older = older else { return } let request = Client.getStatuses(timeline: timeline, range: older) - MastodonController.run(request) { response in + mastodonController.run(request) { response in guard case let .success(newStatuses, pagination) = response else { fatalError() } self.older = pagination?.older MastodonCache.addAll(statuses: newStatuses) @@ -125,7 +127,7 @@ class TimelineTableViewController: EnhancedTableViewController { guard let newer = newer else { return } let request = Client.getStatuses(timeline: timeline, range: newer) - MastodonController.run(request) { response in + mastodonController.run(request) { response in guard case let .success(newStatuses, pagination) = response else { fatalError() } self.newer = pagination?.newer MastodonCache.addAll(statuses: newStatuses) @@ -146,6 +148,8 @@ class TimelineTableViewController: EnhancedTableViewController { } extension TimelineTableViewController: StatusTableViewCellDelegate { + var apiController: MastodonController { mastodonController } + func statusCellCollapsedStateChanged(_ cell: BaseStatusTableViewCell) { // causes the table view to recalculate the cell heights tableView.beginUpdates() diff --git a/Tusker/Screens/Timeline/TimelinesPageViewController.swift b/Tusker/Screens/Timeline/TimelinesPageViewController.swift index 7fd95c3a..a01e74db 100644 --- a/Tusker/Screens/Timeline/TimelinesPageViewController.swift +++ b/Tusker/Screens/Timeline/TimelinesPageViewController.swift @@ -14,14 +14,18 @@ class TimelinesPageViewController: SegmentedPageViewController { private let federatedTitle = NSLocalizedString("Federated", comment: "federated timeline tab title") private let localTitle = NSLocalizedString("Local", comment: "local timeline tab title") - init() { - let home = TimelineTableViewController(for: .home) + let mastodonController: MastodonController + + init(mastodonController: MastodonController) { + self.mastodonController = mastodonController + + let home = TimelineTableViewController(for: .home, mastodonController: mastodonController) home.title = homeTitle - let federated = TimelineTableViewController(for: .public(local: false)) + let federated = TimelineTableViewController(for: .public(local: false), mastodonController: mastodonController) federated.title = federatedTitle - let local = TimelineTableViewController(for: .public(local: true)) + let local = TimelineTableViewController(for: .public(local: true), mastodonController: mastodonController) local.title = localTitle super.init(titles: [ diff --git a/Tusker/Shortcuts/UserActivityManager.swift b/Tusker/Shortcuts/UserActivityManager.swift index b53373af..5701e1f9 100644 --- a/Tusker/Shortcuts/UserActivityManager.swift +++ b/Tusker/Shortcuts/UserActivityManager.swift @@ -15,6 +15,8 @@ class UserActivityManager { private static let encoder = PropertyListEncoder() private static let decoder = PropertyListDecoder() + private static var mastodonController: MastodonController { .shared } + private static func getMainTabBarController() -> MainTabBarViewController { return (UIApplication.shared.delegate! as! AppDelegate).window!.rootViewController as! MainTabBarViewController } @@ -42,7 +44,8 @@ class UserActivityManager { static func handleNewPost(activity: NSUserActivity) { // TODO: check not currently showing compose screen let mentioning = activity.userInfo?["mentioning"] as? String - present(UINavigationController(rootViewController: ComposeViewController(mentioningAcct: mentioning))) + let composeVC = ComposeViewController(mentioningAcct: mentioning, mastodonController: mastodonController) + present(UINavigationController(rootViewController: composeVC)) } // MARK: - Check Notifications @@ -144,7 +147,8 @@ class UserActivityManager { rootController.segmentedControl.selectedSegmentIndex = index rootController.selectPage(at: index, animated: false) default: - navigationController.pushViewController(TimelineTableViewController(for: timeline), animated: false) + let timeline = TimelineTableViewController(for: timeline, mastodonController: mastodonController) + navigationController.pushViewController(timeline, animated: false) } } @@ -182,7 +186,7 @@ class UserActivityManager { tabBarController.select(tab: .explore) if let navigationController = tabBarController.getTabController(tab: .explore) as? UINavigationController { navigationController.popToRootViewController(animated: false) - navigationController.pushViewController(BookmarksTableViewController(), animated: false) + navigationController.pushViewController(BookmarksTableViewController(mastodonController: mastodonController), animated: false) } } diff --git a/Tusker/TuskerNavigationDelegate.swift b/Tusker/TuskerNavigationDelegate.swift index a62072b2..2530ed17 100644 --- a/Tusker/TuskerNavigationDelegate.swift +++ b/Tusker/TuskerNavigationDelegate.swift @@ -12,6 +12,8 @@ import Pachyderm protocol TuskerNavigationDelegate { + var apiController: MastodonController { get } + func show(_ vc: UIViewController) func selected(account accountID: String) @@ -68,15 +70,15 @@ extension TuskerNavigationDelegate where Self: UIViewController { return } - show(ProfileTableViewController(accountID: accountID), sender: self) + show(ProfileTableViewController(accountID: accountID, mastodonController: apiController), sender: self) } func selected(mention: Mention) { - show(ProfileTableViewController(accountID: mention.id), sender: self) + show(ProfileTableViewController(accountID: mention.id, mastodonController: apiController), sender: self) } func selected(tag: Hashtag) { - show(HashtagTimelineViewController(for: tag), sender: self) + show(HashtagTimelineViewController(for: tag, mastodonController: apiController), sender: self) } func selected(url: URL) { @@ -113,7 +115,7 @@ extension TuskerNavigationDelegate where Self: UIViewController { return } - show(ConversationTableViewController(for: statusID, state: state), sender: self) + show(ConversationTableViewController(for: statusID, state: state, mastodonController: apiController), sender: self) } // protocols can't have parameter defaults, so this stub is necessary to fulfill the protocol req @@ -122,14 +124,14 @@ extension TuskerNavigationDelegate where Self: UIViewController { } func compose(mentioning: String? = nil) { - let compose = ComposeViewController( mentioningAcct: mentioning) + let compose = ComposeViewController(mentioningAcct: mentioning, mastodonController: apiController) let vc = UINavigationController(rootViewController: compose) vc.presentationController?.delegate = compose present(vc, animated: true) } func reply(to statusID: String) { - let compose = ComposeViewController(inReplyTo: statusID) + let compose = ComposeViewController(inReplyTo: statusID, mastodonController: apiController) let vc = UINavigationController(rootViewController: compose) vc.presentationController?.delegate = compose present(vc, animated: true) @@ -200,7 +202,7 @@ extension TuskerNavigationDelegate where Self: UIViewController { customActivites.insert(bookmarked ? UnbookmarkStatusActivity() : BookmarkStatusActivity(), at: 0) } - if status.account == MastodonController.account, + if status.account == apiController.account, let pinned = status.pinned { customActivites.insert(pinned ? UnpinStatusActivity() : PinStatusActivity(), at: 1) } @@ -228,13 +230,13 @@ extension TuskerNavigationDelegate where Self: UIViewController { } func showFollowedByList(accountIDs: [String]) { - let vc = AccountListTableViewController(accountIDs: accountIDs) + let vc = AccountListTableViewController(accountIDs: accountIDs, mastodonController: apiController) vc.title = NSLocalizedString("Followed By", comment: "followed by accounts list title") show(vc, sender: self) } func statusActionAccountList(action: StatusActionAccountListTableViewController.ActionType, statusID: String, statusState state: StatusState, accountIDs: [String]?) -> StatusActionAccountListTableViewController { - return StatusActionAccountListTableViewController(actionType: action, statusID: statusID, statusState: state, accountIDs: accountIDs) + return StatusActionAccountListTableViewController(actionType: action, statusID: statusID, statusState: state, accountIDs: accountIDs, mastodonController: apiController) } } diff --git a/Tusker/Views/Account Cell/AccountTableViewCell.swift b/Tusker/Views/Account Cell/AccountTableViewCell.swift index e933d335..cd82f5f4 100644 --- a/Tusker/Views/Account Cell/AccountTableViewCell.swift +++ b/Tusker/Views/Account Cell/AccountTableViewCell.swift @@ -11,6 +11,7 @@ import UIKit class AccountTableViewCell: UITableViewCell { var delegate: TuskerNavigationDelegate? + var mastodonController: MastodonController? { delegate?.apiController } @IBOutlet weak var avatarImageView: UIImageView! @IBOutlet weak var displayNameLabel: UILabel! @@ -68,6 +69,11 @@ 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) }) + guard let mastodonController = mastodonController else { return nil } + return (content: { + ProfileTableViewController(accountID: self.accountID, mastodonController: mastodonController) + }, actions: { + self.actionsForProfile(accountID: self.accountID) + }) } } diff --git a/Tusker/Views/ContentLabel.swift b/Tusker/Views/ContentLabel.swift index 1cdced23..b53e2d02 100644 --- a/Tusker/Views/ContentLabel.swift +++ b/Tusker/Views/ContentLabel.swift @@ -178,13 +178,15 @@ class ContentLabel: LinkLabel { func getViewController(forLink url: URL, inRange range: NSRange) -> UIViewController { let text = (self.text! as NSString).substring(with: range) - if let mention = getMention(for: url, text: text) { - return ProfileTableViewController(accountID: mention.id) - } else if let tag = getHashtag(for: url, text: text) { - return HashtagTimelineViewController(for: tag) - } else { - return SFSafariViewController(url: url) + if let navigationDelegate = navigationDelegate { + if let mention = getMention(for: url, text: text) { + return ProfileTableViewController(accountID: mention.id, mastodonController: navigationDelegate.apiController) + } else if let tag = getHashtag(for: url, text: text) { + return HashtagTimelineViewController(for: tag, mastodonController: navigationDelegate.apiController) + } + } + return SFSafariViewController(url: url) } func getViewController(forLinkAt point: CGPoint) -> UIViewController? { diff --git a/Tusker/Views/Hashtag Cell/HashtagTableViewCell.swift b/Tusker/Views/Hashtag Cell/HashtagTableViewCell.swift index 387c7652..bd364d16 100644 --- a/Tusker/Views/Hashtag Cell/HashtagTableViewCell.swift +++ b/Tusker/Views/Hashtag Cell/HashtagTableViewCell.swift @@ -12,7 +12,7 @@ import Pachyderm class HashtagTableViewCell: UITableViewCell { var delegate: TuskerNavigationDelegate? - + @IBOutlet weak var hashtagLabel: UILabel! var hashtag: Hashtag! diff --git a/Tusker/Views/Notifications/FollowNotificationGroupTableViewCell.swift b/Tusker/Views/Notifications/FollowNotificationGroupTableViewCell.swift index cafb5c13..f45025dc 100644 --- a/Tusker/Views/Notifications/FollowNotificationGroupTableViewCell.swift +++ b/Tusker/Views/Notifications/FollowNotificationGroupTableViewCell.swift @@ -12,6 +12,7 @@ import Pachyderm class FollowNotificationGroupTableViewCell: UITableViewCell { var delegate: TuskerNavigationDelegate? + var mastodonController: MastodonController? { delegate?.apiController } @IBOutlet weak var avatarStackView: UIStackView! @IBOutlet weak var timestampLabel: UILabel! @@ -133,12 +134,13 @@ extension FollowNotificationGroupTableViewCell: MenuPreviewProvider { var navigationDelegate: TuskerNavigationDelegate? { return delegate } func getPreviewProviders(for location: CGPoint, sourceViewController: UIViewController) -> PreviewProviders? { + guard let mastodonController = mastodonController else { return nil } return (content: { let accountIDs = self.group.notificationIDs.compactMap(MastodonCache.notification(for:)).map { $0.account.id } if accountIDs.count == 1 { - return ProfileTableViewController(accountID: accountIDs.first!) + return ProfileTableViewController(accountID: accountIDs.first!, mastodonController: mastodonController) } else { - return AccountListTableViewController(accountIDs: accountIDs) + return AccountListTableViewController(accountIDs: accountIDs, mastodonController: mastodonController) } }, actions: { return [] diff --git a/Tusker/Views/Notifications/FollowRequestNotificationTableViewCell.swift b/Tusker/Views/Notifications/FollowRequestNotificationTableViewCell.swift index 8a5ca23f..b8865507 100644 --- a/Tusker/Views/Notifications/FollowRequestNotificationTableViewCell.swift +++ b/Tusker/Views/Notifications/FollowRequestNotificationTableViewCell.swift @@ -12,6 +12,7 @@ import Pachyderm class FollowRequestNotificationTableViewCell: UITableViewCell { var delegate: TuskerNavigationDelegate? + var mastodonController: MastodonController? { delegate?.apiController } @IBOutlet weak var stackView: UIStackView! @IBOutlet weak var avatarImageView: UIImageView! @@ -89,7 +90,7 @@ class FollowRequestNotificationTableViewCell: UITableViewCell { @IBAction func rejectButtonPressed() { let request = Account.rejectFollowRequest(account) - MastodonController.run(request) { (response) in + mastodonController!.run(request) { (response) in guard case let .success(relationship, _) = response else { fatalError() } MastodonCache.add(relationship: relationship) DispatchQueue.main.async { @@ -106,7 +107,7 @@ class FollowRequestNotificationTableViewCell: UITableViewCell { @IBAction func acceptButtonPressed() { let request = Account.authorizeFollowRequest(account) - MastodonController.run(request) { (response) in + mastodonController!.run(request) { (response) in guard case let .success(relationship, _) = response else { fatalError() } MastodonCache.add(relationship: relationship) DispatchQueue.main.async { @@ -133,8 +134,9 @@ extension FollowRequestNotificationTableViewCell: MenuPreviewProvider { var navigationDelegate: TuskerNavigationDelegate? { return delegate } func getPreviewProviders(for location: CGPoint, sourceViewController: UIViewController) -> PreviewProviders? { + guard let mastodonController = mastodonController else { return nil } return (content: { - return ProfileTableViewController(accountID: self.account.id) + return ProfileTableViewController(accountID: self.account.id, mastodonController: mastodonController) }, actions: { return [] }) diff --git a/Tusker/Views/Profile Header/ProfileHeaderTableViewCell.swift b/Tusker/Views/Profile Header/ProfileHeaderTableViewCell.swift index a3517792..c948f666 100644 --- a/Tusker/Views/Profile Header/ProfileHeaderTableViewCell.swift +++ b/Tusker/Views/Profile Header/ProfileHeaderTableViewCell.swift @@ -16,6 +16,7 @@ protocol ProfileHeaderTableViewCellDelegate: TuskerNavigationDelegate { class ProfileHeaderTableViewCell: UITableViewCell { var delegate: ProfileHeaderTableViewCellDelegate? + var mastodonController: MastodonController? { delegate?.apiController } @IBOutlet weak var headerImageView: UIImageView! @IBOutlet weak var avatarContainerView: UIView! @@ -82,7 +83,7 @@ class ProfileHeaderTableViewCell: UITableViewCell { noteLabel.setTextFromHtml(account.note) noteLabel.setEmojis(account.emojis) - if accountID != MastodonController.account.id { + if accountID != mastodonController!.account.id { // don't show relationship label for the user's own account if let relationship = MastodonCache.relationship(for: accountID) { followsYouLabel.isHidden = !relationship.followedBy diff --git a/Tusker/Views/Status/BaseStatusTableViewCell.swift b/Tusker/Views/Status/BaseStatusTableViewCell.swift index f6b062e1..f9b985c5 100644 --- a/Tusker/Views/Status/BaseStatusTableViewCell.swift +++ b/Tusker/Views/Status/BaseStatusTableViewCell.swift @@ -15,11 +15,13 @@ protocol StatusTableViewCellDelegate: TuskerNavigationDelegate { } class BaseStatusTableViewCell: UITableViewCell { + var delegate: StatusTableViewCellDelegate? { didSet { contentLabel.navigationDelegate = delegate } } + var mastodonController: MastodonController? { delegate?.apiController } @IBOutlet weak var avatarImageView: UIImageView! @IBOutlet weak var displayNameLabel: UILabel! @@ -247,7 +249,7 @@ class BaseStatusTableViewCell: UITableViewCell { let realStatus: Status = status.reblog ?? status let request = (favorited ? Status.favourite : Status.unfavourite)(realStatus) - MastodonController.run(request) { response in + mastodonController!.run(request) { response in DispatchQueue.main.async { if case let .success(newStatus, _) = response { self.favorited = newStatus.favourited ?? false @@ -272,7 +274,7 @@ class BaseStatusTableViewCell: UITableViewCell { let realStatus: Status = status.reblog ?? status let request = (reblogged ? Status.reblog : Status.unreblog)(realStatus) - MastodonController.run(request) { response in + mastodonController!.run(request) { response in DispatchQueue.main.async { if case let .success(newStatus, _) = response { self.reblogged = newStatus.reblogged ?? false @@ -313,8 +315,13 @@ extension BaseStatusTableViewCell: MenuPreviewProvider { var navigationDelegate: TuskerNavigationDelegate? { return delegate } func getPreviewProviders(for location: CGPoint, sourceViewController: UIViewController) -> PreviewProviders? { + guard let mastodonController = mastodonController else { return nil } if avatarImageView.frame.contains(location) { - return (content: { ProfileTableViewController(accountID: self.accountID)}, actions: { self.actionsForProfile(accountID: self.accountID) }) + return (content: { + ProfileTableViewController(accountID: self.accountID, mastodonController: mastodonController) + }, actions: { + self.actionsForProfile(accountID: self.accountID) + }) } else if attachmentsView.frame.contains(location) { let attachmentsViewLocation = attachmentsView.convert(location, from: self) if let attachmentView = attachmentsView.attachmentViews.allObjects.first(where: { $0.frame.contains(attachmentsViewLocation) }), diff --git a/Tusker/Views/Status/TimelineStatusTableViewCell.swift b/Tusker/Views/Status/TimelineStatusTableViewCell.swift index a80e4254..a42ddeb2 100644 --- a/Tusker/Views/Status/TimelineStatusTableViewCell.swift +++ b/Tusker/Views/Status/TimelineStatusTableViewCell.swift @@ -125,8 +125,9 @@ class TimelineStatusTableViewCell: BaseStatusTableViewCell { } override func getStatusCellPreviewProviders(for location: CGPoint, sourceViewController: UIViewController) -> BaseStatusTableViewCell.PreviewProviders? { + guard let mastodonController = mastodonController else { return nil } return ( - content: { ConversationTableViewController(for: self.statusID, state: self.statusState.copy()) }, + content: { ConversationTableViewController(for: self.statusID, state: self.statusState.copy(), mastodonController: mastodonController) }, actions: { self.actionsForStatus(statusID: self.statusID) } ) } @@ -142,6 +143,7 @@ extension TimelineStatusTableViewCell: SelectableTableViewCell { extension TimelineStatusTableViewCell: TableViewSwipeActionProvider { func leadingSwipeActionsConfiguration() -> UISwipeActionsConfiguration? { + guard let mastodonController = mastodonController else { return nil } guard let status = MastodonCache.status(for: statusID) else { fatalError("Missing cached status \(statusID!)") } let favoriteTitle: String @@ -158,7 +160,7 @@ extension TimelineStatusTableViewCell: TableViewSwipeActionProvider { favoriteColor = UIColor(displayP3Red: 1, green: 204/255, blue: 0, alpha: 1) } let favorite = UIContextualAction(style: .normal, title: favoriteTitle) { (action, view, completion) in - MastodonController.run(favoriteRequest, completion: { response in + mastodonController.run(favoriteRequest, completion: { response in DispatchQueue.main.async { guard case let .success(status, _) = response else { completion(false) @@ -185,7 +187,7 @@ extension TimelineStatusTableViewCell: TableViewSwipeActionProvider { reblogColor = tintColor } let reblog = UIContextualAction(style: .normal, title: reblogTitle) { (action, view, completion) in - MastodonController.run(reblogRequest, completion: { response in + mastodonController.run(reblogRequest, completion: { response in DispatchQueue.main.async { guard case let .success(status, _) = response else { completion(false) diff --git a/Tusker/XCallbackURL/XCBActions.swift b/Tusker/XCallbackURL/XCBActions.swift index d90d1920..ead66b93 100644 --- a/Tusker/XCallbackURL/XCBActions.swift +++ b/Tusker/XCallbackURL/XCBActions.swift @@ -13,6 +13,8 @@ import SwiftSoup struct XCBActions { // MARK: - Utils + private static var mastodonController: MastodonController { .shared } + private static func getMainTabBarController() -> MainTabBarViewController { return (UIApplication.shared.delegate as! AppDelegate).window!.rootViewController as! MainTabBarViewController } @@ -42,7 +44,7 @@ struct XCBActions { } } else if let searchQuery = request.arguments["statusURL"] { let request = Client.search(query: searchQuery) - MastodonController.run(request) { (response) in + mastodonController.run(request) { (response) in if case let .success(results, _) = response, let status = results.statuses.first { MastodonCache.add(status: status) @@ -73,7 +75,7 @@ struct XCBActions { } } else if let searchQuery = request.arguments["accountURL"] { let request = Client.search(query: searchQuery) - MastodonController.run(request) { (response) in + mastodonController.run(request) { (response) in if case let .success(results, _) = response { if let account = results.accounts.first { MastodonCache.add(account: account) @@ -91,7 +93,7 @@ struct XCBActions { } } else if let acct = request.arguments["acct"] { let request = Client.searchForAccount(query: acct) - MastodonController.run(request) { (response) in + mastodonController.run(request) { (response) in if case let .success(accounts, _) = response { if let account = accounts.first { MastodonCache.add(account: account) @@ -118,7 +120,7 @@ struct XCBActions { static func showStatus(_ request: XCBRequest, _ session: XCBSession, _ silent: Bool?) { getStatus(from: request, session: session) { (status) in DispatchQueue.main.async { - let vc = ConversationTableViewController(for: status.id) + let vc = ConversationTableViewController(for: status.id, mastodonController: mastodonController) show(vc) } } @@ -132,14 +134,14 @@ struct XCBActions { var status = "" if let mentioning = mentioning { status += mentioning } if let text = text { status += text } - guard CharacterCounter.count(text: status) <= MastodonController.instance.maxStatusCharacters ?? 500 else { + guard CharacterCounter.count(text: status) <= mastodonController.instance.maxStatusCharacters ?? 500 else { session.complete(with: .error, additionalData: [ - "error": "Too many characters. Instance maximum is \(MastodonController.instance.maxStatusCharacters ?? 500)" + "error": "Too many characters. Instance maximum is \(mastodonController.instance.maxStatusCharacters ?? 500)" ]) return } let request = Client.createStatus(text: status, visibility: Preferences.shared.defaultPostVisibility) - MastodonController.run(request) { response in + mastodonController.run(request) { response in if case let .success(status, _) = response { session.complete(with: .success, additionalData: [ "statusURL": status.url?.absoluteString, @@ -152,7 +154,7 @@ struct XCBActions { } } } else { - let compose = ComposeViewController(mentioningAcct: mentioning, text: text) + let compose = ComposeViewController(mentioningAcct: mentioning, text: text, mastodonController: mastodonController) compose.xcbSession = session let vc = UINavigationController(rootViewController: compose) present(vc) @@ -199,7 +201,7 @@ struct XCBActions { static func statusAction(request: @escaping (Status) -> Request, alertTitle: String, _ url: XCBRequest, _ session: XCBSession, _ silent: Bool?) { func performAction(status: Status, completion: ((Status) -> Void)?) { - MastodonController.run(request(status)) { (response) in + mastodonController.run(request(status)) { (response) in if case let .success(status, _) = response { MastodonCache.add(status: status) completion?(status) @@ -219,7 +221,7 @@ struct XCBActions { if silent ?? false { performAction(status: status, completion: nil) } else { - let vc = ConversationTableViewController(for: status.id) + let vc = ConversationTableViewController(for: status.id, mastodonController: mastodonController) DispatchQueue.main.async { show(vc) } @@ -247,7 +249,7 @@ struct XCBActions { static func showAccount(_ request: XCBRequest, _ session: XCBSession, _ silent: Bool?) { getAccount(from: request, session: session) { (account) in DispatchQueue.main.async { - let vc = ProfileTableViewController(accountID: account.id) + let vc = ProfileTableViewController(accountID: account.id, mastodonController: mastodonController) show(vc) } } @@ -269,7 +271,7 @@ struct XCBActions { } static func getCurrentUser(_ request: XCBRequest, _ session: XCBSession, _ silent: Bool?) { - let account = MastodonController.account! + let account = mastodonController.account! session.complete(with: .success, additionalData: [ "username": account.acct, "displayName": account.displayName, @@ -285,7 +287,7 @@ struct XCBActions { static func followUser(_ request: XCBRequest, _ session: XCBSession, _ silent: Bool?) { func performAction(_ account: Account) { let request = Account.follow(account.id) - MastodonController.run(request) { (response) in + mastodonController.run(request) { (response) in if case let .success(relationship, _) = response { MastodonCache.add(relationship: relationship) session.complete(with: .success, additionalData: [ @@ -303,7 +305,7 @@ struct XCBActions { if silent ?? false { performAction(account) } else { - let vc = ProfileTableViewController(accountID: account.id) + let vc = ProfileTableViewController(accountID: account.id, mastodonController: mastodonController) DispatchQueue.main.async { show(vc) }