summaryrefslogtreecommitdiff
path: root/Hutch/Views/Auth/AuthView.swift
diff options
context:
space:
mode:
authorChristian Cleberg <[email protected]>2026-03-17 23:19:43 -0500
committerChristian Cleberg <[email protected]>2026-03-17 23:19:43 -0500
commit32ad6cab8d58d99ebd8a28e8fa6e6f4e587cb1e5 (patch)
treeee36d421d704e508d5617d803b4c8cbdb4804fe1 /Hutch/Views/Auth/AuthView.swift
parent8f2057c53e9009c2529c9c4849c914666c0e4b40 (diff)
downloadhutch-32ad6cab8d58d99ebd8a28e8fa6e6f4e587cb1e5.tar.gz
hutch-32ad6cab8d58d99ebd8a28e8fa6e6f4e587cb1e5.tar.bz2
hutch-32ad6cab8d58d99ebd8a28e8fa6e6f4e587cb1e5.zip
v1.0
Diffstat (limited to 'Hutch/Views/Auth/AuthView.swift')
-rw-r--r--Hutch/Views/Auth/AuthView.swift95
1 files changed, 95 insertions, 0 deletions
diff --git a/Hutch/Views/Auth/AuthView.swift b/Hutch/Views/Auth/AuthView.swift
new file mode 100644
index 0000000..cbf8669
--- /dev/null
+++ b/Hutch/Views/Auth/AuthView.swift
@@ -0,0 +1,95 @@
+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/oauth/personal-access-tokens")!
+
+ @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.")
+ } 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)
+ } header: {
+ Text("Token")
+ }
+
+ if let errorMessage {
+ Section {
+ Label {
+ Text(errorMessage)
+ } icon: {
+ Image(systemName: "exclamationmark.triangle.fill")
+ .foregroundStyle(.red)
+ }
+ .foregroundStyle(.red)
+ }
+ }
+
+ Section {
+ Button {
+ connect()
+ } label: {
+ HStack {
+ Text("Connect")
+ if isConnecting {
+ Spacer()
+ ProgressView()
+ }
+ }
+ }
+ .disabled(tokenTrimmed.isEmpty || isConnecting)
+ }
+
+ Section {
+ Link(destination: createAccountURL) {
+ Label("Create SourceHut account", systemImage: "person.badge.plus")
+ }
+
+ Link(destination: personalAccessTokensURL) {
+ Label("Create Personal Access Token", systemImage: "key")
+ }
+ } 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.")
+ }
+ }
+ .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.localizedDescription
+ }
+ isConnecting = false
+ }
+ }
+}