Files
yellowjacket/frontend/src/store/controllers/player-controller.ts
T

90 lines
2.2 KiB
TypeScript

import type { ReactiveController, ReactiveControllerHost } from 'lit';
import type { PlayerState, TrackInfo } from '../player-store';
import { playerStore } from '../player-store';
/**
* PlayerController connects a Lit component to the PlayerStore.
*
* Usage in a component:
*
* private player = new PlayerController(this);
*
* render() {
* return html`
* <span>${this.player.currentTrack?.fileName}</span>
* <button @click=${() => this.player.play()}>Play</button>
* `;
* }
*/
export class PlayerController implements ReactiveController {
private host: ReactiveControllerHost;
private unsubscribe?: () => void;
constructor(host: ReactiveControllerHost) {
this.host = host;
host.addController(this);
}
// ===================================================================
// LIFECYCLE HOOKS
// ===================================================================
hostConnected(): void {
// Subscribe to store when component mounts
this.unsubscribe = playerStore.subscribe(() => {
this.host.requestUpdate();
});
}
hostDisconnected(): void {
// Unsubscribe when component unmounts (prevents memory leaks)
this.unsubscribe?.();
}
// ===================================================================
// STATE ACCESSORS
// Convenience getters so components don't need to call getState()
// ===================================================================
get state(): Readonly<PlayerState> {
return playerStore.getState();
}
get isPlaying(): boolean {
return this.state.isPlaying;
}
get currentTrack(): TrackInfo | null {
return this.state.currentTrack;
}
get volume(): number {
return this.state.volume;
}
// ===================================================================
// ACTIONS
// Delegate to store (which delegates to backend)
// ===================================================================
play(): void {
playerStore.play();
}
pause(): void {
playerStore.pause();
}
loadTrack(filePath: string): void {
playerStore.loadTrack(filePath);
}
seek(seconds: number): void {
playerStore.seek(seconds);
}
setVolume(level: number): void {
playerStore.setVolume(level);
}
}