Skip to content

Add persistent play/pause button to navbar for TTS#1661

Open
4rdii wants to merge 1 commit intojohnfactotum:gtk4from
4rdii:feat/tts-navbar-play-pause
Open

Add persistent play/pause button to navbar for TTS#1661
4rdii wants to merge 1 commit intojohnfactotum:gtk4from
4rdii:feat/tts-navbar-play-pause

Conversation

@4rdii
Copy link
Copy Markdown

@4rdii 4rdii commented Apr 11, 2026

Summary

Adds a small GtkButton to the main navbar, directly before the existing headphones (Narration) GtkMenuButton, that lets the user start/pause/resume TTS without having to re-open the popover each time.

Motivation

Today, starting narration looks like this:

  1. Click the headphones button → popover opens.
  2. Click Play inside the popover → TTS starts.
  3. Click the reading surface → popover closes (popovers autohide on outside click).
  4. User now has no visible pause control.
  5. To pause: click headphones again → popover → click Play (which is a toggle) → click away.

For a "read along while TTS narrates" flow, this is three round-trips just to toggle pause. Adding a persistent button in the toolbar makes it a single click.

How it works

  • New widget: a GtkButton with id tts-quick-play, image-button style, media-playback-start-symbolic initial icon, and tooltip "Play/Pause Narration". Placed as a sibling of the existing headphones GtkMenuButton.
  • Click handler: this._tts_quick_play.connect('clicked', () => this.tts_box.play()) — delegates to the same play() method that the in-popover button calls.
  • Icon sync: a GObject property binding (bind_property('icon-name', ..., SYNC_CREATE)) mirrors the popover play button's icon-name onto the navbar button. Whichever button the user clicks, both icons flip in lockstep between media-playback-start-symbolic and media-playback-pause-symbolic.
  • One small addition to FoliateTTSBox: a public playButton getter, so navbar.js can reference the internal child without reaching into private state.

Non-goals

  • No keyboard shortcut. A Space or Ctrl+P binding would be nice but is orthogonal and deserves its own discussion for conflict handling with the reader's existing shortcuts.
  • No change to the popover. The popover's play button, Speed, and Pitch controls are untouched.
  • No change to FoliateMediaOverlayBox. This PR only wires the standard TTS path.

Visual impact

One additional button in the toolbar, same size as the other image buttons, so the toolbar widens by roughly one icon's worth. Icon and tooltip are standard GTK symbolic.

Test plan

  • Built locally against Foliate 3.1.1 (Ubuntu 24.04 system libraries).
  • Clicked the navbar button with no prior playback → TTS starts.
  • Clicked the navbar button while playing → TTS pauses, icon flips to media-playback-start-symbolic.
  • Clicked the in-popover Play button while paused → TTS resumes, navbar button's icon flips to media-playback-pause-symbolic.
  • Verified the icon binding survives multiple play/pause cycles.
  • Verified no regression in the existing popover controls.

🤖 Generated with Claude Code

The Narration (headphones) button opens a popover containing the TTS
play/pause/skip controls and the Speed/Pitch scales. The popover
closes on outside click, so once the user starts narration and
returns focus to the reading surface, there is no visible control
for pausing or resuming — the user has to re-click the headphones
button, wait for the popover, click the play-button toggle, and
then click away again. For a reading-along-with-TTS flow, this is
painful.

This change adds a small GtkButton (id: tts-quick-play) to the main
navbar, directly before the existing headphones GtkMenuButton. Its
clicked signal delegates to tts_box.play(), and its icon-name is
kept in sync with the popover's play button via a GObject property
binding (SYNC_CREATE), so:

- Clicking the navbar button starts TTS (or pauses/resumes it).
- Clicking the in-popover play button also updates the navbar
  button's icon.
- Both buttons always show the same media-playback-start-symbolic
  or media-playback-pause-symbolic state.

The navbar button is always visible, adds no new strings besides
"Play/Pause Narration" (translatable), and requires one small
addition to FoliateTTSBox — a public `playButton` getter so the
navbar can reference the internal child without reaching into
private state.

Co-Authored-By: Claude Opus 4.6 (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