summaryrefslogtreecommitdiff
path: root/Rune/ViewModels/SettingsViewModel.swift
blob: 6b773eb1421aadbc3ea2adaee6ec9dc5d258d07c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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
    }
}