Files
meterios/common/AccountManager.swift

113 lines
3.5 KiB
Swift

//
// AccountManager.swift
// meterios
//
// (c) 2025 Martin "maride" Dessauer
//
import Foundation
import SwiftUI
import OSLog
/// **AccountManager** holds multiple accounts and takes care of storing them on the device.
@Observable class AccountManager {
// default contains a ready-to-use instance of AccountManager, read from AppStorage
static public var `default` = AccountManager()
// accounts holds all saved accounts
private(set) var Accounts: Array<Account> = [] { didSet { writeToRaw() } }
private var selectedAccount: Int? { didSet { writeToRaw() } }
// init creates a new AccountManager, reading saved account data from AppStorage
init() {
self.Accounts = AccountManager.readFromRaw()
// Read account selection
@AppStorage("selectedAccount") var selectedAccount: Int?
self.selectedAccount = selectedAccount
}
// readFromRaw reads the current accounts from the stored data and transforms it to a handy Account Array
static private func readFromRaw() -> Array<Account> {
@AppStorage("accounts") var rawAccs = Data()
do {
return try JSONDecoder().decode([Account].self, from: rawAccs)
} catch {
let _ = Logger().error("Error parsing stored accounts from JSON: \(error)")
rawAccs = Data()
return []
}
}
// writeToRaw writes the current account data to the AppStorage
private func writeToRaw() {
@AppStorage("accounts") var rawAccs = Data()
do {
rawAccs = try JSONEncoder().encode(Accounts)
} catch {
let _ = Logger().error("Error writing current accounts to JSON: \(error)")
}
}
// CurrentAccount returns the currently selected account if there is one
func CurrentAccount() -> Account? {
if selectedAccount == nil {
return nil
}
if Accounts.count > selectedAccount! {
return Accounts[selectedAccount!]
}
return nil
}
// SelectAccount sets the current main account as returned by CurrentAccount
func SelectAccount(_ account: Account) {
SelectAccount(IndexOfAccount(account))
}
// SelectAccount sets the current main account as returned by CurrentAccount
func SelectAccount(_ accountID: Int?) {
self.selectedAccount = accountID
// Store account selection
@AppStorage("selectedAccount") var selectedAccount: Int?
selectedAccount = self.selectedAccount
}
// AddAccount adds the given account if it doesn't exist yet
func AddAccount(_ account: Account) {
if IndexOfAccount(account) == nil {
Accounts.append(account)
}
}
// IndexOfAccount returns the index of the specified account identified by address and user ID
func IndexOfAccount(_ account: Account) -> Int? {
return Accounts.firstIndex(where: {
$0.address == account.address &&
$0.userID == account.userID
})
}
// RemoveAccount removes the specified account
func RemoveAccount(_ account: Account) {
if IndexOfAccount(account) != nil {
RemoveAccount(IndexOfAccount(account)!)
}
}
// RemoveAccount removes the account at the specified index
func RemoveAccount(_ index: Int) {
Accounts.remove(at: index)
}
// RefreshAll refreshes all accounts held by this manager instance
func RefreshAll() async {
for acc in Accounts {
await acc.Refresh()
}
}
}