From 3928b2e88acc3061d3ff0d9e8d6e23047ec7ac81 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Tue, 7 Jan 2020 21:29:15 -0500 Subject: [PATCH] Store an array of logged-in accounts internally, get the active MastodonController from the current UIScene See #16 --- Tusker.xcodeproj/project.pbxproj | 8 ++ Tusker/Activities/MastodonActivity.swift | 3 +- Tusker/Controllers/MastodonController.swift | 66 ++++++---- Tusker/Extensions/UIApplication+Scenes.swift | 25 ++++ .../UISceneSession+MastodonController.swift | 32 +++++ Tusker/LocalData.swift | 120 +++++++++++------- Tusker/SceneDelegate.swift | 15 ++- .../Onboarding/OnboardingViewController.swift | 25 ++-- .../PreferencesNavigationController.swift | 5 +- .../Screens/Preferences/PreferencesView.swift | 10 +- .../MyProfileTableViewController.swift | 2 +- .../InstanceTimelineViewController.swift | 5 +- Tusker/Shortcuts/UserActivityManager.swift | 5 +- Tusker/XCallbackURL/XCBActions.swift | 6 +- 14 files changed, 225 insertions(+), 102 deletions(-) create mode 100644 Tusker/Extensions/UIApplication+Scenes.swift create mode 100644 Tusker/Extensions/UISceneSession+MastodonController.swift diff --git a/Tusker.xcodeproj/project.pbxproj b/Tusker.xcodeproj/project.pbxproj index adf1defc..7fe41973 100644 --- a/Tusker.xcodeproj/project.pbxproj +++ b/Tusker.xcodeproj/project.pbxproj @@ -217,6 +217,8 @@ D6E0DC8E216EDF1E00369478 /* Previewing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E0DC8D216EDF1E00369478 /* Previewing.swift */; }; D6E6F26321603F8B006A8599 /* CharacterCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E6F26221603F8B006A8599 /* CharacterCounter.swift */; }; D6E6F26521604242006A8599 /* CharacterCounterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E6F26421604242006A8599 /* CharacterCounterTests.swift */; }; + D6EBF01523C55C0900AE061B /* UIApplication+Scenes.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6EBF01423C55C0900AE061B /* UIApplication+Scenes.swift */; }; + D6EBF01723C55E0D00AE061B /* UISceneSession+MastodonController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6EBF01623C55E0D00AE061B /* UISceneSession+MastodonController.swift */; }; D6F1F84D2193B56E00F5FE67 /* Cache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F1F84C2193B56E00F5FE67 /* Cache.swift */; }; D6F953EC212519E700CF0F2B /* TimelineTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F953EB212519E700CF0F2B /* TimelineTableViewController.swift */; }; D6F953F021251A2900CF0F2B /* MastodonController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F953EF21251A2900CF0F2B /* MastodonController.swift */; }; @@ -494,6 +496,8 @@ D6E0DC8D216EDF1E00369478 /* Previewing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Previewing.swift; sourceTree = ""; }; D6E6F26221603F8B006A8599 /* CharacterCounter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterCounter.swift; sourceTree = ""; }; D6E6F26421604242006A8599 /* CharacterCounterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterCounterTests.swift; sourceTree = ""; }; + D6EBF01423C55C0900AE061B /* UIApplication+Scenes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+Scenes.swift"; sourceTree = ""; }; + D6EBF01623C55E0D00AE061B /* UISceneSession+MastodonController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UISceneSession+MastodonController.swift"; sourceTree = ""; }; D6F1F84C2193B56E00F5FE67 /* Cache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cache.swift; sourceTree = ""; }; D6F953EB212519E700CF0F2B /* TimelineTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineTableViewController.swift; sourceTree = ""; }; D6F953EF21251A2900CF0F2B /* MastodonController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonController.swift; sourceTree = ""; }; @@ -966,6 +970,8 @@ D67C57AE21E28EAD00C3118B /* Array+Uniques.swift */, 0450531E22B0097E00100BA2 /* Timline+UI.swift */, D66A77BA233838DC0058F1EC /* UIFont+Traits.swift */, + D6EBF01423C55C0900AE061B /* UIApplication+Scenes.swift */, + D6EBF01623C55E0D00AE061B /* UISceneSession+MastodonController.swift */, ); path = Extensions; sourceTree = ""; @@ -1620,6 +1626,7 @@ 0427033A22B31269000D31B6 /* AdvancedPrefsView.swift in Sources */, D626493C23C1000300612E6E /* AlbumTableViewCell.swift in Sources */, D6757A822157E8FA00721E32 /* XCBSession.swift in Sources */, + D6EBF01723C55E0D00AE061B /* UISceneSession+MastodonController.swift in Sources */, 04DACE8C212CB14B009840C4 /* MainTabBarViewController.swift in Sources */, D6AEBB412321642700E5038B /* SendMesasgeActivity.swift in Sources */, D6BC9DB1232C61BC002CA326 /* NotificationsPageViewController.swift in Sources */, @@ -1680,6 +1687,7 @@ D64BC19223C271D9000D0238 /* MastodonActivity.swift in Sources */, D6945C3A23AC75E2005C403C /* FindInstanceViewController.swift in Sources */, D6AEBB4523216AF800E5038B /* FollowAccountActivity.swift in Sources */, + D6EBF01523C55C0900AE061B /* UIApplication+Scenes.swift in Sources */, D6538945214D6D7500E3CEFC /* TableViewSwipeActionProvider.swift in Sources */, D6E0DC8E216EDF1E00369478 /* Previewing.swift in Sources */, D6BED174212667E900F02DA0 /* TimelineStatusTableViewCell.swift in Sources */, diff --git a/Tusker/Activities/MastodonActivity.swift b/Tusker/Activities/MastodonActivity.swift index 32275951..25fd5cc7 100644 --- a/Tusker/Activities/MastodonActivity.swift +++ b/Tusker/Activities/MastodonActivity.swift @@ -10,6 +10,7 @@ import UIKit class MastodonActivity: UIActivity { var mastodonController: MastodonController { - MastodonController.shared + let scene = UIApplication.shared.activeOrBackgroundScene! + return scene.session.mastodonController! } } diff --git a/Tusker/Controllers/MastodonController.swift b/Tusker/Controllers/MastodonController.swift index 59aa82a6..5e2ae194 100644 --- a/Tusker/Controllers/MastodonController.swift +++ b/Tusker/Controllers/MastodonController.swift @@ -10,55 +10,67 @@ import Foundation import Pachyderm class MastodonController { + + static private(set) var all = [LocalData.UserAccountInfo: MastodonController]() - @available(*, deprecated, message: "Use dependency injection to obtain an instance") - static let shared = MastodonController() + @available(*, message: "do something less dumb") + static var first: MastodonController { all.first!.value } + + static func getForAccount(_ account: LocalData.UserAccountInfo) -> MastodonController { + if let controller = all[account] { + return controller + } else { + let controller = MastodonController(instanceURL: account.instanceURL) + controller.accountInfo = account + controller.client.clientID = account.clientID + controller.client.clientSecret = account.clientSecret + controller.client.accessToken = account.accessToken + all[account] = controller + return controller + } + } private(set) lazy var cache = MastodonCache(mastodonController: self) - private var client: Client! + let instanceURL: URL + private(set) var accountInfo: LocalData.UserAccountInfo? + + let client: Client! var account: Account! var instance: Instance! - - var accessToken: String? { - client?.accessToken - } - - func createClient(instanceURL: URL = LocalData.shared.instanceURL!) { - client = Client(baseURL: instanceURL) - - if instanceURL == LocalData.shared.instanceURL { - client.clientID = LocalData.shared.clientID - client.clientSecret = LocalData.shared.clientSecret - client.accessToken = LocalData.shared.accessToken - } + + init(instanceURL: URL) { + self.instanceURL = instanceURL + self.accountInfo = nil + self.client = Client(baseURL: instanceURL) } func run(_ request: Request, completion: @escaping Client.Callback) { client.run(request, completion: completion) } - func registerApp(completion: @escaping () -> Void) { - guard LocalData.shared.clientID == nil, - LocalData.shared.clientSecret == nil else { - completion() + func registerApp(completion: @escaping (_ clientID: String, _ clientSecret: String) -> Void) { + guard client.clientID == nil, + client.clientSecret == nil else { + + completion(client.clientID!, client.clientSecret!) return } - + client.registerApp(name: "Tusker", redirectURI: "tusker://oauth", scopes: [.read, .write, .follow]) { response in guard case let .success(app, _) = response else { fatalError() } - LocalData.shared.clientID = app.clientID - LocalData.shared.clientSecret = app.clientSecret - completion() + self.client.clientID = app.clientID + self.client.clientSecret = app.clientSecret + completion(app.clientID, app.clientSecret) } } - func authorize(authorizationCode: String, completion: @escaping () -> Void) { + func authorize(authorizationCode: String, completion: @escaping (_ accessToken: String) -> Void) { client.getAccessToken(authorizationCode: authorizationCode, redirectURI: "tusker://oauth") { response in guard case let .success(settings, _) = response else { fatalError() } - LocalData.shared.accessToken = settings.accessToken - completion() + self.client.accessToken = settings.accessToken + completion(settings.accessToken) } } diff --git a/Tusker/Extensions/UIApplication+Scenes.swift b/Tusker/Extensions/UIApplication+Scenes.swift new file mode 100644 index 00000000..ce5ab857 --- /dev/null +++ b/Tusker/Extensions/UIApplication+Scenes.swift @@ -0,0 +1,25 @@ +// +// UIApplication+Scenes.swift +// Tusker +// +// Created by Shadowfacts on 1/7/20. +// Copyright © 2020 Shadowfacts. All rights reserved. +// + +import UIKit + +extension UIApplication { + + var activeScene: UIScene? { + connectedScenes.first { $0.activationState == .foregroundActive } + } + + var backgroundScene: UIScene? { + connectedScenes.first { $0.activationState == .background } + } + + var activeOrBackgroundScene: UIScene? { + activeScene ?? backgroundScene + } + +} diff --git a/Tusker/Extensions/UISceneSession+MastodonController.swift b/Tusker/Extensions/UISceneSession+MastodonController.swift new file mode 100644 index 00000000..efa4e638 --- /dev/null +++ b/Tusker/Extensions/UISceneSession+MastodonController.swift @@ -0,0 +1,32 @@ +// +// UISceneSession+MastodonController.swift +// Tusker +// +// Created by Shadowfacts on 1/7/20. +// Copyright © 2020 Shadowfacts. All rights reserved. +// + +import UIKit + +extension UISceneSession { + + var mastodonController: MastodonController? { + get { + return userInfo?["mastodonController"] as? MastodonController + } + set { + if let newValue = newValue { + if userInfo == nil { + userInfo = ["mastodonController": newValue] + } else { + userInfo!["mastodonController"] = newValue + } + } else { + if userInfo != nil { + userInfo?.removeValue(forKey: "mastodonController") + } + } + } + } + +} diff --git a/Tusker/LocalData.swift b/Tusker/LocalData.swift index f8ce0b10..6dad3f5b 100644 --- a/Tusker/LocalData.swift +++ b/Tusker/LocalData.swift @@ -18,65 +18,99 @@ class LocalData { if ProcessInfo.processInfo.environment.keys.contains("UI_TESTING") { defaults = UserDefaults(suiteName: "\(Bundle.main.bundleIdentifier!).uitesting")! if ProcessInfo.processInfo.environment.keys.contains("UI_TESTING_LOGIN") { - defaults.set(true, forKey: onboardingCompleteKey) - defaults.set(URL(string: "http://localhost:8080")!, forKey: instanceURLKey) - defaults.set("client_id", forKey: clientIDKey) - defaults.set("client_secret", forKey: clientSecretKey) - defaults.set("access_token", forKey: accessTokenKey) + accounts = [ + UserAccountInfo( + instanceURL: URL(string: "http://localhost:8080")!, + clientID: "client_id", + clientSecret: "client_secret", + username: "admin", + accessToken: "access_token") + ] } } else { defaults = UserDefaults() } } - private let onboardingCompleteKey = "onboardingComplete" + private let accountsKey = "accounts" + var accounts: [UserAccountInfo] { + get { + if let array = defaults.array(forKey: accountsKey) as? [[String: String]] { + return array.compactMap { (info) in + guard let instanceURL = info["instanceURL"], + let url = URL(string: instanceURL), + let id = info["clientID"], + let secret = info["clientSecret"], + let username = info["username"], + let accessToken = info["accessToken"] else { + return nil + } + return UserAccountInfo(instanceURL: url, clientID: id, clientSecret: secret, username: username, accessToken: accessToken) + } + } else { + return [] + } + } + set { + let array = newValue.map { (info) in + return [ + "instanceURL": info.instanceURL.absoluteString, + "clientID": info.clientID, + "clientSecret": info.clientSecret, + "username": info.username, + "accessToken": info.accessToken + ] + } + defaults.set(array, forKey: accountsKey) + } + } + + private let mostRecentAccountKey = "mostRecentAccount" + var mostRecentAccount: String? { + get { + return defaults.string(forKey: mostRecentAccountKey) + } + set { + defaults.set(newValue, forKey: mostRecentAccountKey) + } + } + var onboardingComplete: Bool { - get { - return defaults.bool(forKey: onboardingCompleteKey) - } - set { - defaults.set(newValue, forKey: onboardingCompleteKey) - } + return !accounts.isEmpty } - private let instanceURLKey = "instanceURL" - var instanceURL: URL? { - get { - return defaults.url(forKey: instanceURLKey) - } - set { - defaults.set(newValue, forKey: instanceURLKey) + func addAccount(instanceURL url: URL, clientID id: String, clientSecret secret: String, username: String, accessToken: String) -> UserAccountInfo { + var accounts = self.accounts + if let index = accounts.firstIndex(where: { $0.instanceURL == url && $0.username == username }) { + accounts.remove(at: index) } + let info = UserAccountInfo(instanceURL: url, clientID: id, clientSecret: secret, username: username, accessToken: accessToken) + accounts.append(info) + self.accounts = accounts + return info } - private let clientIDKey = "clientID" - var clientID: String? { - get { - return defaults.string(forKey: clientIDKey) - } - set { - defaults.set(newValue, forKey: clientIDKey) - } + func removeAccount(_ info: UserAccountInfo) { + } - private let clientSecretKey = "clientSecret" - var clientSecret: String? { - get { - return defaults.string(forKey: clientSecretKey) - } - set { - defaults.set(newValue, forKey: clientSecretKey) + func getMostRecentAccount() -> UserAccountInfo? { + if let accessToken = mostRecentAccount { + return accounts.first { $0.accessToken == accessToken } + } else { + return nil } } - - private let accessTokenKey = "accessToken" - var accessToken: String? { - get { - return defaults.string(forKey: accessTokenKey) - } - set { - defaults.set(newValue, forKey: accessTokenKey) - } + +} + +extension LocalData { + struct UserAccountInfo: Equatable, Hashable { + let instanceURL: URL + let clientID: String + let clientSecret: String + let username: String + let accessToken: String } } diff --git a/Tusker/SceneDelegate.swift b/Tusker/SceneDelegate.swift index 5e3d7ac2..67c8c152 100644 --- a/Tusker/SceneDelegate.swift +++ b/Tusker/SceneDelegate.swift @@ -7,12 +7,13 @@ // import UIKit +import Pachyderm class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? - let mastodonController = MastodonController.shared +// let mastodonController = MastodonController.shared func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. @@ -23,6 +24,11 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { window = UIWindow(windowScene: windowScene) if LocalData.shared.onboardingComplete { + if session.mastodonController == nil { + let account = LocalData.shared.getMostRecentAccount()! + session.mastodonController = MastodonController.getForAccount(account) + } + showAppUI() } else { showOnboardingUI() @@ -106,7 +112,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } func showAppUI() { - mastodonController.createClient() + let mastodonController = window!.windowScene!.session.mastodonController! mastodonController.getOwnAccount() mastodonController.getOwnInstance() @@ -131,8 +137,9 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } extension SceneDelegate: OnboardingViewControllerDelegate { - func didFinishOnboarding() { - LocalData.shared.onboardingComplete = true + func didFinishOnboarding(account: LocalData.UserAccountInfo) { + LocalData.shared.mostRecentAccount = account.accessToken + window!.windowScene!.session.mastodonController = MastodonController.getForAccount(account) showAppUI() } } diff --git a/Tusker/Screens/Onboarding/OnboardingViewController.swift b/Tusker/Screens/Onboarding/OnboardingViewController.swift index 21daac5e..e799e2a6 100644 --- a/Tusker/Screens/Onboarding/OnboardingViewController.swift +++ b/Tusker/Screens/Onboarding/OnboardingViewController.swift @@ -10,7 +10,7 @@ import UIKit import AuthenticationServices protocol OnboardingViewControllerDelegate { - func didFinishOnboarding() + func didFinishOnboarding(account: LocalData.UserAccountInfo) } class OnboardingViewController: UINavigationController { @@ -44,16 +44,13 @@ class OnboardingViewController: UINavigationController { } extension OnboardingViewController: InstanceSelectorTableViewControllerDelegate { - func didSelectInstance(url: URL) { - LocalData.shared.instanceURL = url - let mastodonController = MastodonController.shared - mastodonController.createClient() - mastodonController.registerApp { - let clientID = LocalData.shared.clientID! - + func didSelectInstance(url instanceURL: URL) { + let mastodonController = MastodonController(instanceURL: instanceURL) + mastodonController.registerApp { (clientID, clientSecret) in + let callbackURL = "tusker://oauth" - var components = URLComponents(url: url, resolvingAgainstBaseURL: false)! + var components = URLComponents(url: instanceURL, resolvingAgainstBaseURL: false)! components.path = "/oauth/authorize" components.queryItems = [ URLQueryItem(name: "client_id", value: clientID), @@ -70,9 +67,13 @@ extension OnboardingViewController: InstanceSelectorTableViewControllerDelegate let item = components.queryItems?.first(where: { $0.name == "code" }), let authCode = item.value else { return } - mastodonController.authorize(authorizationCode: authCode) { - DispatchQueue.main.async { - self.onboardingDelegate?.didFinishOnboarding() + mastodonController.authorize(authorizationCode: authCode) { (accessToken) in + mastodonController.getOwnAccount { (account) in + let accountInfo = LocalData.shared.addAccount(instanceURL: instanceURL, clientID: clientID, clientSecret: clientSecret, username: account.username, accessToken: accessToken) + + DispatchQueue.main.async { + self.onboardingDelegate?.didFinishOnboarding(account: accountInfo) + } } } } diff --git a/Tusker/Screens/Preferences/PreferencesNavigationController.swift b/Tusker/Screens/Preferences/PreferencesNavigationController.swift index 0ac49c04..db3a9349 100644 --- a/Tusker/Screens/Preferences/PreferencesNavigationController.swift +++ b/Tusker/Screens/Preferences/PreferencesNavigationController.swift @@ -11,8 +11,9 @@ import SwiftUI class PreferencesNavigationController: UINavigationController { - init() { - let hostingController = UIHostingController(rootView: PreferencesView()) + init(mastodonController: MastodonController) { + let view = PreferencesView(currentAccount: mastodonController.accountInfo!) + let hostingController = UIHostingController(rootView: view) super.init(rootViewController: hostingController) hostingController.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(donePressed)) } diff --git a/Tusker/Screens/Preferences/PreferencesView.swift b/Tusker/Screens/Preferences/PreferencesView.swift index 9df96be2..8f2078fa 100644 --- a/Tusker/Screens/Preferences/PreferencesView.swift +++ b/Tusker/Screens/Preferences/PreferencesView.swift @@ -8,6 +8,7 @@ import SwiftUI struct PreferencesView : View { + var currentAccount: LocalData.UserAccountInfo @State private var showingLogoutConfirmation = false var body: some View { @@ -49,11 +50,7 @@ struct PreferencesView : View { } func logoutPressed() { - LocalData.shared.onboardingComplete = false - LocalData.shared.instanceURL = nil - LocalData.shared.clientID = nil - LocalData.shared.clientSecret = nil - LocalData.shared.accessToken = nil + LocalData.shared.removeAccount(currentAccount) NotificationCenter.default.post(name: .userLoggedOut, object: nil) } } @@ -61,7 +58,8 @@ struct PreferencesView : View { #if DEBUG struct PreferencesView_Previews : PreviewProvider { static var previews: some View { - PreferencesView() + let account = LocalData.UserAccountInfo(instanceURL: URL(string: "https://mastodon.social")!, clientID: "clientID", clientSecret: "clientSecret", username: "example", accessToken: "accessToken") + return PreferencesView(currentAccount: account) } } #endif diff --git a/Tusker/Screens/Profile/MyProfileTableViewController.swift b/Tusker/Screens/Profile/MyProfileTableViewController.swift index 7fef8706..09ac7884 100644 --- a/Tusker/Screens/Profile/MyProfileTableViewController.swift +++ b/Tusker/Screens/Profile/MyProfileTableViewController.swift @@ -50,7 +50,7 @@ class MyProfileTableViewController: ProfileTableViewController { } @objc func preferencesPressed() { - present(PreferencesNavigationController(), animated: true) + present(PreferencesNavigationController(mastodonController: mastodonController), animated: true) } @objc func closePreferences() { diff --git a/Tusker/Screens/Timeline/InstanceTimelineViewController.swift b/Tusker/Screens/Timeline/InstanceTimelineViewController.swift index df598ab8..ff809ba7 100644 --- a/Tusker/Screens/Timeline/InstanceTimelineViewController.swift +++ b/Tusker/Screens/Timeline/InstanceTimelineViewController.swift @@ -31,9 +31,8 @@ class InstanceTimelineViewController: TimelineTableViewController { init(for url: URL) { self.instanceURL = url - let mastodonController = MastodonController() - mastodonController.createClient(instanceURL: url) - + let mastodonController = MastodonController(instanceURL: url) + super.init(for: .instance(instanceURL: url), mastodonController: mastodonController) } diff --git a/Tusker/Shortcuts/UserActivityManager.swift b/Tusker/Shortcuts/UserActivityManager.swift index 4b745f40..4c181663 100644 --- a/Tusker/Shortcuts/UserActivityManager.swift +++ b/Tusker/Shortcuts/UserActivityManager.swift @@ -15,7 +15,10 @@ class UserActivityManager { private static let encoder = PropertyListEncoder() private static let decoder = PropertyListDecoder() - private static var mastodonController: MastodonController { .shared } + private static var mastodonController: MastodonController { + let scene = UIApplication.shared.activeOrBackgroundScene! + return scene.session.mastodonController! + } private static func getMainTabBarController() -> MainTabBarViewController { let scene = UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }.first! diff --git a/Tusker/XCallbackURL/XCBActions.swift b/Tusker/XCallbackURL/XCBActions.swift index ad2feb5f..0731fd06 100644 --- a/Tusker/XCallbackURL/XCBActions.swift +++ b/Tusker/XCallbackURL/XCBActions.swift @@ -13,13 +13,15 @@ import SwiftSoup struct XCBActions { // MARK: - Utils - private static var mastodonController: MastodonController { .shared } + private static var mastodonController: MastodonController { + let scene = UIApplication.shared.activeOrBackgroundScene! + return scene.session.mastodonController! + } private static func getMainTabBarController() -> MainTabBarViewController { let scene = UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }.first! let window = scene.windows.first { $0.isKeyWindow }! return window.rootViewController as! MainTabBarViewController -// return (UIApplication.shared.delegate as! AppDelegate).window!.rootViewController as! MainTabBarViewController } private static func show(_ vc: UIViewController) {