krz/hutch

an ios client for sourcehut

clone: git clone https://gitbay.org/krz/hutch.git

v3.3.1: Hutch/Views/Auth/AuthView.swift · raw

  1import SwiftUI
  2
  3/// Token entry screen shown when the user is not authenticated.
  4struct TokenEntryView: View {
  5    private let createAccountURL = URL(string: "https://meta.sr.ht/register")!
  6    private let personalAccessTokensURL = URL(string: "https://meta.sr.ht/oauth2/personal-token")!
  7
  8    @Environment(AppState.self) private var appState
  9    @State private var token = ""
 10    @State private var isConnecting = false
 11    @State private var errorMessage: String?
 12
 13    var body: some View {
 14        NavigationStack {
 15            Form {
 16                Section {
 17                    Text("Enter your SourceHut personal access token to connect.")
 18                        .themedRow()
 19                } header: {
 20                    Text("Welcome to Hutch")
 21                } footer: {
 22                    Text("Hutch stores your SourceHut personal access token securely in the iOS keychain.")
 23                }
 24
 25                Section {
 26                    SecureField("Personal Access Token", text: $token)
 27                        .textContentType(.password)
 28                        .autocorrectionDisabled()
 29                        .textInputAutocapitalization(.never)
 30                        .disabled(isConnecting)
 31                        .themedRow()
 32                } header: {
 33                    Text("Token")
 34                }
 35
 36                if let errorMessage {
 37                    Section {
 38                        Label {
 39                            Text(errorMessage)
 40                        } icon: {
 41                            Image(systemName: "exclamationmark.triangle.fill")
 42                                .foregroundStyle(.red)
 43                        }
 44                        .foregroundStyle(.red)
 45                        .themedRow()
 46                    }
 47                }
 48
 49                Section {
 50                    Button {
 51                        connect()
 52                    } label: {
 53                        HStack {
 54                            Text("Connect")
 55                            if isConnecting {
 56                                Spacer()
 57                                ProgressView()
 58                            }
 59                        }
 60                    }
 61                    .disabled(tokenTrimmed.isEmpty || isConnecting)
 62                    .themedRow()
 63                }
 64
 65                Section {
 66                    Link(destination: createAccountURL) {
 67                        Label("Create SourceHut account", systemImage: "person.badge.plus")
 68                    }
 69                    .themedRow()
 70
 71                    Link(destination: personalAccessTokensURL) {
 72                        Label("Create Personal Access Token", systemImage: "key")
 73                    }
 74                    .themedRow()
 75                } header: {
 76                    Text("Need an account?")
 77                } footer: {
 78                    Text("These links open SourceHut in your browser. After signing up, create a Personal Access Token there and paste it here.")
 79                }
 80            }
 81            .themedList()
 82            .navigationTitle("Hutch")
 83        }
 84    }
 85
 86    private var tokenTrimmed: String {
 87        token.trimmingCharacters(in: .whitespacesAndNewlines)
 88    }
 89
 90    private func connect() {
 91        errorMessage = nil
 92        isConnecting = true
 93        Task {
 94            do {
 95                try await appState.connect(with: tokenTrimmed)
 96            } catch {
 97                errorMessage = error.userFacingMessage
 98            }
 99            isConnecting = false
100        }
101    }
102}