Skip to content

feat(speakers): play/pause toggle, 3-dot overflow menu, name autocomplete#1136

Draft
r3dbars wants to merge 2 commits into
mainfrom
feat/speakers-ux-playpause-menu-autocomplete
Draft

feat(speakers): play/pause toggle, 3-dot overflow menu, name autocomplete#1136
r3dbars wants to merge 2 commits into
mainfrom
feat/speakers-ux-playpause-menu-autocomplete

Conversation

@r3dbars

@r3dbars r3dbars commented Jun 16, 2026

Copy link
Copy Markdown
Owner

Scope

Speakers settings screen only (header Speakers / "Name new voices and manage the people in your meetings" / "N voices to name"). No Home/meeting surfaces touched — that area belongs to #1134.

All changes live in the voice-to-name rows of Sources/UI/Settings/SpeakerPeopleSettingsSection.swift plus three new files.

Changes

1. Play/pause toggle with a clear active state

  • The circular play button renders through a new pure SpeakerClipPlaybackPresentation (play ⇄ pause glyph) and gains an accent ring while playing; the whole row gets a subtle accent highlight so the playing clip is obvious among many.
  • Only one clip plays at a time, and the button returns to play on finish — both already guaranteed by SpeakerClipPlayback (stops the prior sound on a new clip; posts a state-change notification every row observes).

2. Three-dots overflow menu (replaces the bare transcript icon)

  • After Save Name, an ellipsis menu with:
    • Show transcript — same reveal the old doc.text icon did (openTranscript).
    • Delete voice — wired to the real SpeakerDatabase.deleteSpeaker path via model.deleteVoice, behind a destructive confirmation. The delete is verified (getSpeaker(id:) == nil) and surfaces an error in-row if it didn't actually remove the voice — never a silent no-op.

3. Autocomplete in the "Who is this?" field

  • New SpeakerNameAutocompleteField wraps NSComboBox and reuses the existing SpeakerNameSelectionPolicy (the same matching/inline-completion the post-meeting SpeakerNamingSheet uses).
  • Suggestions are built from named profiles by the pure SpeakerNameSuggestionSource (excludes the voice being named and unnamed/blank profiles).

Tests

  • New Tests/SpeakerVoiceRowPresentationTests.swift (8 suites): play/pause state machine, active-highlight rule, a11y/help copy, overflow-menu action ordering + destructive flag, delete-never-silent error mapping, and the autocomplete data source (incl. reuse of SpeakerNameSelectionPolicy inline completion).
  • Wired into Tests/FastTests.manifest + run-tests.sh APP_SOURCES.
  • bash run-tests.sh5439/5439 pass. bash build.sh --no-open → clean, perf budget OK.

Manual click-test still needed (real-app UI behaviors)

  • Play one clip → button shows pause + row highlights; start a second → first resets to play; let a clip finish → returns to play.
  • Overflow → Show transcript opens the originating meeting; Delete voice confirms, removes the voice, refreshes the list; force a failure (e.g. locked DB) → in-row error shows.
  • Type in Who is this? → suggestions + inline completion match existing speaker names; selecting a decorated label stores the plain name; Enter saves.

Peer / collision notes

🤖 Generated with Claude Code

r3dbars and others added 2 commits June 15, 2026 21:47
Three UX changes scoped to the Speakers settings screen's "N voices to
name" rows (SpeakerVoiceToNameRow):

1. Play/pause toggle with a clear active state. The circular button now
   renders through SpeakerClipPlaybackPresentation (pause glyph + accent
   ring while playing) and the whole row gets a subtle accent highlight,
   so with many clips the playing one is unambiguous. One-clip-at-a-time
   and finish->reset are already guaranteed by SpeakerClipPlayback.

2. The bare transcript-document icon is replaced by a three-dots overflow
   menu after Save Name: "Show transcript" (the old reveal action) and a
   destructive "Delete voice" wired to the real SpeakerDatabase deletion
   path. Delete is confirmed, verified (getSpeaker == nil) and surfaces an
   error instead of silently no-opping.

3. The "Who is this?" field becomes a name autocomplete. A new
   SpeakerNameAutocompleteField wraps NSComboBox and reuses
   SpeakerNameSelectionPolicy exactly like the post-meeting naming sheet;
   suggestions come from named profiles via SpeakerNameSuggestionSource.

Testable logic is extracted into Foundation-pure helpers
(SpeakerVoiceRowPresentation) covered by SpeakerVoiceRowPresentationTests
and wired into the fast-test manifest + APP_SOURCES.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codex peer-review P2: comboBoxSelectionDidChange re-filtered by the
already-committed stringValue inside the async block, so the selected
index could fall outside the shrunken visible list and picking a
2nd-or-later dropdown suggestion never reached the SwiftUI binding (Save
stayed on the old prefix). Resolve the picked label synchronously while
the typed query still matches the displayed list; defer only the field
assignment so it lands after the combo commits its own value.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant