Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions frontend/app/services/studying-timer.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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();
Expand Down Expand Up @@ -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;
Expand All @@ -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();
Expand Down
29 changes: 28 additions & 1 deletion frontend/tests/unit/services/studying-timer-test.js
Original file line number Diff line number Diff line change
@@ -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);
});
});
});
Loading