diff --git a/frontend/app/services/studying-timer.ts b/frontend/app/services/studying-timer.ts index faf9acb82..712a03642 100644 --- a/frontend/app/services/studying-timer.ts +++ b/frontend/app/services/studying-timer.ts @@ -1,9 +1,10 @@ -import Service from '@ember/service'; +import Service, { service } from '@ember/service'; import { action } from '@ember/object'; import config from 'brn/config/environment'; import { tracked } from '@glimmer/tracking'; import { isTesting } from '@embroider/macros'; import type IdleJs from 'idle-js'; +import type AudioService from './audio'; export interface TimerInstance { isStarted: boolean; @@ -13,6 +14,7 @@ export interface TimerInstance { } export default class StudyingTimerService extends Service { + @service('audio') declare audio: AudioService; willDestroy() { super.willDestroy(); this.idleWatcher && this.idleWatcher.stop(); @@ -63,6 +65,15 @@ export default class StudyingTimerService extends Service { this.isPaused = false; } @action + maybeIdlePause() { + // Pause cascades into audio.stop() via task-player.onPauseStateChanged, + // which would interrupt exercises whenever the user stops moving the mouse. + if (this.audio.isPlaying) { + return; + } + this.pause(); + } + @action async startIdleWatcher() { if (isTesting()) { return; @@ -75,7 +86,7 @@ export default class StudyingTimerService extends Service { this.idleWatcher = new IdleJs({ idle: timerInstance.idleTimeout || config.idleTimeout, onIdle() { - player.pause(); + player.maybeIdlePause(); }, onActive() { timerInstance.relaunchStartedTimer(); diff --git a/frontend/tests/unit/services/studying-timer-test.js b/frontend/tests/unit/services/studying-timer-test.js index 5a809ad83..e88eb816e 100644 --- a/frontend/tests/unit/services/studying-timer-test.js +++ b/frontend/tests/unit/services/studying-timer-test.js @@ -1,12 +1,39 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; +import Service from '@ember/service'; module('Unit | Service | studying-timer', function (hooks) { setupTest(hooks); - // Replace this with your real tests. test('it exists', function (assert) { let service = this.owner.lookup('service:studying-timer'); assert.ok(service); }); + + module('maybeIdlePause', function () { + function withAudio(owner, playing) { + owner.register('service:audio', class extends Service { isPlaying = playing; }); + return owner.lookup('service:studying-timer'); + } + + test('pauses when audio is not playing', function (assert) { + const timer = withAudio(this.owner, false); + timer.maybeIdlePause(); + assert.true(timer.isPaused); + }); + + test('does not pause when audio is playing', function (assert) { + const timer = withAudio(this.owner, true); + timer.maybeIdlePause(); + assert.false(timer.isPaused); + }); + + test('user pause still works while audio plays', function (assert) { + // Regression guard: only maybeIdlePause should defer to audio state; + // direct pause() (timer button click) must remain unconditional. + const timer = withAudio(this.owner, true); + timer.pause(); + assert.true(timer.isPaused); + }); + }); });