blob: 91534b04ab15ba8c733265b09134b65cb0616702 (
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 SwiftUI
/// Token entry screen shown when the user is not authenticated.
struct TokenEntryView: View {
private let createAccountURL = URL(string: "https://meta.sr.ht/register")!
private let personalAccessTokensURL = URL(string: "https://meta.sr.ht/oauth2/personal-token")!
@Environment(AppState.self) private var appState
@State private var token = ""
@State private var isConnecting = false
@State private var errorMessage: String?
var body: some View {
NavigationStack {
Form {
Section {
Text("Enter your SourceHut personal access token to connect.")
.themedRow()
} header: {
Text("Welcome to Hutch")
} footer: {
Text("Hutch stores your SourceHut personal access token securely in the iOS keychain.")
}
Section {
SecureField("Personal Access Token", text: $token)
.textContentType(.password)
.autocorrectionDisabled()
.textInputAutocapitalization(.never)
.disabled(isConnecting)
.themedRow()
} header: {
Text("Token")
}
if let errorMessage {
Section {
Label {
Text(errorMessage)
} icon: {
Image(systemName: "exclamationmark.triangle.fill")
.foregroundStyle(.red)
}
.foregroundStyle(.red)
.themedRow()
}
}
Section {
Button {
connect()
} label: {
HStack {
Text("Connect")
if isConnecting {
Spacer()
ProgressView()
}
}
}
.disabled(tokenTrimmed.isEmpty || isConnecting)
.themedRow()
}
Section {
Link(destination: createAccountURL) {
Label("Create SourceHut account", systemImage: "person.badge.plus")
}
.themedRow()
Link(destination: personalAccessTokensURL) {
Label("Create Personal Access Token", systemImage: "key")
}
.themedRow()
} header: {
Text("Need an account?")
} footer: {
Text("These links open SourceHut in your browser. After signing up, create a Personal Access Token there and paste it here.")
}
}
.themedList()
.navigationTitle("Hutch")
}
}
private var tokenTrimmed: String {
token.trimmingCharacters(in: .whitespacesAndNewlines)
}
private func connect() {
errorMessage = nil
isConnecting = true
Task {
do {
try await appState.connect(with: tokenTrimmed)
} catch {
errorMessage = error.userFacingMessage
}
isConnecting = false
}
}
}
|