Release: web UX overhaul + Android native port + server polish #59

Merged
bvandeusen merged 298 commits from dev into main 2026-06-01 16:11:21 -04:00
Showing only changes of commit e5c82c56c6 - Show all commits
+14 -9
View File
@@ -35,21 +35,25 @@ describe('useGlobalShortcuts', () => {
test('Space toggles play/pause', async () => { test('Space toggles play/pause', async () => {
const store = await import('./store.svelte'); const store = await import('./store.svelte');
expect(store.player.state).toBe('paused'); // playQueue leaves the store at 'loading' (intent-to-play; jsdom
press(' '); // never moves it to 'playing' because there's no real audio). The
flushSync(); // togglePlay contract is: loading|playing -> paused, anything else
expect(store.player.state).toBe('playing'); // -> loading. So Space round-trips loading <-> paused.
expect(store.player.state).toBe('loading');
press(' '); press(' ');
flushSync(); flushSync();
expect(store.player.state).toBe('paused'); expect(store.player.state).toBe('paused');
press(' ');
flushSync();
expect(store.player.state).toBe('loading');
}); });
test('K is an alias for Space (YouTube convention)', async () => { test('K is an alias for Space (YouTube convention)', async () => {
const store = await import('./store.svelte'); const store = await import('./store.svelte');
expect(store.player.state).toBe('paused'); expect(store.player.state).toBe('loading');
press('k'); press('k');
flushSync(); flushSync();
expect(store.player.state).toBe('playing'); expect(store.player.state).toBe('paused');
}); });
test('ArrowRight advances to the next track', async () => { test('ArrowRight advances to the next track', async () => {
@@ -97,19 +101,20 @@ describe('useGlobalShortcuts', () => {
test('shortcuts are ignored when focus is in an input', async () => { test('shortcuts are ignored when focus is in an input', async () => {
const store = await import('./store.svelte'); const store = await import('./store.svelte');
expect(store.player.state).toBe('paused'); const before = store.player.state;
const input = document.createElement('input'); const input = document.createElement('input');
document.body.appendChild(input); document.body.appendChild(input);
input.focus(); input.focus();
press(' ', input); press(' ', input);
flushSync(); flushSync();
// No state change — Space should pass through to the input. // No state change — Space should pass through to the input.
expect(store.player.state).toBe('paused'); expect(store.player.state).toBe(before);
input.remove(); input.remove();
}); });
test('modifier keys disable the shortcut (browser hotkey passthrough)', async () => { test('modifier keys disable the shortcut (browser hotkey passthrough)', async () => {
const store = await import('./store.svelte'); const store = await import('./store.svelte');
const before = store.player.state;
const event = new KeyboardEvent('keydown', { const event = new KeyboardEvent('keydown', {
key: ' ', key: ' ',
ctrlKey: true, ctrlKey: true,
@@ -118,6 +123,6 @@ describe('useGlobalShortcuts', () => {
}); });
window.dispatchEvent(event); window.dispatchEvent(event);
flushSync(); flushSync();
expect(store.player.state).toBe('paused'); expect(store.player.state).toBe(before);
}); });
}); });