Fix idle pause during LISTEN audio gaps (followup to #2893)#2907
Merged
Conversation
The previous fix (#2893) only guarded onIdle against firing while audio was actively playing, but the LISTEN sequence sets isPlaying=false during the 1500ms gap between clips. With idleTimeout=10000ms, onIdle landed inside the gap after ~3 clips and paused the exercise, deadlocking listenModeTask in waitWhilePaused() (IdleJs doesn't reschedule onIdle without a user input event). Add studyingTimer.resetIdle() that rearms the watcher via stop().start(), called from audio.playAudio() — the single funnel for all three audio entry points (startPlayTask, listenModeTask, interactModeTask). Each clip resets the 10s countdown, so the watcher only fires when there is genuinely no audio activity (e.g. INTERACT mode awaiting user clicks). resetIdle() deliberately does not touch isPaused — user-initiated pause must remain sticky (preserved by the regression test from f9c43aa). Verified in browser: LISTEN played all 3 clips with mouse still, timer counted 00:00→00:18 with isPaused=false throughout, transitioned to INTERACT, then idle correctly paused at ~10s of inactivity. Click on a word resumed normally. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Frontend test coverage: 72.52% (+0.12% compared to 72.4% on base) |
|
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.



Summary
maybeIdlePause()guard only checksaudio.isPlayingat the instant IdleJs fires, but inlistenModeTaskisPlayingisfalseduring the 1500 ms gap between clips and duringsetAudioElementsdecoding. WithidleTimeout: 10000, after ~3 clipsonIdlelands in the gap, pauses, andlistenModeTaskdeadlocks inwaitWhilePaused()(IdleJs does not rescheduleonIdlewithout a user input event).studyingTimer.resetIdle()that rearms the watcher viastop().start(), called fromaudio.playAudio()— the single funnel all three audio entry points go through (startPlayTask,listenModeTask's direct call,interactModeTask's direct call). Every clip resets the 10 s countdown.resetIdle()deliberately does not touchisPaused— user-initiated pause must remain sticky (the f9c43aa regression test still passes).maybeIdlePause()is kept as a defensive backstop for the unlikely case of a single clip exceeding the idle window.Test plan
pnpm lint:types— clean.pnpm test:ember --filter studying-timer— 8/8 pass (5 existing + 3 new tests forresetIdle: rearm via stop/start, no-toggle ofisPausedregression guard, no-op whenidleWatcheris null).pnpm test:ember --filter audio --filter task-player— 109/109 pass. Circular service injection (audio ↔ studying-timer) resolves lazily.isPaused=falsethroughout, transitioned to INTERACT, then idle correctly paused at ~10 s of inactivity. Click on a word resumed normally.🤖 Generated with Claude Code