diff --git a/Packages/ComposeUI/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/Packages/ComposeUI/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 00000000..919434a6
--- /dev/null
+++ b/Packages/ComposeUI/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/Packages/UserAccounts/.gitignore b/Packages/UserAccounts/.gitignore
new file mode 100644
index 00000000..3b298120
--- /dev/null
+++ b/Packages/UserAccounts/.gitignore
@@ -0,0 +1,9 @@
+.DS_Store
+/.build
+/Packages
+/*.xcodeproj
+xcuserdata/
+DerivedData/
+.swiftpm/config/registries.json
+.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
+.netrc
diff --git a/Packages/UserAccounts/Package.resolved b/Packages/UserAccounts/Package.resolved
new file mode 100644
index 00000000..a9ae5ab1
--- /dev/null
+++ b/Packages/UserAccounts/Package.resolved
@@ -0,0 +1,23 @@
+{
+ "pins" : [
+ {
+ "identity" : "swift-system",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/apple/swift-system.git",
+ "state" : {
+ "revision" : "025bcb1165deab2e20d4eaba79967ce73013f496",
+ "version" : "1.2.1"
+ }
+ },
+ {
+ "identity" : "swift-url",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/karwa/swift-url.git",
+ "state" : {
+ "branch" : "main",
+ "revision" : "220f6ab9d8a7e0742f85eb9f21b745942e001ae6"
+ }
+ }
+ ],
+ "version" : 2
+}
diff --git a/Packages/UserAccounts/Package.swift b/Packages/UserAccounts/Package.swift
new file mode 100644
index 00000000..cc7656a8
--- /dev/null
+++ b/Packages/UserAccounts/Package.swift
@@ -0,0 +1,31 @@
+// swift-tools-version: 5.7
+// The swift-tools-version declares the minimum version of Swift required to build this package.
+
+import PackageDescription
+
+let package = Package(
+ name: "UserAccounts",
+ platforms: [
+ .iOS(.v15),
+ ],
+ products: [
+ // Products define the executables and libraries a package produces, and make them visible to other packages.
+ .library(
+ name: "UserAccounts",
+ targets: ["UserAccounts"]),
+ ],
+ dependencies: [
+ // Dependencies declare other packages that this package depends on.
+ .package(path: "../Pachyderm"),
+ ],
+ targets: [
+ // Targets are the basic building blocks of a package. A target can define a module or a test suite.
+ // Targets can depend on other targets in this package, and on products in packages this package depends on.
+ .target(
+ name: "UserAccounts",
+ dependencies: ["Pachyderm"]),
+ .testTarget(
+ name: "UserAccountsTests",
+ dependencies: ["UserAccounts"]),
+ ]
+)
diff --git a/Packages/UserAccounts/README.md b/Packages/UserAccounts/README.md
new file mode 100644
index 00000000..c2ecdca8
--- /dev/null
+++ b/Packages/UserAccounts/README.md
@@ -0,0 +1,3 @@
+# UserAccounts
+
+A description of this package.
diff --git a/Packages/UserAccounts/Sources/UserAccounts/UserAccountInfo.swift b/Packages/UserAccounts/Sources/UserAccounts/UserAccountInfo.swift
new file mode 100644
index 00000000..2fac2f8a
--- /dev/null
+++ b/Packages/UserAccounts/Sources/UserAccounts/UserAccountInfo.swift
@@ -0,0 +1,80 @@
+//
+// UserAccountInfo.swift
+// UserAccounts
+//
+// Created by Shadowfacts on 3/5/23.
+//
+
+import Foundation
+import CryptoKit
+
+public struct UserAccountInfo: Equatable, Hashable {
+ public let id: String
+ public let instanceURL: URL
+ public let clientID: String
+ public let clientSecret: String
+ public private(set) var username: String!
+ public let accessToken: String
+
+ fileprivate static let tempAccountID = "temp"
+
+ static func id(instanceURL: URL, username: String?) -> String {
+ // We hash the instance host and username to form the account ID
+ // so that account IDs will match across devices, allowing for data syncing and handoff.
+ var hasher = SHA256()
+ hasher.update(data: instanceURL.host!.data(using: .utf8)!)
+ if let username {
+ hasher.update(data: username.data(using: .utf8)!)
+ }
+ return Data(hasher.finalize()).base64EncodedString()
+ }
+
+ /// Only to be used for temporary MastodonController needed to fetch own account info and create final UserAccountInfo with real username
+ public init(tempInstanceURL instanceURL: URL, clientID: String, clientSecret: String, accessToken: String) {
+ self.id = UserAccountInfo.tempAccountID
+ self.instanceURL = instanceURL
+ self.clientID = clientID
+ self.clientSecret = clientSecret
+ self.accessToken = accessToken
+ }
+
+ init(instanceURL: URL, clientID: String, clientSecret: String, username: String? = nil, accessToken: String) {
+ self.id = UserAccountInfo.id(instanceURL: instanceURL, username: username)
+ self.instanceURL = instanceURL
+ self.clientID = clientID
+ self.clientSecret = clientSecret
+ self.username = username
+ self.accessToken = accessToken
+ }
+
+ init?(userDefaultsDict dict: [String: String]) {
+ guard let id = dict["id"],
+ let instanceURL = dict["instanceURL"],
+ let url = URL(string: instanceURL),
+ let clientID = dict["clientID"],
+ let secret = dict["clientSecret"],
+ let accessToken = dict["accessToken"] else {
+ return nil
+ }
+ self.id = id
+ self.instanceURL = url
+ self.clientID = clientID
+ self.clientSecret = secret
+ self.username = dict["username"]
+ self.accessToken = accessToken
+ }
+
+ /// A filename-safe string for this account
+ public var persistenceKey: String {
+ // slashes are not allowed in the persistent store coordinator name
+ id.replacingOccurrences(of: "/", with: "_")
+ }
+
+ public func hash(into hasher: inout Hasher) {
+ hasher.combine(id)
+ }
+
+ public static func ==(lhs: UserAccountInfo, rhs: UserAccountInfo) -> Bool {
+ return lhs.id == rhs.id
+ }
+}
diff --git a/Tusker/LocalData.swift b/Packages/UserAccounts/Sources/UserAccounts/UserAccountsManager.swift
similarity index 55%
rename from Tusker/LocalData.swift
rename to Packages/UserAccounts/Sources/UserAccounts/UserAccountsManager.swift
index 4da80d77..e69973ae 100644
--- a/Tusker/LocalData.swift
+++ b/Packages/UserAccounts/Sources/UserAccounts/UserAccountsManager.swift
@@ -1,18 +1,16 @@
//
-// LocalData.swift
-// Tusker
+// UserAccountsManager.swift
+// UserAccounts
//
-// Created by Shadowfacts on 8/18/18.
-// Copyright © 2018 Shadowfacts. All rights reserved.
+// Created by Shadowfacts on 3/5/23.
//
import Foundation
import Combine
-import CryptoKit
-class LocalData: ObservableObject {
+public class UserAccountsManager: ObservableObject {
- static let shared = LocalData()
+ public static let shared = UserAccountsManager()
let defaults: UserDefaults
@@ -38,7 +36,7 @@ class LocalData: ObservableObject {
}
private let accountsKey = "accounts"
- private(set) var accounts: [UserAccountInfo] {
+ public private(set) var accounts: [UserAccountInfo] {
get {
if let array = defaults.array(forKey: accountsKey) as? [[String: String]] {
return array.compactMap(UserAccountInfo.init(userDefaultsDict:))
@@ -66,7 +64,7 @@ class LocalData: ObservableObject {
}
private let mostRecentAccountKey = "mostRecentAccount"
- private(set) var mostRecentAccountID: String? {
+ public private(set) var mostRecentAccountID: String? {
get {
return defaults.string(forKey: mostRecentAccountKey)
}
@@ -109,13 +107,13 @@ class LocalData: ObservableObject {
usesAccountIDHashes = true
}
- // MARK: - Account Management
+ // MARK: Account Management
- var onboardingComplete: Bool {
+ public var onboardingComplete: Bool {
return !accounts.isEmpty
}
- func addAccount(instanceURL url: URL, clientID: String, clientSecret secret: String, username: String?, accessToken: String) -> UserAccountInfo {
+ public func addAccount(instanceURL url: URL, clientID: 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)
@@ -126,15 +124,15 @@ class LocalData: ObservableObject {
return info
}
- func removeAccount(_ info: UserAccountInfo) {
+ public func removeAccount(_ info: UserAccountInfo) {
accounts.removeAll(where: { $0.id == info.id })
}
- func getAccount(id: String) -> UserAccountInfo? {
+ public func getAccount(id: String) -> UserAccountInfo? {
return accounts.first(where: { $0.id == id })
}
- func getMostRecentAccount() -> UserAccountInfo? {
+ public func getMostRecentAccount() -> UserAccountInfo? {
guard onboardingComplete else { return nil }
let mostRecent: UserAccountInfo?
if let id = mostRecentAccountID {
@@ -145,86 +143,13 @@ class LocalData: ObservableObject {
return mostRecent ?? accounts.first!
}
- func setMostRecentAccount(_ account: UserAccountInfo?) {
+ public func setMostRecentAccount(_ account: UserAccountInfo?) {
mostRecentAccountID = account?.id
}
}
-extension LocalData {
- struct UserAccountInfo: Equatable, Hashable {
- let id: String
- let instanceURL: URL
- let clientID: String
- let clientSecret: String
- private(set) var username: String!
- let accessToken: String
-
- fileprivate static let tempAccountID = "temp"
-
- fileprivate static func id(instanceURL: URL, username: String?) -> String {
- // We hash the instance host and username to form the account ID
- // so that account IDs will match across devices, allowing for data syncing and handoff.
- var hasher = SHA256()
- hasher.update(data: instanceURL.host!.data(using: .utf8)!)
- if let username {
- hasher.update(data: username.data(using: .utf8)!)
- }
- return Data(hasher.finalize()).base64EncodedString()
- }
-
- /// Only to be used for temporary MastodonController needed to fetch own account info and create final UserAccountInfo with real username
- init(tempInstanceURL instanceURL: URL, clientID: String, clientSecret: String, accessToken: String) {
- self.id = UserAccountInfo.tempAccountID
- self.instanceURL = instanceURL
- self.clientID = clientID
- self.clientSecret = clientSecret
- self.accessToken = accessToken
- }
-
- fileprivate init(instanceURL: URL, clientID: String, clientSecret: String, username: String? = nil, accessToken: String) {
- self.id = UserAccountInfo.id(instanceURL: instanceURL, username: username)
- self.instanceURL = instanceURL
- self.clientID = clientID
- self.clientSecret = clientSecret
- self.username = username
- self.accessToken = accessToken
- }
-
- fileprivate init?(userDefaultsDict dict: [String: String]) {
- guard let id = dict["id"],
- let instanceURL = dict["instanceURL"],
- let url = URL(string: instanceURL),
- let clientID = dict["clientID"],
- let secret = dict["clientSecret"],
- let accessToken = dict["accessToken"] else {
- return nil
- }
- self.id = id
- self.instanceURL = url
- self.clientID = clientID
- self.clientSecret = secret
- self.username = dict["username"]
- self.accessToken = accessToken
- }
-
- /// A filename-safe string for this account
- var persistenceKey: String {
- // slashes are not allowed in the persistent store coordinator name
- id.replacingOccurrences(of: "/", with: "_")
- }
-
- func hash(into hasher: inout Hasher) {
- hasher.combine(id)
- }
-
- static func ==(lhs: UserAccountInfo, rhs: UserAccountInfo) -> Bool {
- return lhs.id == rhs.id
- }
- }
-}
-
-extension Notification.Name {
+public extension Notification.Name {
static let userLoggedOut = Notification.Name("Tusker.userLoggedOut")
static let addAccount = Notification.Name("Tusker.addAccount")
static let activateAccount = Notification.Name("Tusker.activateAccount")
diff --git a/Tusker.xcodeproj/project.pbxproj b/Tusker.xcodeproj/project.pbxproj
index d7f04697..cd4275d7 100644
--- a/Tusker.xcodeproj/project.pbxproj
+++ b/Tusker.xcodeproj/project.pbxproj
@@ -142,7 +142,6 @@
D64BC18623C1253A000D0238 /* AssetPreviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64BC18523C1253A000D0238 /* AssetPreviewViewController.swift */; };
D64BC18F23C18B9D000D0238 /* FollowRequestNotificationTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64BC18D23C18B9D000D0238 /* FollowRequestNotificationTableViewCell.swift */; };
D64BC19023C18B9D000D0238 /* FollowRequestNotificationTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D64BC18E23C18B9D000D0238 /* FollowRequestNotificationTableViewCell.xib */; };
- D64D0AAD2128D88B005A6F37 /* LocalData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64D0AAC2128D88B005A6F37 /* LocalData.swift */; };
D64D0AB12128D9AE005A6F37 /* OnboardingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64D0AB02128D9AE005A6F37 /* OnboardingViewController.swift */; };
D64D8CA92463B494006B0BAA /* MultiThreadDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64D8CA82463B494006B0BAA /* MultiThreadDictionary.swift */; };
D651C5B42915B00400236EF6 /* ProfileFieldsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D651C5B32915B00400236EF6 /* ProfileFieldsView.swift */; };
@@ -268,6 +267,7 @@
D6ADB6F028ED1F25009924AB /* CachedImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6ADB6EF28ED1F25009924AB /* CachedImageView.swift */; };
D6AEBB3E2321638100E5038B /* UIActivity+Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6AEBB3D2321638100E5038B /* UIActivity+Types.swift */; };
D6AEBB432321685E00E5038B /* OpenInSafariActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6AEBB422321685E00E5038B /* OpenInSafariActivity.swift */; };
+ D6B0026E29B5248800C70BE2 /* UserAccounts in Frameworks */ = {isa = PBXBuildFile; productRef = D6B0026D29B5248800C70BE2 /* UserAccounts */; };
D6B053A223BD2C0600A066FA /* AssetPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B053A123BD2C0600A066FA /* AssetPickerViewController.swift */; };
D6B053A423BD2C8100A066FA /* AssetCollectionsListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B053A323BD2C8100A066FA /* AssetCollectionsListViewController.swift */; };
D6B053A623BD2D0C00A066FA /* AssetCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B053A523BD2D0C00A066FA /* AssetCollectionViewController.swift */; };
@@ -559,7 +559,6 @@
D64BC18523C1253A000D0238 /* AssetPreviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetPreviewViewController.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 = ""; };
- D64D0AAC2128D88B005A6F37 /* LocalData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalData.swift; sourceTree = ""; };
D64D0AB02128D9AE005A6F37 /* OnboardingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewController.swift; sourceTree = ""; };
D64D8CA82463B494006B0BAA /* MultiThreadDictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiThreadDictionary.swift; sourceTree = ""; };
D651C5B32915B00400236EF6 /* ProfileFieldsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileFieldsView.swift; sourceTree = ""; };
@@ -688,6 +687,7 @@
D6ADB6EF28ED1F25009924AB /* CachedImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CachedImageView.swift; sourceTree = ""; };
D6AEBB3D2321638100E5038B /* UIActivity+Types.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIActivity+Types.swift"; sourceTree = ""; };
D6AEBB422321685E00E5038B /* OpenInSafariActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenInSafariActivity.swift; sourceTree = ""; };
+ D6B0026C29B5245400C70BE2 /* UserAccounts */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = UserAccounts; path = Packages/UserAccounts; sourceTree = ""; };
D6B053A123BD2C0600A066FA /* AssetPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetPickerViewController.swift; sourceTree = ""; };
D6B053A323BD2C8100A066FA /* AssetCollectionsListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetCollectionsListViewController.swift; sourceTree = ""; };
D6B053A523BD2D0C00A066FA /* AssetCollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetCollectionViewController.swift; sourceTree = ""; };
@@ -813,6 +813,7 @@
files = (
D674A50927F9128D00BA03AC /* Pachyderm in Frameworks */,
D659F35E2953A212002D944A /* TTTKit in Frameworks */,
+ D6B0026E29B5248800C70BE2 /* UserAccounts in Frameworks */,
D60CFFDB24A290BA00D00083 /* SwiftSoup in Frameworks */,
D60088EF2980D8B5005B4D00 /* StoreKit.framework in Frameworks */,
D6552367289870790048A653 /* ScreenCorners in Frameworks */,
@@ -1537,6 +1538,7 @@
D674A50727F910F300BA03AC /* Pachyderm */,
D6BEA243291A0C83002F4D01 /* Duckable */,
D68A76F22953915C001DA1B3 /* TTTKit */,
+ D6B0026C29B5245400C70BE2 /* UserAccounts */,
D6D4DDCE212518A000E1C4BB /* Tusker */,
D6D4DDE3212518A200E1C4BB /* TuskerTests */,
D6D4DDEE212518A200E1C4BB /* TuskerUITests */,
@@ -1573,7 +1575,6 @@
D6B30E08254BAF63009CAEE5 /* ImageGrayscalifier.swift */,
D61F75BC293D099600C0B37F /* Lazy.swift */,
D60E2F2B24423EAD005F8713 /* LazilyDecoding.swift */,
- D64D0AAC2128D88B005A6F37 /* LocalData.swift */,
D61DC84528F498F200B82C6E /* Logging.swift */,
D6B81F432560390300F6E31D /* MenuController.swift */,
D64D8CA82463B494006B0BAA /* MultiThreadDictionary.swift */,
@@ -1741,6 +1742,7 @@
D63CC701290EC0B8000E19DE /* Sentry */,
D6BEA244291A0EDE002F4D01 /* Duckable */,
D659F35D2953A212002D944A /* TTTKit */,
+ D6B0026D29B5248800C70BE2 /* UserAccounts */,
);
productName = Tusker;
productReference = D6D4DDCC212518A000E1C4BB /* Tusker.app */;
@@ -2147,7 +2149,6 @@
D6DD2A45273D6C5700386A6C /* GIFImageView.swift in Sources */,
D61F759029353B4300C0B37F /* FileManager+Size.swift in Sources */,
0427033822B30F5F000D31B6 /* BehaviorPrefsView.swift in Sources */,
- D64D0AAD2128D88B005A6F37 /* LocalData.swift in Sources */,
D6945C2F23AC47C3005C403C /* SavedDataManager.swift in Sources */,
D6C94D892139E6EC00CB5196 /* AttachmentView.swift in Sources */,
D6C693EF216192C2007D6A6D /* TuskerNavigationDelegate.swift in Sources */,
@@ -2966,6 +2967,10 @@
isa = XCSwiftPackageProductDependency;
productName = Pachyderm;
};
+ D6B0026D29B5248800C70BE2 /* UserAccounts */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = UserAccounts;
+ };
D6BEA244291A0EDE002F4D01 /* Duckable */ = {
isa = XCSwiftPackageProductDependency;
productName = Duckable;
diff --git a/Tusker/API/LogoutService.swift b/Tusker/API/LogoutService.swift
index 42b76255..e5837ee8 100644
--- a/Tusker/API/LogoutService.swift
+++ b/Tusker/API/LogoutService.swift
@@ -7,13 +7,14 @@
//
import Foundation
+import UserAccounts
@MainActor
class LogoutService {
- let accountInfo: LocalData.UserAccountInfo
+ let accountInfo: UserAccountInfo
private let mastodonController: MastodonController
- init(accountInfo: LocalData.UserAccountInfo) {
+ init(accountInfo: UserAccountInfo) {
self.accountInfo = accountInfo
self.mastodonController = MastodonController.getForAccount(accountInfo)
}
@@ -23,7 +24,7 @@ class LogoutService {
try? await self.mastodonController.client.revokeAccessToken()
}
MastodonController.removeForAccount(accountInfo)
- LocalData.shared.removeAccount(accountInfo)
+ UserAccountsManager.shared.removeAccount(accountInfo)
let psc = mastodonController.persistentContainer.persistentStoreCoordinator
for store in psc.persistentStores {
guard let url = store.url else {
diff --git a/Tusker/API/MastodonController.swift b/Tusker/API/MastodonController.swift
index a2b8e60a..489118fd 100644
--- a/Tusker/API/MastodonController.swift
+++ b/Tusker/API/MastodonController.swift
@@ -9,15 +9,16 @@
import Foundation
import Pachyderm
import Combine
+import UserAccounts
class MastodonController: ObservableObject {
- static private(set) var all = [LocalData.UserAccountInfo: MastodonController]()
+ static private(set) var all = [UserAccountInfo: MastodonController]()
@available(*, message: "do something less dumb")
static var first: MastodonController { all.first!.value }
- static func getForAccount(_ account: LocalData.UserAccountInfo) -> MastodonController {
+ static func getForAccount(_ account: UserAccountInfo) -> MastodonController {
if let controller = all[account] {
return controller
} else {
@@ -31,7 +32,7 @@ class MastodonController: ObservableObject {
}
}
- static func removeForAccount(_ account: LocalData.UserAccountInfo) {
+ static func removeForAccount(_ account: UserAccountInfo) {
all.removeValue(forKey: account)
}
@@ -43,7 +44,7 @@ class MastodonController: ObservableObject {
private(set) nonisolated lazy var persistentContainer = MastodonCachePersistentStore(for: accountInfo, transient: transient)
let instanceURL: URL
- var accountInfo: LocalData.UserAccountInfo?
+ var accountInfo: UserAccountInfo?
var accountPreferences: AccountPreferences!
let client: Client!
diff --git a/Tusker/AppDelegate.swift b/Tusker/AppDelegate.swift
index 5ffd44e7..d4141592 100644
--- a/Tusker/AppDelegate.swift
+++ b/Tusker/AppDelegate.swift
@@ -10,6 +10,7 @@ import UIKit
import CoreData
import OSLog
import Sentry
+import UserAccounts
let stateRestorationLogger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "StateRestoration")
@@ -32,7 +33,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
if let oldSavedData = SavedDataManager.load() {
do {
for account in oldSavedData.accountIDs {
- guard let account = LocalData.shared.getAccount(id: account) else {
+ guard let account = UserAccountsManager.shared.getAccount(id: account) else {
continue
}
let controller = MastodonController.getForAccount(account)
diff --git a/Tusker/CoreData/AccountPreferences.swift b/Tusker/CoreData/AccountPreferences.swift
index 53f990d1..c8c0b388 100644
--- a/Tusker/CoreData/AccountPreferences.swift
+++ b/Tusker/CoreData/AccountPreferences.swift
@@ -9,11 +9,12 @@
import Foundation
import CoreData
import Pachyderm
+import UserAccounts
@objc(AccountPreferences)
public final class AccountPreferences: NSManagedObject {
- @nonobjc class func fetchRequest(account: LocalData.UserAccountInfo) -> NSFetchRequest {
+ @nonobjc class func fetchRequest(account: UserAccountInfo) -> NSFetchRequest {
let req = NSFetchRequest(entityName: "AccountPreferences")
req.predicate = NSPredicate(format: "accountID = %@", account.id)
req.sortDescriptors = [NSSortDescriptor(key: "createdAt", ascending: true)]
@@ -27,7 +28,7 @@ public final class AccountPreferences: NSManagedObject {
@LazilyDecoding(from: \AccountPreferences.pinnedTimelinesData, fallback: AccountPreferences.defaultPinnedTimelines)
var pinnedTimelines: [PinnedTimeline]
- static func `default`(account: LocalData.UserAccountInfo, context: NSManagedObjectContext) -> AccountPreferences {
+ static func `default`(account: UserAccountInfo, context: NSManagedObjectContext) -> AccountPreferences {
let prefs = AccountPreferences(context: context)
prefs.accountID = account.id
prefs.createdAt = Date()
diff --git a/Tusker/CoreData/MastodonCachePersistentStore.swift b/Tusker/CoreData/MastodonCachePersistentStore.swift
index 1c6b78d7..05e4560f 100644
--- a/Tusker/CoreData/MastodonCachePersistentStore.swift
+++ b/Tusker/CoreData/MastodonCachePersistentStore.swift
@@ -13,12 +13,13 @@ import Combine
import OSLog
import Sentry
import CloudKit
+import UserAccounts
fileprivate let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "PersistentStore")
class MastodonCachePersistentStore: NSPersistentCloudKitContainer {
- private let accountInfo: LocalData.UserAccountInfo?
+ private let accountInfo: UserAccountInfo?
private static let managedObjectModel: NSManagedObjectModel = {
let url = Bundle.main.url(forResource: "Tusker", withExtension: "momd")!
@@ -51,7 +52,7 @@ class MastodonCachePersistentStore: NSPersistentCloudKitContainer {
let accountSubject = PassthroughSubject()
let relationshipSubject = PassthroughSubject()
- init(for accountInfo: LocalData.UserAccountInfo?, transient: Bool = false) {
+ init(for accountInfo: UserAccountInfo?, transient: Bool = false) {
self.accountInfo = accountInfo
let group = DispatchGroup()
diff --git a/Tusker/CoreData/SavedHashtag.swift b/Tusker/CoreData/SavedHashtag.swift
index 265513b9..f206d456 100644
--- a/Tusker/CoreData/SavedHashtag.swift
+++ b/Tusker/CoreData/SavedHashtag.swift
@@ -10,6 +10,7 @@ import Foundation
import CoreData
import Pachyderm
import WebURLFoundationExtras
+import UserAccounts
@objc(SavedHashtag)
public final class SavedHashtag: NSManagedObject {
@@ -18,13 +19,13 @@ public final class SavedHashtag: NSManagedObject {
return NSFetchRequest(entityName: "SavedHashtag")
}
- @nonobjc class func fetchRequest(account: LocalData.UserAccountInfo) -> NSFetchRequest {
+ @nonobjc class func fetchRequest(account: UserAccountInfo) -> NSFetchRequest {
let req = NSFetchRequest(entityName: "SavedHashtag")
req.predicate = NSPredicate(format: "accountID = %@", account.id)
return req
}
- @nonobjc class func fetchRequest(name: String, account: LocalData.UserAccountInfo) -> NSFetchRequest {
+ @nonobjc class func fetchRequest(name: String, account: UserAccountInfo) -> NSFetchRequest {
let req = NSFetchRequest(entityName: "SavedHashtag")
req.predicate = NSPredicate(format: "name LIKE[cd] %@ AND accountID = %@", name, account.id)
return req
@@ -37,7 +38,7 @@ public final class SavedHashtag: NSManagedObject {
}
extension SavedHashtag {
- convenience init(hashtag: Hashtag, account: LocalData.UserAccountInfo, context: NSManagedObjectContext) {
+ convenience init(hashtag: Hashtag, account: UserAccountInfo, context: NSManagedObjectContext) {
self.init(context: context)
self.accountID = account.id
self.name = hashtag.name
diff --git a/Tusker/CoreData/SavedInstance.swift b/Tusker/CoreData/SavedInstance.swift
index f2c612e8..d6e938b7 100644
--- a/Tusker/CoreData/SavedInstance.swift
+++ b/Tusker/CoreData/SavedInstance.swift
@@ -8,6 +8,7 @@
import Foundation
import CoreData
+import UserAccounts
@objc(SavedInstance)
public final class SavedInstance: NSManagedObject {
@@ -16,13 +17,13 @@ public final class SavedInstance: NSManagedObject {
return NSFetchRequest(entityName: "SavedInstance")
}
- @nonobjc class func fetchRequest(account: LocalData.UserAccountInfo) -> NSFetchRequest {
+ @nonobjc class func fetchRequest(account: UserAccountInfo) -> NSFetchRequest {
let req = NSFetchRequest(entityName: "SavedInstance")
req.predicate = NSPredicate(format: "accountID = %@", account.id)
return req
}
- @nonobjc class func fetchRequest(url: URL, account: LocalData.UserAccountInfo) -> NSFetchRequest {
+ @nonobjc class func fetchRequest(url: URL, account: UserAccountInfo) -> NSFetchRequest {
let req = NSFetchRequest(entityName: "SavedInstance")
req.predicate = NSPredicate(format: "url = %@ AND accountID = %@", url as NSURL, account.id)
return req
@@ -34,7 +35,7 @@ public final class SavedInstance: NSManagedObject {
}
extension SavedInstance {
- convenience init(url: URL, account: LocalData.UserAccountInfo, context: NSManagedObjectContext) {
+ convenience init(url: URL, account: UserAccountInfo, context: NSManagedObjectContext) {
self.init(context: context)
self.accountID = account.id
self.url = url
diff --git a/Tusker/CoreData/TimelinePosition.swift b/Tusker/CoreData/TimelinePosition.swift
index 444bae4a..99d164a6 100644
--- a/Tusker/CoreData/TimelinePosition.swift
+++ b/Tusker/CoreData/TimelinePosition.swift
@@ -9,11 +9,12 @@
import Foundation
import CoreData
import Pachyderm
+import UserAccounts
@objc(TimelinePosition)
public final class TimelinePosition: NSManagedObject {
- @nonobjc class func fetchRequest(timeline: Timeline, account: LocalData.UserAccountInfo) -> NSFetchRequest {
+ @nonobjc class func fetchRequest(timeline: Timeline, account: UserAccountInfo) -> NSFetchRequest {
let req = NSFetchRequest(entityName: "TimelinePosition")
req.predicate = NSPredicate(format: "accountID = %@ AND timelineKind = %@", account.id, toTimelineKind(timeline))
req.sortDescriptors = [NSSortDescriptor(key: "createdAt", ascending: true)]
@@ -34,7 +35,7 @@ public final class TimelinePosition: NSManagedObject {
set { timelineKind = toTimelineKind(newValue) }
}
- convenience init(timeline: Timeline, account: LocalData.UserAccountInfo, context: NSManagedObjectContext) {
+ convenience init(timeline: Timeline, account: UserAccountInfo, context: NSManagedObjectContext) {
self.init(context: context)
self.timeline = timeline
self.accountID = account.id
diff --git a/Tusker/Scenes/AuxiliarySceneDelegate.swift b/Tusker/Scenes/AuxiliarySceneDelegate.swift
index 211f7c63..7480865f 100644
--- a/Tusker/Scenes/AuxiliarySceneDelegate.swift
+++ b/Tusker/Scenes/AuxiliarySceneDelegate.swift
@@ -8,6 +8,7 @@
import UIKit
import Pachyderm
+import UserAccounts
class AuxiliarySceneDelegate: UIResponder, UIWindowSceneDelegate, TuskerSceneDelegate {
@@ -31,11 +32,11 @@ class AuxiliarySceneDelegate: UIResponder, UIWindowSceneDelegate, TuskerSceneDel
}
launchActivity = activity
- let account: LocalData.UserAccountInfo
+ let account: UserAccountInfo
if let activityAccount = UserActivityManager.getAccount(from: activity) {
account = activityAccount
- } else if let mostRecent = LocalData.shared.getMostRecentAccount() {
+ } else if let mostRecent = UserAccountsManager.shared.getMostRecentAccount() {
account = mostRecent
} else {
// without an account, we can't do anything so we just destroy the scene
diff --git a/Tusker/Scenes/ComposeSceneDelegate.swift b/Tusker/Scenes/ComposeSceneDelegate.swift
index 61f2de1c..c97a36b9 100644
--- a/Tusker/Scenes/ComposeSceneDelegate.swift
+++ b/Tusker/Scenes/ComposeSceneDelegate.swift
@@ -8,6 +8,7 @@
import UIKit
import Combine
+import UserAccounts
class ComposeSceneDelegate: UIResponder, UIWindowSceneDelegate, TuskerSceneDelegate {
@@ -22,12 +23,12 @@ class ComposeSceneDelegate: UIResponder, UIWindowSceneDelegate, TuskerSceneDeleg
return
}
- guard LocalData.shared.onboardingComplete else {
+ guard UserAccountsManager.shared.onboardingComplete else {
UIApplication.shared.requestSceneSessionDestruction(session, options: nil, errorHandler: nil)
return
}
- let account: LocalData.UserAccountInfo
+ let account: UserAccountInfo
let controller: MastodonController
let draft: Draft?
@@ -36,7 +37,7 @@ class ComposeSceneDelegate: UIResponder, UIWindowSceneDelegate, TuskerSceneDeleg
account = activityAccount
} else {
// todo: this potentially changes the account for the draft, should show the same warning to user as in the drafts selection screen
- account = LocalData.shared.getMostRecentAccount()!
+ account = UserAccountsManager.shared.getMostRecentAccount()!
}
controller = MastodonController.getForAccount(account)
@@ -49,7 +50,7 @@ class ComposeSceneDelegate: UIResponder, UIWindowSceneDelegate, TuskerSceneDeleg
draft = nil
}
} else {
- account = LocalData.shared.getMostRecentAccount()!
+ account = UserAccountsManager.shared.getMostRecentAccount()!
controller = MastodonController.getForAccount(account)
draft = nil
}
diff --git a/Tusker/Scenes/MainSceneDelegate.swift b/Tusker/Scenes/MainSceneDelegate.swift
index 7ca55ae0..8b6f5547 100644
--- a/Tusker/Scenes/MainSceneDelegate.swift
+++ b/Tusker/Scenes/MainSceneDelegate.swift
@@ -11,6 +11,7 @@ import Pachyderm
import MessageUI
import CoreData
import Duckable
+import UserAccounts
class MainSceneDelegate: UIResponder, UIWindowSceneDelegate, TuskerSceneDelegate {
@@ -161,13 +162,13 @@ class MainSceneDelegate: UIResponder, UIWindowSceneDelegate, TuskerSceneDelegate
func showAppOrOnboardingUI(session: UISceneSession? = nil) {
let session = session ?? window!.windowScene!.session
- if LocalData.shared.onboardingComplete {
- let account: LocalData.UserAccountInfo
+ if UserAccountsManager.shared.onboardingComplete {
+ let account: UserAccountInfo
if let activity = launchActivity,
let activityAccount = UserActivityManager.getAccount(from: activity) {
account = activityAccount
} else {
- account = LocalData.shared.getMostRecentAccount()!
+ account = UserAccountsManager.shared.getMostRecentAccount()!
}
if session.mastodonController == nil {
@@ -194,9 +195,9 @@ class MainSceneDelegate: UIResponder, UIWindowSceneDelegate, TuskerSceneDelegate
}
}
- func activateAccount(_ account: LocalData.UserAccountInfo, animated: Bool) {
- let oldMostRecentAccount = LocalData.shared.mostRecentAccountID
- LocalData.shared.setMostRecentAccount(account)
+ func activateAccount(_ account: UserAccountInfo, animated: Bool) {
+ let oldMostRecentAccount = UserAccountsManager.shared.mostRecentAccountID
+ UserAccountsManager.shared.setMostRecentAccount(account)
window!.windowScene!.session.mastodonController = MastodonController.getForAccount(account)
// iPadOS shows the title below the App Name
@@ -212,8 +213,8 @@ class MainSceneDelegate: UIResponder, UIWindowSceneDelegate, TuskerSceneDelegate
if let container = window?.rootViewController as? AccountSwitchingContainerViewController {
let direction: AccountSwitchingContainerViewController.AnimationDirection
if animated,
- let oldIndex = LocalData.shared.accounts.firstIndex(where: { $0.id == oldMostRecentAccount }),
- let newIndex = LocalData.shared.accounts.firstIndex(of: account) {
+ let oldIndex = UserAccountsManager.shared.accounts.firstIndex(where: { $0.id == oldMostRecentAccount }),
+ let newIndex = UserAccountsManager.shared.accounts.firstIndex(of: account) {
direction = newIndex > oldIndex ? .upwards : .downwards
} else {
direction = .none
@@ -229,8 +230,8 @@ class MainSceneDelegate: UIResponder, UIWindowSceneDelegate, TuskerSceneDelegate
return
}
LogoutService(accountInfo: account).run()
- if LocalData.shared.onboardingComplete {
- activateAccount(LocalData.shared.accounts.first!, animated: false)
+ if UserAccountsManager.shared.onboardingComplete {
+ activateAccount(UserAccountsManager.shared.accounts.first!, animated: false)
} else {
window!.rootViewController = createOnboardingUI()
}
@@ -269,7 +270,7 @@ class MainSceneDelegate: UIResponder, UIWindowSceneDelegate, TuskerSceneDelegate
}
extension MainSceneDelegate: OnboardingViewControllerDelegate {
- func didFinishOnboarding(account: LocalData.UserAccountInfo) {
+ func didFinishOnboarding(account: UserAccountInfo) {
activateAccount(account, animated: false)
}
}
diff --git a/Tusker/Screens/Fast Account Switcher/FastAccountSwitcherViewController.swift b/Tusker/Screens/Fast Account Switcher/FastAccountSwitcherViewController.swift
index 408e10ce..0104cfab 100644
--- a/Tusker/Screens/Fast Account Switcher/FastAccountSwitcherViewController.swift
+++ b/Tusker/Screens/Fast Account Switcher/FastAccountSwitcherViewController.swift
@@ -7,6 +7,7 @@
//
import UIKit
+import UserAccounts
protocol FastAccountSwitcherViewControllerDelegate: AnyObject {
func fastAccountSwitcherAddToViewHierarchy(_ fastAccountSwitcher: FastAccountSwitcherViewController)
@@ -139,9 +140,9 @@ class FastAccountSwitcherViewController: UIViewController {
addAccountPlaceholder
]
- for account in LocalData.shared.accounts {
+ for account in UserAccountsManager.shared.accounts {
let accountView = FastSwitchingAccountView(account: account, orientation: itemOrientation)
- accountView.isCurrent = account.id == LocalData.shared.mostRecentAccountID
+ accountView.isCurrent = account.id == UserAccountsManager.shared.mostRecentAccountID
accountsStack.addArrangedSubview(accountView)
accountViews.append(accountView)
}
@@ -168,9 +169,9 @@ class FastAccountSwitcherViewController: UIViewController {
(self.view.window!.windowScene!.delegate as! MainSceneDelegate).showAddAccount()
}
} else {
- let account = LocalData.shared.accounts[newIndex - 1]
+ let account = UserAccountsManager.shared.accounts[newIndex - 1]
- if account.id != LocalData.shared.mostRecentAccountID {
+ if account.id != UserAccountsManager.shared.mostRecentAccountID {
if hapticFeedback {
selectionChangedFeedbackGenerator?.selectionChanged()
}
diff --git a/Tusker/Screens/Fast Account Switcher/FastSwitchingAccountView.swift b/Tusker/Screens/Fast Account Switcher/FastSwitchingAccountView.swift
index e5930cf7..7e04fbc3 100644
--- a/Tusker/Screens/Fast Account Switcher/FastSwitchingAccountView.swift
+++ b/Tusker/Screens/Fast Account Switcher/FastSwitchingAccountView.swift
@@ -7,6 +7,7 @@
//
import UIKit
+import UserAccounts
class FastSwitchingAccountView: UIView {
@@ -49,7 +50,7 @@ class FastSwitchingAccountView: UIView {
private var avatarRequest: ImageCache.Request?
- init(account: LocalData.UserAccountInfo, orientation: FastAccountSwitcherViewController.ItemOrientation) {
+ init(account: UserAccountInfo, orientation: FastAccountSwitcherViewController.ItemOrientation) {
self.orientation = orientation
super.init(frame: .zero)
commonInit()
@@ -121,7 +122,7 @@ class FastSwitchingAccountView: UIView {
isAccessibilityElement = true
}
- private func setupAccount(account: LocalData.UserAccountInfo) {
+ private func setupAccount(account: UserAccountInfo) {
usernameLabel.text = account.username
instanceLabel.text = account.instanceURL.host!
let controller = MastodonController.getForAccount(account)
diff --git a/Tusker/Screens/Main/AccountSwitchingContainerViewController.swift b/Tusker/Screens/Main/AccountSwitchingContainerViewController.swift
index eb35c7ea..29a0b767 100644
--- a/Tusker/Screens/Main/AccountSwitchingContainerViewController.swift
+++ b/Tusker/Screens/Main/AccountSwitchingContainerViewController.swift
@@ -8,6 +8,7 @@
import UIKit
import ScreenCorners
+import UserAccounts
class AccountSwitchingContainerViewController: UIViewController {
@@ -16,7 +17,7 @@ class AccountSwitchingContainerViewController: UIViewController {
private var userActivities: [String: NSUserActivity] = [:]
- init(root: TuskerRootViewController, for account: LocalData.UserAccountInfo) {
+ init(root: TuskerRootViewController, for account: UserAccountInfo) {
self.currentAccountID = account.id
self.root = root
@@ -33,7 +34,7 @@ class AccountSwitchingContainerViewController: UIViewController {
embedChild(root)
}
- func setRoot(_ newRoot: TuskerRootViewController, for account: LocalData.UserAccountInfo, animating direction: AnimationDirection) {
+ func setRoot(_ newRoot: TuskerRootViewController, for account: UserAccountInfo, animating direction: AnimationDirection) {
let oldRoot = self.root
if direction == .none {
oldRoot.removeViewAndController()
diff --git a/Tusker/Screens/Main/MainSidebarMyProfileCollectionViewCell.swift b/Tusker/Screens/Main/MainSidebarMyProfileCollectionViewCell.swift
index dd7e5961..0de63d85 100644
--- a/Tusker/Screens/Main/MainSidebarMyProfileCollectionViewCell.swift
+++ b/Tusker/Screens/Main/MainSidebarMyProfileCollectionViewCell.swift
@@ -7,6 +7,7 @@
//
import UIKit
+import UserAccounts
class MainSidebarMyProfileCollectionViewCell: UICollectionViewListCell {
@@ -35,7 +36,7 @@ class MainSidebarMyProfileCollectionViewCell: UICollectionViewListCell {
fatalError("init(coder:) has not been implemented")
}
- func updateUI(item: MainSidebarViewController.Item, account: LocalData.UserAccountInfo) async {
+ func updateUI(item: MainSidebarViewController.Item, account: UserAccountInfo) async {
var config = defaultContentConfiguration()
config.text = item.title
config.image = UIImage(systemName: item.imageName!)
diff --git a/Tusker/Screens/Onboarding/OnboardingViewController.swift b/Tusker/Screens/Onboarding/OnboardingViewController.swift
index f3331181..402c783c 100644
--- a/Tusker/Screens/Onboarding/OnboardingViewController.swift
+++ b/Tusker/Screens/Onboarding/OnboardingViewController.swift
@@ -10,10 +10,11 @@ import UIKit
import AuthenticationServices
import Pachyderm
import OSLog
+import UserAccounts
protocol OnboardingViewControllerDelegate {
@MainActor
- func didFinishOnboarding(account: LocalData.UserAccountInfo)
+ func didFinishOnboarding(account: UserAccountInfo)
}
private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "OnboardingViewController")
@@ -145,7 +146,7 @@ class OnboardingViewController: UINavigationController {
}
// construct a temporary UserAccountInfo instance for the MastodonController to use to fetch its own account
- let tempAccountInfo = LocalData.UserAccountInfo(tempInstanceURL: instanceURL, clientID: clientID, clientSecret: clientSecret, accessToken: accessToken)
+ let tempAccountInfo = UserAccountInfo(tempInstanceURL: instanceURL, clientID: clientID, clientSecret: clientSecret, accessToken: accessToken)
mastodonController.accountInfo = tempAccountInfo
updateStatus("Checking Credentials")
@@ -158,7 +159,7 @@ class OnboardingViewController: UINavigationController {
throw Error.gettingOwnAccount(error)
}
- let accountInfo = LocalData.shared.addAccount(instanceURL: instanceURL, clientID: clientID, clientSecret: clientSecret, username: ownAccount.username, accessToken: accessToken)
+ let accountInfo = UserAccountsManager.shared.addAccount(instanceURL: instanceURL, clientID: clientID, clientSecret: clientSecret, username: ownAccount.username, accessToken: accessToken)
mastodonController.accountInfo = accountInfo
self.onboardingDelegate?.didFinishOnboarding(account: accountInfo)
diff --git a/Tusker/Screens/Preferences/AdvancedPrefsView.swift b/Tusker/Screens/Preferences/AdvancedPrefsView.swift
index d5aed245..d698f14c 100644
--- a/Tusker/Screens/Preferences/AdvancedPrefsView.swift
+++ b/Tusker/Screens/Preferences/AdvancedPrefsView.swift
@@ -9,6 +9,7 @@ import SwiftUI
import Pachyderm
import CoreData
import CloudKit
+import UserAccounts
struct AdvancedPrefsView : View {
@ObservedObject var preferences = Preferences.shared
@@ -30,7 +31,7 @@ struct AdvancedPrefsView : View {
var formattingFooter: some View {
var s: AttributedString = "This option is only supported with Pleroma and some compatible Mastodon instances (such as Glitch).\n"
- if let account = LocalData.shared.getMostRecentAccount() {
+ if let account = UserAccountsManager.shared.getMostRecentAccount() {
let mastodonController = MastodonController.getForAccount(account)
// shouldn't need to load the instance here, because loading it is kicked off my the scene delegate
if !mastodonController.instanceFeatures.probablySupportsMarkdown {
@@ -135,7 +136,7 @@ struct AdvancedPrefsView : View {
].map {
$0.getDiskSizeInBytes() ?? 0
}.reduce(0, +)
- mastodonCacheSize = LocalData.shared.accounts.map {
+ mastodonCacheSize = UserAccountsManager.shared.accounts.map {
let descriptions = MastodonController.getForAccount($0).persistentContainer.persistentStoreDescriptions
return descriptions.map {
guard let url = $0.url else {
@@ -148,7 +149,7 @@ struct AdvancedPrefsView : View {
}
private func clearCache() {
- for account in LocalData.shared.accounts {
+ for account in UserAccountsManager.shared.accounts {
let controller = MastodonController.getForAccount(account)
let container = controller.persistentContainer
do {
@@ -178,7 +179,7 @@ struct AdvancedPrefsView : View {
}
private func resetUI() {
- let mostRecent = LocalData.shared.getMostRecentAccount()!
+ let mostRecent = UserAccountsManager.shared.getMostRecentAccount()!
NotificationCenter.default.post(name: .activateAccount, object: nil, userInfo: ["account": mostRecent])
}
}
diff --git a/Tusker/Screens/Preferences/LocalAccountAvatarView.swift b/Tusker/Screens/Preferences/LocalAccountAvatarView.swift
index 6d17804e..b586e528 100644
--- a/Tusker/Screens/Preferences/LocalAccountAvatarView.swift
+++ b/Tusker/Screens/Preferences/LocalAccountAvatarView.swift
@@ -7,9 +7,10 @@
//
import SwiftUI
+import UserAccounts
struct LocalAccountAvatarView: View {
- let localAccountInfo: LocalData.UserAccountInfo
+ let localAccountInfo: UserAccountInfo
@State var avatarImage: UIImage? = nil
@ObservedObject var preferences = Preferences.shared
diff --git a/Tusker/Screens/Preferences/PreferencesNavigationController.swift b/Tusker/Screens/Preferences/PreferencesNavigationController.swift
index 5514a635..a36aee6d 100644
--- a/Tusker/Screens/Preferences/PreferencesNavigationController.swift
+++ b/Tusker/Screens/Preferences/PreferencesNavigationController.swift
@@ -8,6 +8,7 @@
import UIKit
import SwiftUI
+import UserAccounts
class PreferencesNavigationController: UINavigationController {
@@ -64,7 +65,7 @@ class PreferencesNavigationController: UINavigationController {
guard let windowScene = self.view.window?.windowScene else {
return
}
- let account = notification.userInfo!["account"] as! LocalData.UserAccountInfo
+ let account = notification.userInfo!["account"] as! UserAccountInfo
if let sceneDelegate = windowScene.delegate as? MainSceneDelegate {
isSwitchingAccounts = true
dismiss(animated: true) { // dismiss preferences
@@ -85,8 +86,8 @@ class PreferencesNavigationController: UINavigationController {
sceneDelegate.logoutCurrent()
}
} else {
- LogoutService(accountInfo: LocalData.shared.getMostRecentAccount()!).run()
- let accountID = LocalData.shared.getMostRecentAccount()?.id
+ LogoutService(accountInfo: UserAccountsManager.shared.getMostRecentAccount()!).run()
+ let accountID = UserAccountsManager.shared.getMostRecentAccount()?.id
UIApplication.shared.requestSceneSessionActivation(nil, userActivity: UserActivityManager.mainSceneActivity(accountID: accountID), options: nil)
UIApplication.shared.requestSceneSessionDestruction(windowScene.session, options: nil)
}
@@ -95,7 +96,7 @@ class PreferencesNavigationController: UINavigationController {
}
extension PreferencesNavigationController: OnboardingViewControllerDelegate {
- func didFinishOnboarding(account: LocalData.UserAccountInfo) {
+ func didFinishOnboarding(account: UserAccountInfo) {
guard let windowScene = self.view.window?.windowScene else {
return
}
diff --git a/Tusker/Screens/Preferences/PreferencesView.swift b/Tusker/Screens/Preferences/PreferencesView.swift
index 049002e8..6ee2f61a 100644
--- a/Tusker/Screens/Preferences/PreferencesView.swift
+++ b/Tusker/Screens/Preferences/PreferencesView.swift
@@ -6,11 +6,12 @@
//
import SwiftUI
+import UserAccounts
struct PreferencesView: View {
let mastodonController: MastodonController
- @ObservedObject private var localData = LocalData.shared
+ @ObservedObject private var userAccounts = UserAccountsManager.shared
@State private var showingLogoutConfirmation = false
init(mastodonController: MastodonController) {
@@ -31,7 +32,7 @@ struct PreferencesView: View {
private var accountsSection: some View {
Section {
- ForEach(localData.accounts, id: \.accessToken) { (account) in
+ ForEach(userAccounts.accounts, id: \.accessToken) { (account) in
Button(action: {
NotificationCenter.default.post(name: .activateAccount, object: nil, userInfo: ["account": account])
}) {
@@ -58,12 +59,12 @@ struct PreferencesView: View {
}.onDelete { (indices: IndexSet) in
var indices = indices
var logoutFromCurrent = false
- if let index = indices.first(where: { localData.accounts[$0] == mastodonController.accountInfo! }) {
+ if let index = indices.first(where: { userAccounts.accounts[$0] == mastodonController.accountInfo! }) {
logoutFromCurrent = true
indices.remove(index)
}
- indices.forEach { LogoutService(accountInfo: localData.accounts[$0]).run() }
+ indices.forEach { LogoutService(accountInfo: userAccounts.accounts[$0]).run() }
if logoutFromCurrent {
self.logoutPressed()
diff --git a/Tusker/Shortcuts/UserActivityManager.swift b/Tusker/Shortcuts/UserActivityManager.swift
index 48fd88f1..eaa3eff0 100644
--- a/Tusker/Shortcuts/UserActivityManager.swift
+++ b/Tusker/Shortcuts/UserActivityManager.swift
@@ -10,6 +10,7 @@ import UIKit
import Intents
import Pachyderm
import OSLog
+import UserAccounts
private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "UserActivityManager")
@@ -32,11 +33,11 @@ class UserActivityManager {
scene.session.mastodonController!
}
- static func getAccount(from activity: NSUserActivity) -> LocalData.UserAccountInfo? {
+ static func getAccount(from activity: NSUserActivity) -> UserAccountInfo? {
guard let id = activity.userInfo?["accountID"] as? String else {
return nil
}
- return LocalData.shared.getAccount(id: id)
+ return UserAccountsManager.shared.getAccount(id: id)
}
// MARK: - Main Scene