feat(speakers): play/pause toggle, 3-dot overflow menu, name autocomplete#1136
Draft
r3dbars wants to merge 2 commits into
Draft
feat(speakers): play/pause toggle, 3-dot overflow menu, name autocomplete#1136r3dbars wants to merge 2 commits into
r3dbars wants to merge 2 commits into
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.swiftplus three new files.Changes
1. Play/pause toggle with a clear active state
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.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)
ellipsismenu with:doc.texticon did (openTranscript).SpeakerDatabase.deleteSpeakerpath viamodel.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
SpeakerNameAutocompleteFieldwrapsNSComboBoxand reuses the existingSpeakerNameSelectionPolicy(the same matching/inline-completion the post-meetingSpeakerNamingSheetuses).SpeakerNameSuggestionSource(excludes the voice being named and unnamed/blank profiles).Tests
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 ofSpeakerNameSelectionPolicyinline completion).Tests/FastTests.manifest+run-tests.shAPP_SOURCES.bash run-tests.sh→ 5439/5439 pass.bash build.sh --no-open→ clean, perf budget OK.Manual click-test still needed (real-app UI behaviors)
Peer / collision notes
FastTests.manifestandrun-tests.sh— different regions, should auto-merge; whoever lands second may need a trivial rebase.🤖 Generated with Claude Code