frontend: Finish interactivity
This commit is contained in:
@@ -1,30 +1,103 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import SongTable from './SongTable';
|
||||
import NowPlaying from './NowPlaying';
|
||||
import AddSongPanel from './AddSongPanel';
|
||||
import { API, PlaylistItem } from '../api/player';
|
||||
|
||||
const App: React.FC = () => {
|
||||
const [isPlaying, setIsPlaying] = useState(false);
|
||||
const [nowPlayingSong, setNowPlayingSong] = useState<string | null>(null);
|
||||
const [nowPlayingFileName, setNowPlayingFileName] = useState<string | null>(null);
|
||||
const [songs, setSongs] = useState<string[]>([]);
|
||||
const [songs, setSongs] = useState<PlaylistItem[]>([]);
|
||||
const [ws, setWs] = useState<WebSocket | null>(null);
|
||||
|
||||
const fetchPlaylist = async () => {
|
||||
const playlist = await API.getPlaylist();
|
||||
setSongs(playlist);
|
||||
};
|
||||
|
||||
const fetchNowPlaying = async () => {
|
||||
const nowPlaying = await API.getNowPlaying();
|
||||
setNowPlayingSong(nowPlaying.nowPlaying);
|
||||
setNowPlayingFileName(nowPlaying.currentFile);
|
||||
setIsPlaying(!nowPlaying.isPaused);
|
||||
};
|
||||
|
||||
const handleAddURL = (url: string) => {
|
||||
const urlToAdd = url.trim();
|
||||
if (urlToAdd) {
|
||||
setSongs([...songs, urlToAdd]);
|
||||
API.addToPlaylist(urlToAdd);
|
||||
fetchPlaylist();
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelete = (index: number) => {
|
||||
setSongs(songs.filter((_, i) => i !== index));
|
||||
API.removeFromPlaylist(index);
|
||||
fetchPlaylist();
|
||||
fetchNowPlaying();
|
||||
};
|
||||
|
||||
const handleSkipTo = (index: number) => {
|
||||
setNowPlayingSong(songs[index]);
|
||||
setNowPlayingFileName(songs[index].split('/').pop() || null);
|
||||
setIsPlaying(true);
|
||||
const handleSkipTo = async (index: number) => {
|
||||
const song = songs[index];
|
||||
if (song.playing) {
|
||||
togglePlayPause();
|
||||
} else {
|
||||
await API.skipTo(index);
|
||||
await API.play();
|
||||
}
|
||||
|
||||
fetchNowPlaying();
|
||||
fetchPlaylist();
|
||||
};
|
||||
|
||||
const togglePlayPause = async () => {
|
||||
if (isPlaying) {
|
||||
await API.pause();
|
||||
} else {
|
||||
await API.play();
|
||||
}
|
||||
|
||||
fetchNowPlaying();
|
||||
};
|
||||
|
||||
const handleSkip = async () => {
|
||||
await API.skip();
|
||||
fetchNowPlaying();
|
||||
};
|
||||
|
||||
const handlePrevious = async () => {
|
||||
await API.previous();
|
||||
fetchNowPlaying();
|
||||
};
|
||||
|
||||
const watchForEvents = () => {
|
||||
const ws = API.subscribeToEvents((event) => {
|
||||
switch (event.event) {
|
||||
case 'user_modify':
|
||||
case 'end-file':
|
||||
case 'playback-restart':
|
||||
fetchPlaylist();
|
||||
fetchNowPlaying();
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return ws;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchPlaylist();
|
||||
fetchNowPlaying();
|
||||
setWs(watchForEvents());
|
||||
|
||||
return () => {
|
||||
if (ws) {
|
||||
ws.close();
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-center h-screen w-screen bg-black py-10">
|
||||
<div className="bg-violet-900 w-full md:max-w-xl h-full md:max-h-xl md:border md:rounded-2xl flex flex-col">
|
||||
@@ -33,14 +106,15 @@ const App: React.FC = () => {
|
||||
songName={nowPlayingSong || "(Not Playing)"}
|
||||
fileName={nowPlayingFileName || ""}
|
||||
isPlaying={isPlaying}
|
||||
onPlayPause={() => setIsPlaying(!isPlaying)}
|
||||
onStepForward={() => {}}
|
||||
onStepBackward={() => {}}
|
||||
onPlayPause={togglePlayPause}
|
||||
onSkip={handleSkip}
|
||||
onPrevious={handlePrevious}
|
||||
/>
|
||||
|
||||
{songs.length > 0 ? (
|
||||
<SongTable
|
||||
songs={songs}
|
||||
isPlaying={isPlaying}
|
||||
onDelete={handleDelete}
|
||||
onSkipTo={handleSkipTo}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user