uttrflow / uttrflow/uttrflow-swift

VoiceOver reads shortcut rows by their code names ("pasteLastTranscript shortcut") and never hears that the field is recording

Open Beginner friendly
#684 0 comments 0 reactions 0 assignees View on GitHub
accessibility area:general bug good first issue P2
Dominant language
Swift
Stars
4
Forks
17
Avg merge
3h 32m
Merged PRs (30d)
277

Description

## What happens

Each shortcut row in Settings → General is a `SettingsShortcutField`, whose accessibility label is built from the enum's raw value:

```swift
// Sources/Uttrflow/Settings/SettingsControlView.swift:222-224
.accessibilityElement(children: .contain)
.accessibilityLabel("\(action.rawValue) shortcut, \(keys.joined(separator: " "))")
```

`ShortcutAction`'s raw values are `dictate`, `clipboard`, `pasteLastTranscript` and `copyLastTranscript` (`Sources/UttrflowCore/Keyboard/ShortcutAction.swift:4-13`). So VoiceOver reads "pasteLastTranscript shortcut, ⌃ ⌘ V" (spoken as one run-together word), while the visible label is "Paste last transcript" (`Sources/UttrflowUX/ShortcutRegistry.swift:41`).

Two more gaps in the same label:

- A shortcut with nothing bound draws "None" (`SettingsControlView.swift:201-204`), but the label ends "shortcut, " with nothing after it.
- While recording, the row shows "Press the new shortcut" (`SettingsShortcutRecorder.prompt`) and the Change button becomes Cancel, but the label still reads the old keys, so a VoiceOver user is not told the field is listening or that Escape cancels.

## Why it matters

Changing a shortcut is one of the first things a keyboard or VoiceOver user does. They hear code identifiers instead of the names on screen, and no feedback when the field starts listening.

## How to reproduce

Open Settings → General with VoiceOver on and move to the shortcut rows. Or read line 224.

## Acceptance criteria

- The label uses `ShortcutRegistry.label(for: action)`: "Paste last transcript shortcut, Control Command V" or similar.
- With nothing bound it reads "…shortcut, none".
- While recording it reads "…shortcut, press the new shortcut, or Escape to cancel", and the change is announced when recording starts.
- Modifier glyphs are read as words if VoiceOver does not already speak them (check with VoiceOver; the onboarding keycaps have the same question).
- If practical, move the label text into `UttrflowUX` (for example a static on `SettingsShortcut`) so a test in `Tests/UttrflowUXTests/SettingsShortcutTests.swift` can cover all three states.

## Where to start

- `Sources/Uttrflow/Settings/SettingsControlView.swift:180-225`.
- Run `make verify` (export `DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer` first) and read CONTRIBUTING.md.

**Size:** S, about 1–2 hours.

Contributor guide

Open the contributing guide

Research direction

Start in Sources/Uttrflow/Settings/SettingsControlView.swift:180-225 and compare the current label with ShortcutRegistry.label(for: action), SettingsShortcutRecorder.prompt, and the bound-key states. Check whether the label can move into SettingsShortcut and cover it in Tests/UttrflowUXTests/SettingsShortcutTests.swift. Run the relevant tests or make verify, then confirm VoiceOver announces the friendly name, none state, and recording/cancel state.

Written by the indexing model from the issue text.

Assessment

Tech stack
macos, swift
Domain
accessibility, desktop
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
84/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.