diff options
| author | Christian Cleberg <[email protected]> | 2026-03-24 21:48:23 -0500 |
|---|---|---|
| committer | Christian Cleberg <[email protected]> | 2026-03-24 21:48:23 -0500 |
| commit | cf587aa0573ac4f34e1effe70108a9eca82093ac (patch) | |
| tree | 833e6f4961522e35b08af01b5f012983f8e34678 /Rune/ViewModels/SettingsViewModel.swift | |
| download | rune-1.0.0.tar.gz rune-1.0.0.tar.bz2 rune-1.0.0.zip | |
v1.0v1.0.0
Diffstat (limited to 'Rune/ViewModels/SettingsViewModel.swift')
| -rw-r--r-- | Rune/ViewModels/SettingsViewModel.swift | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/Rune/ViewModels/SettingsViewModel.swift b/Rune/ViewModels/SettingsViewModel.swift new file mode 100644 index 0000000..6b773eb --- /dev/null +++ b/Rune/ViewModels/SettingsViewModel.swift @@ -0,0 +1,102 @@ +import Combine +import Foundation + +@MainActor +final class SettingsViewModel: ObservableObject { + @Published private(set) var client: NjallaClient? + @Published private(set) var balance: WalletBalance? + @Published private(set) var isAuthenticated = false + @Published private(set) var isBootstrapped = false + @Published private(set) var isLoadingBalance = false + @Published var errorMessage: String? + + private let keychainManager = KeychainManager() + + var requiresOnboarding: Bool { + isBootstrapped && !isAuthenticated + } + + func bootstrap() async { + guard !isBootstrapped else { return } + + defer { + isBootstrapped = true + } + + do { + guard let token = try keychainManager.readToken(), !token.isEmpty else { + isAuthenticated = false + client = nil + balance = nil + return + } + + let client = NjallaClient(token: token) + self.client = client + isAuthenticated = true + try await refreshBalance() + } catch is CancellationError { + return + } catch { + if (error as? URLError)?.code == .cancelled { + return + } + errorMessage = error.localizedDescription + client = nil + balance = nil + isAuthenticated = false + } + } + + func login(token: String) async throws { + let trimmedToken = token.trimmingCharacters(in: .whitespacesAndNewlines) + let client = NjallaClient(token: trimmedToken) + let balance = try await client.getBalance() + try keychainManager.saveToken(trimmedToken) + + self.client = client + self.balance = balance + isAuthenticated = true + isBootstrapped = true + errorMessage = nil + } + + func refreshBalance() async throws { + guard let client else { return } + + isLoadingBalance = true + defer { + isLoadingBalance = false + } + + do { + balance = try await client.getBalance() + errorMessage = nil + } catch is CancellationError { + throw CancellationError() + } catch { + if (error as? URLError)?.code == .cancelled { + throw error + } + errorMessage = error.localizedDescription + throw error + } + } + + func logout() throws { + try keychainManager.deleteToken() + client = nil + balance = nil + isAuthenticated = false + errorMessage = nil + } + + func logoutIfCurrentTokenDeleted(_ key: String) throws -> Bool { + guard let storedToken = try keychainManager.readToken(), storedToken == key else { + return false + } + + try logout() + return true + } +} |
