WIP - Complete App refactoring
This commit is contained in:
@@ -6,3 +6,40 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@Observable
|
||||
class AccountManager {
|
||||
var accounts: [any Account] = []
|
||||
var authTokens: [String: String] = [:]
|
||||
|
||||
/// Save account as JSON.
|
||||
func save(account: any Account, authToken: String?) async throws {
|
||||
account.saveTokenToKeychain(authToken!)
|
||||
let data = try JSONEncoder().encode(account)
|
||||
|
||||
let accountDir = account.accountType.rawValue + "/" + account.id.uuidString + "/account.json"
|
||||
await DataStore.shared.save(data: data, toPath: accountDir)
|
||||
}
|
||||
|
||||
/// Load accounts from JSON files.
|
||||
func loadAccounts() async throws {
|
||||
// Read data from file or user defaults
|
||||
for accountType in AccountType.allCases {
|
||||
// List all account UUIDs under the /accountType directory
|
||||
let accountUUIDs = DataStore.shared.listAllFolders(dir: accountType.rawValue + "/")
|
||||
|
||||
// Decode each account and fetch the authToken
|
||||
for accountUUID in accountUUIDs {
|
||||
do {
|
||||
guard let account = try await DataStore.shared.loadDynamic(fromPath: accountType.rawValue + "/" + accountUUID + "/account.json", type: accountType.accountType) else {
|
||||
continue
|
||||
}
|
||||
authTokens[accountUUID] = (account as! any Account).getTokenFromKeychain() ?? ""
|
||||
self.accounts.append(account as! (any Account))
|
||||
} catch {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,3 +6,44 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import KeychainSwift
|
||||
|
||||
|
||||
enum AccountType: String, Codable, CaseIterable {
|
||||
case cookbook = "cookbook"
|
||||
case local = "local"
|
||||
|
||||
var accountType: any Decodable.Type {
|
||||
switch self {
|
||||
case .cookbook: return CookbookAccount.self
|
||||
case .local: return LocalAccount.self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protocol Account: Codable, Identifiable {
|
||||
/// A unique identifier for this account
|
||||
var id: UUID { get }
|
||||
|
||||
/// A name for the account that can be displayed in the UI
|
||||
var displayName: String { get }
|
||||
|
||||
/// For differentiating account types when decoding
|
||||
var accountType: AccountType { get }
|
||||
|
||||
/// Base endpoint URL
|
||||
var baseURL: URL { get }
|
||||
|
||||
/// Account username
|
||||
var username: String { get }
|
||||
|
||||
/// For storing/retrieving tokens from Keychain
|
||||
func saveTokenToKeychain(_ token: String)
|
||||
func getTokenFromKeychain() -> String?
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// CookbookV1Account.swift
|
||||
// CookbookAccount.swift
|
||||
// Nextcloud Cookbook iOS Client
|
||||
//
|
||||
// Created by Vincent Meilinger on 24.01.25.
|
||||
@@ -10,9 +10,10 @@ import KeychainSwift
|
||||
|
||||
|
||||
struct CookbookAccount: Account {
|
||||
let accountType: AccountType = .cookbook
|
||||
|
||||
let id: UUID
|
||||
var displayName: String = "Nextcloud Cookbook Account"
|
||||
let accountType: AccountType = .cookbook
|
||||
|
||||
let baseURL: URL
|
||||
let username: String
|
||||
|
||||
@@ -6,3 +6,23 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
|
||||
struct LocalAccount: Account {
|
||||
let id: UUID
|
||||
var displayName: String = "Local Account"
|
||||
var accountType: AccountType = .local
|
||||
|
||||
let baseURL: URL = URL(filePath: "")!
|
||||
let username: String = ""
|
||||
|
||||
/// Keychain convenience
|
||||
func saveTokenToKeychain(_ token: String) {
|
||||
return
|
||||
}
|
||||
|
||||
func getTokenFromKeychain() -> String? {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user