diff options
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 + } +} |
