| @@ -68,6 +68,9 @@ private struct SecretSetSheet: View { |
| 68 | 68 | |
| 69 | 69 | @State private var name = "" |
| 70 | 70 | @State private var value = "" |
| 71 | @State private var multiLine = false |
| 72 | /// Errors shown here are this sheet's own, not an earlier list action's. |
| 73 | @State private var attempted = false |
| 71 | 74 | |
| 72 | 75 | var body: some View { |
| 73 | 76 | NavigationStack { |
| @@ -78,14 +81,26 @@ private struct SecretSetSheet: View { |
| 78 | 81 | .autocorrectionDisabled() |
| 79 | 82 | .textInputAutocapitalization(.characters) |
| 80 | 83 | .accessibilityIdentifier("secret-name") |
| 81 | | SecureField("Value", text: $value) |
| 82 | | .autocorrectionDisabled() |
| 83 | | .textInputAutocapitalization(.never) |
| 84 | | .accessibilityIdentifier("secret-value") |
| 84 | if multiLine { |
| 85 | TextEditor(text: $value) |
| 86 | .frame(minHeight: 120) |
| 87 | .font(.gbMono(.caption)) |
| 88 | .autocorrectionDisabled() |
| 89 | .textInputAutocapitalization(.never) |
| 90 | .accessibilityIdentifier("secret-value-multiline") |
| 91 | } else { |
| 92 | SecureField("Value", text: $value) |
| 93 | .autocorrectionDisabled() |
| 94 | .textInputAutocapitalization(.never) |
| 95 | .accessibilityIdentifier("secret-value") |
| 96 | } |
| 97 | Toggle("Multi-line value", isOn: $multiLine) |
| 85 | 98 | } footer: { |
| 86 | | Text("Uppercase letters, digits and underscores. The value is sent once and cannot be read back.") |
| 99 | Text(multiLine |
| 100 | ? "Shown while you type, for a value with line breaks such as a private key. It is sent once and cannot be read back." |
| 101 | : "Uppercase letters, digits and underscores. The value is sent once and cannot be read back.") |
| 87 | 102 | } |
| 88 | | if let error = model.actionError { |
| 103 | if attempted, let error = model.actionError { |
| 89 | 104 | Section { GBNotice(error, .gbWarn) } |
| 90 | 105 | } |
| 91 | 106 | } |
| @@ -101,6 +116,7 @@ private struct SecretSetSheet: View { |
| 101 | 116 | } else { |
| 102 | 117 | Button("Set") { |
| 103 | 118 | Task { |
| 119 | attempted = true |
| 104 | 120 | guard await model.set(name: name, value: value) else { return } |
| 105 | 121 | // A secure field that still holds text as the sheet |
| 106 | 122 | // goes makes iOS offer to save it as a password. |
| @@ -222,6 +238,7 @@ private struct DeployKeyAddSheet: View { |
| 222 | 238 | @State private var text = "" |
| 223 | 239 | @State private var canPush = false |
| 224 | 240 | @State private var ttl: String? |
| 241 | @State private var attempted = false |
| 225 | 242 | |
| 226 | 243 | var body: some View { |
| 227 | 244 | NavigationStack { |
| @@ -246,7 +263,7 @@ private struct DeployKeyAddSheet: View { |
| 246 | 263 | Text("In a year").tag(String?.some("365d")) |
| 247 | 264 | } |
| 248 | 265 | } |
| 249 | | if let error = model.actionError { |
| 266 | if attempted, let error = model.actionError { |
| 250 | 267 | Section { GBNotice(error, .gbWarn) } |
| 251 | 268 | } |
| 252 | 269 | } |
| @@ -261,7 +278,10 @@ private struct DeployKeyAddSheet: View { |
| 261 | 278 | ProgressView() |
| 262 | 279 | } else { |
| 263 | 280 | Button("Add") { |
| 264 | | Task { if await model.add(publicKey: text, canPush: canPush, ttl: ttl) { onDone() } } |
| 281 | Task { |
| 282 | attempted = true |
| 283 | if await model.add(publicKey: text, canPush: canPush, ttl: ttl) { onDone() } |
| 284 | } |
| 265 | 285 | } |
| 266 | 286 | .disabled(text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty) |
| 267 | 287 | .accessibilityIdentifier("deploy-key-submit") |