| 1 | import SwiftUI |
| 2 | |
| 3 | @MainActor public struct NativeSignInView: View { |
| 4 | @ObservedObject private var connection: NativeConnection |
| 5 | private let name: String |
| 6 | private let symbol: String |
| 7 | @Environment(\.openURL) private var openURL |
| 8 | |
| 9 | public init(_ name: String, systemImage: String, connection: NativeConnection) { |
| 10 | self.name = name |
| 11 | symbol = systemImage |
| 12 | self.connection = connection |
| 13 | } |
| 14 | public var body: some View { |
| 15 | ScrollView { |
| 16 | VStack(alignment: .leading, spacing: 24) { |
| 17 | Image(systemName: symbol).font(.largeTitle).foregroundStyle(.tint) |
| 18 | .padding(18).background(.tint.opacity(0.1), in: RoundedRectangle(cornerRadius: 20)) |
| 19 | .accessibilityHidden(true) |
| 20 | Text(name).font(.largeTitle.bold()) |
| 21 | Text("Your team, wherever you work.").foregroundStyle(.secondary) |
| 22 | if connection.signingIn { |
| 23 | ProgressView("Finish signing in in your browser") |
| 24 | Text(connection.code).font(.title.monospaced().bold()).textSelection(.enabled) |
| 25 | Text("Compare this code with the one in your browser before approving sign-in.") |
| 26 | .foregroundStyle(.secondary) |
| 27 | |
| 28 | Button("Cancel") { connection.cancel() } |
| 29 | } else { |
| 30 | VStack(alignment: .leading, spacing: 8) { |
| 31 | Text("Server address").font(.headline) |
| 32 | TextField("https://your-server", text: $connection.serverAddress) |
| 33 | .textFieldStyle(.roundedBorder).accessibilityIdentifier("serverAddress") |
| 34 | #if os(iOS) |
| 35 | .keyboardType(.URL).textInputAutocapitalization(.never).autocorrectionDisabled() |
| 36 | #endif |
| 37 | .onSubmit(signIn) |
| 38 | } |
| 39 | TextField("Account name (optional)", text: $connection.accountName) |
| 40 | .textFieldStyle(.roundedBorder) |
| 41 | Button("Sign in", systemImage: "arrow.right", action: signIn) |
| 42 | .buttonStyle(.borderedProminent).keyboardShortcut(.defaultAction) |
| 43 | } |
| 44 | if !connection.error.isEmpty { |
| 45 | Label(connection.error, systemImage: "exclamationmark.circle") |
| 46 | .foregroundStyle(.red).fixedSize(horizontal: false, vertical: true) |
| 47 | } |
| 48 | }.controlSize(.large).frame(maxWidth: 440, alignment: .leading).padding(32) |
| 49 | .frame(maxWidth: .infinity) |
| 50 | } |
| 51 | } |
| 52 | private func signIn() { connection.signIn() } |
| 53 | } |
| 54 | |