forked from shadowfacts/Tusker
Onboarding view controller needs to set the account info object on the mastodon controller before calling getOwnAccount since getOwnAccount will upsert the user's account into the persistent container, which requires the account info to exist to create a unique-per-account identifier.
158 lines
5.2 KiB
Swift
158 lines
5.2 KiB
Swift
//
|
|
// LocalData.swift
|
|
// Tusker
|
|
//
|
|
// Created by Shadowfacts on 8/18/18.
|
|
// Copyright © 2018 Shadowfacts. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import Combine
|
|
|
|
class LocalData: ObservableObject {
|
|
|
|
static let shared = LocalData()
|
|
|
|
let defaults: UserDefaults
|
|
|
|
private init() {
|
|
if ProcessInfo.processInfo.environment.keys.contains("UI_TESTING") {
|
|
defaults = UserDefaults(suiteName: "\(Bundle.main.bundleIdentifier!).uitesting")!
|
|
if ProcessInfo.processInfo.environment.keys.contains("UI_TESTING_LOGIN") {
|
|
accounts = [
|
|
UserAccountInfo(
|
|
id: UUID().uuidString,
|
|
instanceURL: URL(string: "http://localhost:8080")!,
|
|
clientID: "client_id",
|
|
clientSecret: "client_secret",
|
|
username: "admin",
|
|
accessToken: "access_token")
|
|
]
|
|
}
|
|
} else {
|
|
defaults = UserDefaults()
|
|
}
|
|
}
|
|
|
|
private let accountsKey = "accounts"
|
|
var accounts: [UserAccountInfo] {
|
|
get {
|
|
if let array = defaults.array(forKey: accountsKey) as? [[String: String]] {
|
|
return array.compactMap { (info) in
|
|
guard let id = info["id"],
|
|
let instanceURL = info["instanceURL"],
|
|
let url = URL(string: instanceURL),
|
|
let clientId = info["clientID"],
|
|
let secret = info["clientSecret"],
|
|
let accessToken = info["accessToken"] else {
|
|
return nil
|
|
}
|
|
return UserAccountInfo(id: id, instanceURL: url, clientID: clientId, clientSecret: secret, username: info["username"], accessToken: accessToken)
|
|
}
|
|
} else {
|
|
return []
|
|
}
|
|
}
|
|
set {
|
|
objectWillChange.send()
|
|
let array = newValue.map { (info) -> [String: String] in
|
|
var res = [
|
|
"id": info.id,
|
|
"instanceURL": info.instanceURL.absoluteString,
|
|
"clientID": info.clientID,
|
|
"clientSecret": info.clientSecret,
|
|
"accessToken": info.accessToken
|
|
]
|
|
if let username = info.username {
|
|
res["username"] = username
|
|
}
|
|
return res
|
|
}
|
|
defaults.set(array, forKey: accountsKey)
|
|
}
|
|
}
|
|
|
|
private let mostRecentAccountKey = "mostRecentAccount"
|
|
private var mostRecentAccount: String? {
|
|
get {
|
|
return defaults.string(forKey: mostRecentAccountKey)
|
|
}
|
|
set {
|
|
objectWillChange.send()
|
|
defaults.set(newValue, forKey: mostRecentAccountKey)
|
|
}
|
|
}
|
|
|
|
var onboardingComplete: Bool {
|
|
return !accounts.isEmpty
|
|
}
|
|
|
|
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)
|
|
}
|
|
let id = UUID().uuidString
|
|
let info = UserAccountInfo(id: id, instanceURL: url, clientID: clientID, clientSecret: secret, username: username, accessToken: accessToken)
|
|
accounts.append(info)
|
|
self.accounts = accounts
|
|
return info
|
|
}
|
|
|
|
func setUsername(for info: UserAccountInfo, username: String) {
|
|
var info = info
|
|
info.username = username
|
|
removeAccount(info)
|
|
accounts.append(info)
|
|
}
|
|
|
|
func removeAccount(_ info: UserAccountInfo) {
|
|
accounts.removeAll(where: { $0.id == info.id })
|
|
}
|
|
|
|
func getAccount(id: String) -> UserAccountInfo? {
|
|
return accounts.first(where: { $0.id == id })
|
|
}
|
|
|
|
func getMostRecentAccount() -> UserAccountInfo? {
|
|
guard onboardingComplete else { return nil }
|
|
let mostRecent: UserAccountInfo?
|
|
if let id = mostRecentAccount {
|
|
mostRecent = accounts.first { $0.id == id }
|
|
} else {
|
|
mostRecent = nil
|
|
}
|
|
return mostRecent ?? accounts.first!
|
|
}
|
|
|
|
func setMostRecentAccount(_ account: UserAccountInfo?) {
|
|
mostRecentAccount = account?.id
|
|
}
|
|
|
|
}
|
|
|
|
extension LocalData {
|
|
struct UserAccountInfo: Equatable, Hashable {
|
|
let id: String
|
|
let instanceURL: URL
|
|
let clientID: String
|
|
let clientSecret: String
|
|
fileprivate(set) var username: String!
|
|
let accessToken: String
|
|
|
|
func hash(into hasher: inout Hasher) {
|
|
hasher.combine(id)
|
|
}
|
|
|
|
static func ==(lhs: UserAccountInfo, rhs: UserAccountInfo) -> Bool {
|
|
return lhs.id == rhs.id
|
|
}
|
|
}
|
|
}
|
|
|
|
extension Notification.Name {
|
|
static let userLoggedOut = Notification.Name("Tusker.userLoggedOut")
|
|
static let addAccount = Notification.Name("Tusker.addAccount")
|
|
static let activateAccount = Notification.Name("Tusker.activateAccount")
|
|
}
|