forked from shadowfacts/Tusker
Move local user accounts to separate package
This commit is contained in:
parent
5471d810c8
commit
247bb31c56
7
Packages/ComposeUI/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
Packages/ComposeUI/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
generated
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
|
@ -0,0 +1,9 @@
|
|||
.DS_Store
|
||||
/.build
|
||||
/Packages
|
||||
/*.xcodeproj
|
||||
xcuserdata/
|
||||
DerivedData/
|
||||
.swiftpm/config/registries.json
|
||||
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
||||
.netrc
|
|
@ -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
|
||||
}
|
|
@ -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"]),
|
||||
]
|
||||
)
|
|
@ -0,0 +1,3 @@
|
|||
# UserAccounts
|
||||
|
||||
A description of this package.
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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")
|
|
@ -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 = "<group>"; };
|
||||
D64BC18D23C18B9D000D0238 /* FollowRequestNotificationTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowRequestNotificationTableViewCell.swift; sourceTree = "<group>"; };
|
||||
D64BC18E23C18B9D000D0238 /* FollowRequestNotificationTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FollowRequestNotificationTableViewCell.xib; sourceTree = "<group>"; };
|
||||
D64D0AAC2128D88B005A6F37 /* LocalData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalData.swift; sourceTree = "<group>"; };
|
||||
D64D0AB02128D9AE005A6F37 /* OnboardingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewController.swift; sourceTree = "<group>"; };
|
||||
D64D8CA82463B494006B0BAA /* MultiThreadDictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiThreadDictionary.swift; sourceTree = "<group>"; };
|
||||
D651C5B32915B00400236EF6 /* ProfileFieldsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileFieldsView.swift; sourceTree = "<group>"; };
|
||||
|
@ -688,6 +687,7 @@
|
|||
D6ADB6EF28ED1F25009924AB /* CachedImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CachedImageView.swift; sourceTree = "<group>"; };
|
||||
D6AEBB3D2321638100E5038B /* UIActivity+Types.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIActivity+Types.swift"; sourceTree = "<group>"; };
|
||||
D6AEBB422321685E00E5038B /* OpenInSafariActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenInSafariActivity.swift; sourceTree = "<group>"; };
|
||||
D6B0026C29B5245400C70BE2 /* UserAccounts */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = UserAccounts; path = Packages/UserAccounts; sourceTree = "<group>"; };
|
||||
D6B053A123BD2C0600A066FA /* AssetPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetPickerViewController.swift; sourceTree = "<group>"; };
|
||||
D6B053A323BD2C8100A066FA /* AssetCollectionsListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetCollectionsListViewController.swift; sourceTree = "<group>"; };
|
||||
D6B053A523BD2D0C00A066FA /* AssetCollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetCollectionViewController.swift; sourceTree = "<group>"; };
|
||||
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<AccountPreferences> {
|
||||
@nonobjc class func fetchRequest(account: UserAccountInfo) -> NSFetchRequest<AccountPreferences> {
|
||||
let req = NSFetchRequest<AccountPreferences>(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()
|
||||
|
|
|
@ -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<String, Never>()
|
||||
let relationshipSubject = PassthroughSubject<String, Never>()
|
||||
|
||||
init(for accountInfo: LocalData.UserAccountInfo?, transient: Bool = false) {
|
||||
init(for accountInfo: UserAccountInfo?, transient: Bool = false) {
|
||||
self.accountInfo = accountInfo
|
||||
|
||||
let group = DispatchGroup()
|
||||
|
|
|
@ -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<SavedHashtag>(entityName: "SavedHashtag")
|
||||
}
|
||||
|
||||
@nonobjc class func fetchRequest(account: LocalData.UserAccountInfo) -> NSFetchRequest<SavedHashtag> {
|
||||
@nonobjc class func fetchRequest(account: UserAccountInfo) -> NSFetchRequest<SavedHashtag> {
|
||||
let req = NSFetchRequest<SavedHashtag>(entityName: "SavedHashtag")
|
||||
req.predicate = NSPredicate(format: "accountID = %@", account.id)
|
||||
return req
|
||||
}
|
||||
|
||||
@nonobjc class func fetchRequest(name: String, account: LocalData.UserAccountInfo) -> NSFetchRequest<SavedHashtag> {
|
||||
@nonobjc class func fetchRequest(name: String, account: UserAccountInfo) -> NSFetchRequest<SavedHashtag> {
|
||||
let req = NSFetchRequest<SavedHashtag>(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
|
||||
|
|
|
@ -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<SavedInstance>(entityName: "SavedInstance")
|
||||
}
|
||||
|
||||
@nonobjc class func fetchRequest(account: LocalData.UserAccountInfo) -> NSFetchRequest<SavedInstance> {
|
||||
@nonobjc class func fetchRequest(account: UserAccountInfo) -> NSFetchRequest<SavedInstance> {
|
||||
let req = NSFetchRequest<SavedInstance>(entityName: "SavedInstance")
|
||||
req.predicate = NSPredicate(format: "accountID = %@", account.id)
|
||||
return req
|
||||
}
|
||||
|
||||
@nonobjc class func fetchRequest(url: URL, account: LocalData.UserAccountInfo) -> NSFetchRequest<SavedInstance> {
|
||||
@nonobjc class func fetchRequest(url: URL, account: UserAccountInfo) -> NSFetchRequest<SavedInstance> {
|
||||
let req = NSFetchRequest<SavedInstance>(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
|
||||
|
|
|
@ -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<TimelinePosition> {
|
||||
@nonobjc class func fetchRequest(timeline: Timeline, account: UserAccountInfo) -> NSFetchRequest<TimelinePosition> {
|
||||
let req = NSFetchRequest<TimelinePosition>(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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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!)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue