Skip to content

Commit

Permalink
✨ [Stack] Add queue event
Browse files Browse the repository at this point in the history
  • Loading branch information
beefchimi committed Dec 22, 2023
1 parent 73556e8 commit fcee531
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 6 deletions.
4 changes: 4 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,10 @@ soundStack.activeEvents;
// Possible `StackState` values are: `idle`, `loading`, `playing`.
(event: 'state', listener: (current: StackState) => void)

// Event called whenever the `keys` property changes. This is useful
// to subscribe to changes in the internal “sound queue”.
(event: 'queue', listener: (newKeys: SoundId[], oldKeys: SoundId[]) => void)

// Event called whenever the `volume` property changes.
(event: 'volume', listener: (level: number) => void)

Expand Down
17 changes: 11 additions & 6 deletions src/Stack.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {EmittenCommon} from 'emitten';

import {getErrorMessage, fetchAudioBuffer, scratchBuffer} from './helpers';
import {clamp, msToSec, secToMs} from './utilities';
import {arrayShallowEquals, clamp, msToSec, secToMs} from './utilities';
import {tokens} from './tokens';

import type {
Expand Down Expand Up @@ -201,18 +201,23 @@ export class Stack extends EmittenCommon<StackEventMap> {
({id}) => !outOfBoundsIds.includes(id),
);

outOfBounds.forEach((expiredSound) => {
expiredSound.stop();
});

outOfBounds.forEach((expiredSound) => expiredSound.stop());
this.#setQueue(filteredQueue);

return newSound;
}

#setQueue(value: Sound[]) {
const oldKeys = [...this._keys];
const newKeys = value.map(({id}) => id);
const identicalKeys = arrayShallowEquals(oldKeys, newKeys);

this.#queue = value;
this._keys = value.map(({id}) => id);
this._keys = newKeys;

if (!identicalKeys) {
this.emit('queue', newKeys, oldKeys);
}
}

#setState(value: StackState) {
Expand Down
47 changes: 47 additions & 0 deletions src/tests/Stack.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,28 @@ describe('Stack component', () => {
expect(spySound3Stop).toBeCalled();
});

it('emits `queue` event for each stopped Sound', async () => {
const spyQueue: StackEventMap['queue'] = vi.fn((_new, _old) => {});

mockStack.on('queue', spyQueue);
expect(spyQueue).not.toBeCalled();

await mockStack.prepare('One');
await mockStack.prepare('Two');
await mockStack.prepare('Three');

expect(spyQueue).toBeCalledTimes(3);
expect(spyQueue).toHaveBeenLastCalledWith(
['One', 'Two', 'Three'],
['One', 'Two'],
);

mockStack.stop();

expect(spyQueue).toBeCalledTimes(6);
expect(spyQueue).toHaveBeenLastCalledWith([], ['Three']);
});

it('returns instance', async () => {
await mockStack.prepare('Foo');
const instance = mockStack.stop();
Expand Down Expand Up @@ -293,6 +315,31 @@ describe('Stack component', () => {
await expect(sound).resolves.toBeInstanceOf(Sound);
await expect(sound).resolves.toHaveProperty('id', mockSoundId);
});

it('emits `queue` event with new and old `keys`', async () => {
const mockSoundId1 = 'Foo';
const mockSoundId2 = 'Bar';
const spyQueue: StackEventMap['queue'] = vi.fn((_new, _old) => {});

mockStack.on('queue', spyQueue);
expect(spyQueue).not.toBeCalled();
expect(mockStack.keys).toHaveLength(0);

await mockStack.prepare(mockSoundId1);

expect(spyQueue).toBeCalledTimes(1);
expect(spyQueue).toBeCalledWith([mockSoundId1], []);
expect(mockStack.keys).toHaveLength(1);

await mockStack.prepare(mockSoundId2);

expect(spyQueue).toBeCalledTimes(2);
expect(spyQueue).toBeCalledWith(
[mockSoundId1, mockSoundId2],
[mockSoundId1],
);
expect(mockStack.keys).toHaveLength(2);
});
});

describe('#load()', () => {
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export interface StackError {
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
export type StackEventMap = {
state: (current: StackState) => void;
queue: (newKeys: SoundId[], oldKeys: SoundId[]) => void;
volume: (level: number) => void;
mute: (muted: boolean) => void;
error: (message: StackError) => void;
Expand Down

0 comments on commit fcee531

Please sign in to comment.