View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0011963 | Taler | wallet (iOS App) | public | 2026-11-07 21:27 | 2026-11-07 21:27 |
| Reporter | bot-cg [agent] | Assigned To | Resolution deadline | ||
| Implementer | Reviewer | ||||
| Release signed by | Deployed by | ||||
| Verifier | Communicator | CM_7 | |||
| Data protection authority notification required | No | ||||
| CSIRT notification required | No | ||||
| Estimated effort (hours) | Actual effort (hours) | 0 | |||
| Fast-track | No | ||||
| Work package | none | ||||
| Priority | normal | Severity | minor | Reproducibility | have not tried |
| Status | new | Resolution | open | ||
| Summary | 0011963: Add bank account: the Add button stays disabled when only the IBAN is filled in, with no hint why, and a failed save is silent | ||||
| Description | Adding a bank account can get stuck with no feedback at all. Three things in TalerWallet1/Views/Settings/Bank/BankEditView.swift combine: **1. The IBAN field does not clear `unchanged`, so Add stays disabled.** Line 73: `.disabled(disabled || notValid || unchanged)`. `unchanged` starts `true` (line 42) and is cleared in exactly three places -- `onChange(of: accountLabel)` (lines 195-199), `onChange(of: accountHolder)` (lines 217-221) and `onChange(of: xTaler)` (lines 265-271) -- each guarded by `if userTyped`, and `userTyped` is set only by a focus change (lines 296-303). The IBAN field's own `onChange` (lines 253-260) only starts the `model.validateIban` task; it never touches `unchanged`. So a user who fills in just the IBAN -- the one field the button's own validation (`notValid = iban.isEmpty || !ibanValid`) is about -- sees Add stay greyed out permanently, with nothing on screen saying what is missing. The button has no accessibility hint and there is no inline validation text. **2. When the save does run and fails, nothing is shown.** `updateAccount()` (lines 104-...) returns `false` without any user-visible effect unless *both* `accountHolder` and `accountLabel` are non-empty (line 106). On the failure paths it sets `showAlert = true` (e.g. line 127, after a payto URI that cannot be assembled) -- but `showAlert` is declared at line 32 and **bound to no `.alert` modifier anywhere in the file**. The flag is written and never read. `symLog.log("error addBankAccount")` (line 136) is the only trace, which the user cannot see. **3. A dead accessibility label.** Minor, same screen: lines 65-67 compute `a11yStr` as "Add bank account" / "Update bank account", but `DoneButton(titleStr:accessibilityLabelStr:)` is called with `titleStr` for both arguments (line 70), so the computed label is never used and the button is announced as just "Add". Found while writing a deterministic UI test for this flow: the test filled the IBAN, waited for the button to become enabled, and timed out. The field order turns out to be load-bearing in a way nothing on the screen indicates. | ||||
| Steps To Reproduce | 1. Settings -> Bank Accounts -> + (add). 2. Leave "Label" and "Account holder" empty and type a valid IBAN into the IBAN field, e.g. CH9300762011623852957. Observed: "Add" stays disabled indefinitely, with no indication of what is missing. Filling in "Label" (or "Account holder") afterwards enables it. 3. For the silent-failure part: reach any `updateAccount()` failure path -- e.g. an account holder string that makes `URLComponents.string` nil, or a wallet-core `addBankAccount` rejection. Observed: the view stays as it is, no alert, no error text. `showAlert` is set but no `.alert` is attached to it. Expected: either the button is enabled once the form is actually valid (all three fields participating in the enabled state), or the screen says which field is still required -- and a failed save reports something. | ||||
| Additional Information | Suggested fix: * Let the IBAN/xTaler field participate in `unchanged` like the other two (clear it in the IBAN `onChange` as well), or -- better -- drop `unchanged` from the `.disabled` expression for a *new* account, where "unchanged" is not a meaningful state, and compute validity from the fields the save actually requires: label, holder and the payto target. * Add an `.accessibilityHint` (and ideally visible helper text) naming the missing field while the button is disabled. The same codebase does this elsewhere -- e.g. the P2P subject screen's "enabled when subject and expiration are set". * Bind `showAlert` to an `.alert`, or remove it and report the error some other way. As it stands the failure is invisible to the user and to a test. * Pass `a11yStr` to `DoneButton`'s `accessibilityLabelStr` parameter, which is presumably what lines 65-67 intended. Severity is a judgment call: nothing is lost or corrupted, but the screen can reach a state where the user cannot proceed and is told nothing, which is how it presented. | ||||
| Tags | No tags attached. | ||||
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2026-11-07 21:27 | bot-cg | New Issue |