summaryrefslogtreecommitdiff
path: root/makima/ios/Sources/Makima/App/AppState.swift
blob: 1cc6788f20323e99c70ea845cea47727a5ffe896 (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
import SwiftUI
import Combine

@MainActor
@Observable
final class AppState {
    let auth: AuthStore
    var wsStatus: WebSocketStatus = .idle
    var webSocket: TaskWebSocket?
    var pendingDeepLink: DeepLink?

    init(auth: AuthStore = AuthStore()) {
        self.auth = auth

        if ScreenshotMode.isEnabled {
            auth.seedScreenshotData()
        }
    }

    func ensureWebSocket() {
        guard !ScreenshotMode.isEnabled else {
            wsStatus = .online
            return
        }
        guard webSocket == nil, let client = auth.client else { return }
        let ws = TaskWebSocket(profile: client.profile, apiKey: client.apiKey)
        ws.onStatusChange = { [weak self] s in Task { @MainActor in self?.wsStatus = s } }
        ws.connect()
        webSocket = ws
    }

    func teardownWebSocket() {
        webSocket?.disconnect()
        webSocket = nil
        wsStatus = .idle
    }
}

enum DeepLink: Hashable {
    case task(id: String)
    case directive(id: String)
    case contract(id: String)

    init?(url: URL) {
        guard url.scheme == "makima", let host = url.host else { return nil }
        let id = url.pathComponents.dropFirst().first ?? ""
        guard !id.isEmpty else { return nil }
        switch host {
        case "task":      self = .task(id: id)
        case "directive": self = .directive(id: id)
        case "contract":  self = .contract(id: id)
        default:          return nil
        }
    }
}