refactored many events to use wails bindings, reducing boilerplate

This commit is contained in:
2026-02-25 18:51:07 -05:00
parent baa4644ece
commit cf144bf0dd
20 changed files with 1044 additions and 716 deletions
@@ -80,7 +80,7 @@ export class PlayerControls extends LitElement {
`;
private handlePlayClick = () => {
this.player.play();
queueStore.play();
};
private handlePauseClick = () => {
+2 -28
View File
@@ -2,44 +2,18 @@
// These names must match the corresponding event names in the Go backend.
export const Events = {
// Playback control events
// Playback events (backend → frontend push)
PlaybackStateChanged: "PlaybackStateChanged",
PlaybackFinished: "PlaybackFinished",
RequestPlay: "RequestPlay",
RequestPause: "RequestPause",
RequestLoadFile: "RequestLoadFile",
// Track events
TrackChanged: "TrackChanged",
// Seek events
Seek: "Seek",
SeekFailed: "SeekFailed",
// Volume events
RequestSetVolume: "RequestSetVolume",
VolumeChanged: "VolumeChanged",
// Queue events
// Queue events (backend → frontend push)
QueueChanged: "QueueChanged",
QueueIndexChanged: "QueueIndexChanged",
QueueModeChanged: "QueueModeChanged",
QueueTracksModified: "QueueTracksModified",
RequestNext: "RequestNext",
RequestPrevious: "RequestPrevious",
RequestSetQueue: "RequestSetQueue",
RequestAddToQueue: "RequestAddToQueue",
RequestPlayNext: "RequestPlayNext",
RequestRemoveFromQueue: "RequestRemoveFromQueue",
RequestToggleShuffle: "RequestToggleShuffle",
RequestCycleRepeat: "RequestCycleRepeat",
RequestAddTracksToQueue: "RequestAddTracksToQueue",
RequestPlayTracksNext: "RequestPlayTracksNext",
RequestPlayQueueIndex: "RequestPlayQueueIndex",
RequestRemoveTracksFromQueue: "RequestRemoveTracksFromQueue",
RequestInsertTracksAtIndex: "RequestInsertTracksAtIndex",
RequestMoveQueueTracks: "RequestMoveQueueTracks",
RequestClearQueue: "RequestClearQueue",
// Playlist events
PlaylistCreated: "PlaylistCreated",
@@ -12,7 +12,7 @@ import { playerStore } from '../player-store';
* render() {
* return html`
* <span>${this.player.currentTrack?.fileName}</span>
* <button @click=${() => this.player.play()}>Play</button>
* <button @click=${() => this.player.pause()}>Pause</button>
* `;
* }
*/
@@ -67,10 +67,6 @@ export class PlayerController implements ReactiveController {
// Delegate to store (which delegates to backend)
// ===================================================================
play(): void {
playerStore.play();
}
pause(): void {
playerStore.pause();
}
@@ -71,6 +71,10 @@ export class QueueController implements ReactiveController {
// ACTIONS
// ===================================================================
play(): void {
queueStore.play();
}
next(): void {
queueStore.next();
}
+7 -10
View File
@@ -1,5 +1,6 @@
import { EventsOn, EventsEmit } from '@runtime/runtime';
import { EventsOn } from '@runtime/runtime';
import { Events } from '../events';
import * as Player from '@go/player/Player';
// TrackInfo mirrors the player.TrackInfo struct in the Go backend.
// Fields are serialized as camelCase JSON via struct tags.
@@ -79,27 +80,23 @@ class PlayerStore {
// ===================================================================
// ACTIONS
// These delegate to the backend via Wails events
// These delegate to the backend via Wails bindings
// ===================================================================
play(): void {
EventsEmit(Events.RequestPlay);
}
pause(): void {
EventsEmit(Events.RequestPause);
Player.Pause();
}
loadTrack(filePath: string): void {
EventsEmit(Events.RequestLoadFile, filePath);
Player.LoadFile(filePath);
}
seek(seconds: number): void {
EventsEmit(Events.Seek, seconds);
Player.Seek(seconds);
}
setVolume(level: number): void {
EventsEmit(Events.RequestSetVolume, level);
Player.SetVolume(level);
}
// ===================================================================
+26 -31
View File
@@ -1,5 +1,6 @@
import { EventsOn, EventsEmit } from '@runtime/runtime';
import { EventsOn } from '@runtime/runtime';
import { Events } from '../events';
import * as Queue from '@go/queue/Queue';
// Types
export interface QueueTrack {
@@ -179,15 +180,19 @@ class QueueStore {
// ===================================================================
// ACTIONS
// These delegate to the backend via Wails events
// These delegate to the backend via Wails bindings
// ===================================================================
play(): void {
Queue.Play();
}
next(): void {
EventsEmit(Events.RequestNext);
Queue.Next();
}
previous(): void {
EventsEmit(Events.RequestPrevious);
Queue.Previous();
}
setQueue(
@@ -195,71 +200,61 @@ class QueueStore {
startIndex: number,
shuffleStart = false,
): void {
EventsEmit(
Events.RequestSetQueue,
filePaths,
startIndex,
shuffleStart,
);
Queue.SetQueue(filePaths, startIndex, shuffleStart);
}
addToQueue(filePath: string): void {
EventsEmit(Events.RequestAddToQueue, filePath);
Queue.AddTrack(filePath);
}
playNext(filePath: string): void {
EventsEmit(Events.RequestPlayNext, filePath);
Queue.InsertNext(filePath);
}
removeFromQueue(position: number): void {
EventsEmit(Events.RequestRemoveFromQueue, position);
Queue.RemoveTrack(position);
}
removeTracksFromQueue(positions: number[]): void {
EventsEmit(Events.RequestRemoveTracksFromQueue, positions);
Queue.RemoveTracks(positions);
}
addTracksToQueue(filePaths: string[]): void {
EventsEmit(Events.RequestAddTracksToQueue, filePaths);
Queue.AddTracks(filePaths);
}
playTracksNext(filePaths: string[]): void {
EventsEmit(Events.RequestPlayTracksNext, filePaths);
Queue.InsertNextTracks(filePaths);
}
toggleShuffle(): void {
EventsEmit(Events.RequestToggleShuffle);
Queue.ToggleShuffle();
}
cycleRepeat(): void {
EventsEmit(Events.RequestCycleRepeat);
Queue.CycleRepeat();
}
playAtIndex(index: number): void {
EventsEmit(Events.RequestPlayQueueIndex, index);
Queue.PlayIndex(index);
}
insertTracksAtIndex(filePaths: string[], index: number): void {
EventsEmit(
Events.RequestInsertTracksAtIndex,
filePaths,
index,
);
insertTracksAtIndex(
filePaths: string[],
index: number,
): void {
Queue.InsertTracksAt(filePaths, index);
}
moveTracksInQueue(
fromIndices: number[],
toIndex: number,
): void {
EventsEmit(
Events.RequestMoveQueueTracks,
fromIndices,
toIndex,
);
Queue.MoveQueueTracks(fromIndices, toIndex);
}
clearQueue(): void {
EventsEmit(Events.RequestClearQueue);
Queue.Clear();
}
// ===================================================================
+106
View File
@@ -171,6 +171,47 @@ export namespace library {
}
export namespace player {
export class TrackInfo {
fileName: string;
filePath: string;
state: string;
title: string;
artist: string;
album: string;
coverArt: string;
coverArtSmall: string;
coverArtMedium: string;
coverArtLarge: string;
trackLength: number;
seekPosition: number;
trackChangeId: number;
static createFrom(source: any = {}) {
return new TrackInfo(source);
}
constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source);
this.fileName = source["fileName"];
this.filePath = source["filePath"];
this.state = source["state"];
this.title = source["title"];
this.artist = source["artist"];
this.album = source["album"];
this.coverArt = source["coverArt"];
this.coverArtSmall = source["coverArtSmall"];
this.coverArtMedium = source["coverArtMedium"];
this.coverArtLarge = source["coverArtLarge"];
this.trackLength = source["trackLength"];
this.seekPosition = source["seekPosition"];
this.trackChangeId = source["trackChangeId"];
}
}
}
export namespace playlist {
export class CandidateTrack {
@@ -344,6 +385,71 @@ export namespace playlist {
}
export namespace queue {
export class Track {
id: number;
audioFileId: number;
filePath: string;
position: number;
title: string;
artist: string;
static createFrom(source: any = {}) {
return new Track(source);
}
constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source);
this.id = source["id"];
this.audioFileId = source["audioFileId"];
this.filePath = source["filePath"];
this.position = source["position"];
this.title = source["title"];
this.artist = source["artist"];
}
}
export class State {
tracks: Track[];
currentIndex: number;
shuffleMode: boolean;
repeatMode: string;
sourcePlaylistId: number;
static createFrom(source: any = {}) {
return new State(source);
}
constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source);
this.tracks = this.convertValues(source["tracks"], Track);
this.currentIndex = source["currentIndex"];
this.shuffleMode = source["shuffleMode"];
this.repeatMode = source["repeatMode"];
this.sourcePlaylistId = source["sourcePlaylistId"];
}
convertValues(a: any, classs: any, asMap: boolean = false): any {
if (!a) {
return a;
}
if (a.slice && a.map) {
return (a as any[]).map(elem => this.convertValues(elem, classs));
} else if ("object" === typeof a) {
if (asMap) {
for (const key of Object.keys(a)) {
a[key] = new classs(a[key]);
}
return a;
}
return new classs(a);
}
return a;
}
}
}
export namespace tracklist {
export class Column {
+42
View File
@@ -0,0 +1,42 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
import {player} from '../models';
import {context} from '../models';
export function ChangeVolume(arg1:number):Promise<void>;
export function CurrentPosition():Promise<number>;
export function CurrentPositionSeconds():Promise<number>;
export function EmitCurrentState():Promise<void>;
export function GetCurrentTrackInfo():Promise<player.TrackInfo>;
export function InitSpeaker():Promise<void>;
export function IsPlaying():Promise<boolean>;
export function LoadFile(arg1:string):Promise<void>;
export function MuteToggle():Promise<void>;
export function Pause():Promise<void>;
export function Play():Promise<void>;
export function RestoreState():Promise<void>;
export function SaveState():Promise<void>;
export function Seek(arg1:number):Promise<void>;
export function SetContext(arg1:context.Context):Promise<void>;
export function SetPlaybackFinishedHandler(arg1:any):Promise<void>;
export function SetVolume(arg1:player.UserVolume):Promise<void>;
export function TrackLengthInSeconds():Promise<number>;
export function UnloadTrack():Promise<void>;
+79
View File
@@ -0,0 +1,79 @@
// @ts-check
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
export function ChangeVolume(arg1) {
return window['go']['player']['Player']['ChangeVolume'](arg1);
}
export function CurrentPosition() {
return window['go']['player']['Player']['CurrentPosition']();
}
export function CurrentPositionSeconds() {
return window['go']['player']['Player']['CurrentPositionSeconds']();
}
export function EmitCurrentState() {
return window['go']['player']['Player']['EmitCurrentState']();
}
export function GetCurrentTrackInfo() {
return window['go']['player']['Player']['GetCurrentTrackInfo']();
}
export function InitSpeaker() {
return window['go']['player']['Player']['InitSpeaker']();
}
export function IsPlaying() {
return window['go']['player']['Player']['IsPlaying']();
}
export function LoadFile(arg1) {
return window['go']['player']['Player']['LoadFile'](arg1);
}
export function MuteToggle() {
return window['go']['player']['Player']['MuteToggle']();
}
export function Pause() {
return window['go']['player']['Player']['Pause']();
}
export function Play() {
return window['go']['player']['Player']['Play']();
}
export function RestoreState() {
return window['go']['player']['Player']['RestoreState']();
}
export function SaveState() {
return window['go']['player']['Player']['SaveState']();
}
export function Seek(arg1) {
return window['go']['player']['Player']['Seek'](arg1);
}
export function SetContext(arg1) {
return window['go']['player']['Player']['SetContext'](arg1);
}
export function SetPlaybackFinishedHandler(arg1) {
return window['go']['player']['Player']['SetPlaybackFinishedHandler'](arg1);
}
export function SetVolume(arg1) {
return window['go']['player']['Player']['SetVolume'](arg1);
}
export function TrackLengthInSeconds() {
return window['go']['player']['Player']['TrackLengthInSeconds']();
}
export function UnloadTrack() {
return window['go']['player']['Player']['UnloadTrack']();
}
+50
View File
@@ -0,0 +1,50 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
import {queue} from '../models';
import {context} from '../models';
export function AddTrack(arg1:string):Promise<void>;
export function AddTracks(arg1:Array<string>):Promise<void>;
export function Clear():Promise<void>;
export function CycleRepeat():Promise<void>;
export function EmitCurrentState():Promise<void>;
export function GetState():Promise<queue.State>;
export function InsertNext(arg1:string):Promise<void>;
export function InsertNextTracks(arg1:Array<string>):Promise<void>;
export function InsertTracksAt(arg1:Array<string>,arg2:number):Promise<void>;
export function MoveQueueTracks(arg1:Array<number>,arg2:number):Promise<void>;
export function Next():Promise<void>;
export function OnPlaybackFinished():Promise<void>;
export function Play():Promise<void>;
export function PlayIndex(arg1:number):Promise<void>;
export function Previous():Promise<void>;
export function RemoveTrack(arg1:number):Promise<void>;
export function RemoveTracks(arg1:Array<number>):Promise<void>;
export function RestoreState():Promise<void>;
export function SaveState():Promise<void>;
export function SetContext(arg1:context.Context):Promise<void>;
export function SetPlayer(arg1:queue.TrackLoader):Promise<void>;
export function SetQueue(arg1:Array<string>,arg2:number,arg3:boolean):Promise<void>;
export function ToggleShuffle():Promise<void>;
+95
View File
@@ -0,0 +1,95 @@
// @ts-check
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
export function AddTrack(arg1) {
return window['go']['queue']['Queue']['AddTrack'](arg1);
}
export function AddTracks(arg1) {
return window['go']['queue']['Queue']['AddTracks'](arg1);
}
export function Clear() {
return window['go']['queue']['Queue']['Clear']();
}
export function CycleRepeat() {
return window['go']['queue']['Queue']['CycleRepeat']();
}
export function EmitCurrentState() {
return window['go']['queue']['Queue']['EmitCurrentState']();
}
export function GetState() {
return window['go']['queue']['Queue']['GetState']();
}
export function InsertNext(arg1) {
return window['go']['queue']['Queue']['InsertNext'](arg1);
}
export function InsertNextTracks(arg1) {
return window['go']['queue']['Queue']['InsertNextTracks'](arg1);
}
export function InsertTracksAt(arg1, arg2) {
return window['go']['queue']['Queue']['InsertTracksAt'](arg1, arg2);
}
export function MoveQueueTracks(arg1, arg2) {
return window['go']['queue']['Queue']['MoveQueueTracks'](arg1, arg2);
}
export function Next() {
return window['go']['queue']['Queue']['Next']();
}
export function OnPlaybackFinished() {
return window['go']['queue']['Queue']['OnPlaybackFinished']();
}
export function Play() {
return window['go']['queue']['Queue']['Play']();
}
export function PlayIndex(arg1) {
return window['go']['queue']['Queue']['PlayIndex'](arg1);
}
export function Previous() {
return window['go']['queue']['Queue']['Previous']();
}
export function RemoveTrack(arg1) {
return window['go']['queue']['Queue']['RemoveTrack'](arg1);
}
export function RemoveTracks(arg1) {
return window['go']['queue']['Queue']['RemoveTracks'](arg1);
}
export function RestoreState() {
return window['go']['queue']['Queue']['RestoreState']();
}
export function SaveState() {
return window['go']['queue']['Queue']['SaveState']();
}
export function SetContext(arg1) {
return window['go']['queue']['Queue']['SetContext'](arg1);
}
export function SetPlayer(arg1) {
return window['go']['queue']['Queue']['SetPlayer'](arg1);
}
export function SetQueue(arg1, arg2, arg3) {
return window['go']['queue']['Queue']['SetQueue'](arg1, arg2, arg3);
}
export function ToggleShuffle() {
return window['go']['queue']['Queue']['ToggleShuffle']();
}