From 23e411e78cf275706f2c068061c862f99516c42b Mon Sep 17 00:00:00 2001 From: finsofblueimnotyou <93227270+finsofblueimnotyou@users.noreply.github.com> Date: Wed, 12 Feb 2025 19:58:15 -0500 Subject: [PATCH] Implement basic volume scrolling interaction --- src/App.tsx | 844 ++++++++++++++++++++++++++-------------------------- 1 file changed, 427 insertions(+), 417 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 86ad12b..77dcc47 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,417 +1,427 @@ -import React, { createRef, useEffect, useRef, useState } from "react"; -import { convertFileSrc, invoke } from "@tauri-apps/api/core"; -import "./App.css"; -import { Config, playbackInfo } from "./types"; -// import { EventEmitter } from "@tauri-apps/plugin-shell"; -// import { listen } from "@tauri-apps/api/event"; -// import { fetch } from "@tauri-apps/plugin-http"; -import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow"; - -const appWindow = getCurrentWebviewWindow(); - -function App() { - const library = useState([]); - const [queue, setQueue] = useState([]); - const [playing, setPlaying] = useState(false); - const [playlists, setPlaylists] = useState([]); - const [viewName, setViewName] = useState("Library"); - - const [nowPlaying, setNowPlaying] = useState( - } - /> - ); - - useEffect(() => { - const unlisten = appWindow.listen("now_playing_change", ({ payload, }) => { - const displayArtwork = () => { - invoke('display_album_art', { uuid: payload.uuid }).then(() => {}) - } - // console.log(event); - setNowPlaying( - } - /> - ) - - }) - return () => { unlisten.then((f) => f()) } - }, []); - - useEffect(() => { - const unlisten = appWindow.listen("queue_updated", (_) => { - // console.log(event); - invoke('get_queue').then((_songs) => { - let songs = _songs as any[] - setQueue( - songs.filter((_, i) => i != 0).map((song, i) => - - ) - ) - }) - }) - return () => { unlisten.then((f) => f()) } - }, []); - - useEffect(() => { - const unlisten = appWindow.listen("playing", (_) => { - setPlaying(true) - }) - return () => { unlisten.then((f) => f()) } - }, []); - - useEffect(() => { - const unlisten = appWindow.listen("paused", (_) => { - setPlaying(false) - }) - return () => { unlisten.then((f) => f()) } - }, []); - - useEffect(() => { - getConfig(); - }, []) - - return ( -
-
-
- - -
-
- { nowPlaying } - -
-
-
- -
-
- ); -} - -export default App; - -interface PlaylistHeadProps { - playlists: JSX.Element[] - setPlaylists: React.Dispatch>, - setViewName: React.Dispatch>, - setLibrary: React.Dispatch>, -} - -function PlaylistHead({ playlists, setPlaylists, setViewName, setLibrary }: PlaylistHeadProps) { - - useEffect(() => { - const unlisten = appWindow.listen("playlists_gotten", (_res) => { - // console.log(event); - let res = _res.payload; - - setPlaylists([ - ...res.map( (item) => { - return ( - - ) - }) - ]) - }) - return () => { unlisten.then((f) => f()) } - }, []); - let handle_import = () => { - invoke('import_playlist').then((_res) => { - let res = _res as any; - - setPlaylists([ - ...playlists, - - ]) - console.log(res.name); - }) - } - return ( -
- - { playlists } - -
- ) -} - -interface MainViewProps { - lib_ref: [JSX.Element[], React.Dispatch>], - viewName: string -} - -function MainView({ lib_ref, viewName }: MainViewProps) { - const [library, setLibrary] = lib_ref; - - useEffect(() => { - const unlisten = appWindow.listen("library_loaded", (_) => { - console.log("library_loaded"); - invoke('get_library').then((lib) => { - setLibrary([...(lib as any[]).map((song) => { - - return ( - - ) - })]) - }) - - invoke('get_playlists').then(() => {}) - }) - return () => { unlisten.then((f) => f()) } - }, []); - - - return ( -
-

{ viewName }

-
{ library }
-
- ) -} - -interface SongProps { - location: any, - playerLocation: string | {"Playlist" : any}, - uuid: string, - plays: number, - format?: string, - duration: string, - last_played?: string, - date_added?: string, - date_modified?: string, - tags: any -} - -function Song(props: SongProps) { - // console.log(props.tags); - - return( -
{ - invoke("play_now", { uuid: props.uuid, location: props.playerLocation }).then(() => {}) - }} className="song"> -

{ props.tags.TrackArtist }

-

{ props.tags.TrackTitle }

-

{ props.tags.AlbumTitle }

-

- { Math.round(+props.duration / 60) }: - { (+props.duration % 60).toString().padStart(2, "0") } -

-
- ) -} - -interface PlayBarProps { - playing: boolean, - setPlaying: React.Dispatch> -} - -function PlayBar({ playing, setPlaying }: PlayBarProps) { - const [position, setPosition] = useState(0); - const [duration, setDuration] = useState(0); - const [seekBarSize, setSeekBarSize] = useState(0); - const seekBarRef = React.createRef(); - - useEffect(() => { - const unlisten = appWindow.listen("playback_info", ({ payload, }) => { - const info = payload as playbackInfo; - const pos_ = Array.isArray(info.position) ? info.position![0] : 0; - const dur_ = Array.isArray(info.duration) ? info.duration![0] : 0; - - setPosition(pos_); - setDuration(dur_); - let progress = ((dur_/pos_) * 100); - setSeekBarSize(progress) - }) - return () => { unlisten.then((f) => f()) } - }, []); - - const seek = (event: React.MouseEvent) => { - event.stopPropagation(); - let rect = seekBarRef.current!.getBoundingClientRect(); - let val = ((event.clientX-rect.left) / (rect.width))*position; - - invoke('seek', { time: Math.round(val * 1000) }).then() - }; - - return ( -
-
-
-
-
-
- - - - -
-
- - - { - invoke('set_volume', { volume: volume.target.value }).then(() => {}) - }} /> -

- { Math.floor(+duration / 60).toString().padStart(2, "0") }: - { (+duration % 60).toString().padStart(2, "0") }/ - { Math.floor(+position / 60).toString().padStart(2, "0") }: - { (+position % 60).toString().padStart(2, "0") } - -

-
-
-
- ) -} - -interface NowPlayingProps { - title: string, - artist: string, - album: string, - artwork: JSX.Element -} - -function NowPlaying({ title, artist, album, artwork }: NowPlayingProps) { - return ( -
-
- { artwork } -
-

{ title }

-

{ artist }

-

{ album }

-
- ) -} - -interface QueueProps { - songs: JSX.Element[], -} - -function Queue({ songs }: QueueProps) { - return ( -
- { songs } -
- ) -} - -interface QueueSongProps { - song: any, - location: "Library" | {"Playlist": string}, - index: number, -} - -function QueueSong({ song, location, index }: QueueSongProps) { - // console.log(song.tags); - - let removeFromQueue = () => { - invoke('remove_from_queue', { index: index }).then(() => {}) - } - - let playNow = () => { - invoke('play_now', { uuid: song.uuid, location: location }).then(() => {}) - } - - return ( -
- -
-

{ song.tags.TrackTitle }

-

{ song.tags.TrackArtist }

-
-
- ) -} - -function getConfig(): any { - invoke('get_config').then( (_config) => { - let config = _config as Config; - if (config.libraries.libraries.length == 0) { - invoke('create_new_library').then(() => {}) - } else { - // console.log("else"); - invoke('lib_already_created').then(() => {}) - } - }) -} +import React, { createRef, useEffect, useRef, useState } from "react"; +import { convertFileSrc, invoke } from "@tauri-apps/api/core"; +import "./App.css"; +import { Config, playbackInfo } from "./types"; +// import { EventEmitter } from "@tauri-apps/plugin-shell"; +// import { listen } from "@tauri-apps/api/event"; +// import { fetch } from "@tauri-apps/plugin-http"; +import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow"; + +const appWindow = getCurrentWebviewWindow(); + +function App() { + const library = useState([]); + const [queue, setQueue] = useState([]); + const [playing, setPlaying] = useState(false); + const [playlists, setPlaylists] = useState([]); + const [viewName, setViewName] = useState("Library"); + + const [nowPlaying, setNowPlaying] = useState( + } + /> + ); + + useEffect(() => { + const unlisten = appWindow.listen("now_playing_change", ({ payload, }) => { + const displayArtwork = () => { + invoke('display_album_art', { uuid: payload.uuid }).then(() => {}) + } + // console.log(event); + setNowPlaying( + } + /> + ) + + }) + return () => { unlisten.then((f) => f()) } + }, []); + + useEffect(() => { + const unlisten = appWindow.listen("queue_updated", (_) => { + // console.log(event); + invoke('get_queue').then((_songs) => { + let songs = _songs as any[] + setQueue( + songs.filter((_, i) => i != 0).map((song, i) => + + ) + ) + }) + }) + return () => { unlisten.then((f) => f()) } + }, []); + + useEffect(() => { + const unlisten = appWindow.listen("playing", (_) => { + setPlaying(true) + }) + return () => { unlisten.then((f) => f()) } + }, []); + + useEffect(() => { + const unlisten = appWindow.listen("paused", (_) => { + setPlaying(false) + }) + return () => { unlisten.then((f) => f()) } + }, []); + + useEffect(() => { + getConfig(); + }, []) + + return ( +
+
+
+ + +
+
+ { nowPlaying } + +
+
+
+ +
+
+ ); +} + +export default App; + +interface PlaylistHeadProps { + playlists: JSX.Element[] + setPlaylists: React.Dispatch>, + setViewName: React.Dispatch>, + setLibrary: React.Dispatch>, +} + +function PlaylistHead({ playlists, setPlaylists, setViewName, setLibrary }: PlaylistHeadProps) { + + useEffect(() => { + const unlisten = appWindow.listen("playlists_gotten", (_res) => { + // console.log(event); + let res = _res.payload; + + setPlaylists([ + ...res.map( (item) => { + return ( + + ) + }) + ]) + }) + return () => { unlisten.then((f) => f()) } + }, []); + let handle_import = () => { + invoke('import_playlist').then((_res) => { + let res = _res as any; + + setPlaylists([ + ...playlists, + + ]) + console.log(res.name); + }) + } + return ( +
+ + { playlists } + +
+ ) +} + +interface MainViewProps { + lib_ref: [JSX.Element[], React.Dispatch>], + viewName: string +} + +function MainView({ lib_ref, viewName }: MainViewProps) { + const [library, setLibrary] = lib_ref; + + useEffect(() => { + const unlisten = appWindow.listen("library_loaded", (_) => { + console.log("library_loaded"); + invoke('get_library').then((lib) => { + setLibrary([...(lib as any[]).map((song) => { + + return ( + + ) + })]) + }) + + invoke('get_playlists').then(() => {}) + }) + return () => { unlisten.then((f) => f()) } + }, []); + + + return ( +
+

{ viewName }

+
{ library }
+
+ ) +} + +interface SongProps { + location: any, + playerLocation: string | {"Playlist" : any}, + uuid: string, + plays: number, + format?: string, + duration: string, + last_played?: string, + date_added?: string, + date_modified?: string, + tags: any +} + +function Song(props: SongProps) { + // console.log(props.tags); + + return( +
{ + invoke("play_now", { uuid: props.uuid, location: props.playerLocation }).then(() => {}) + }} className="song"> +

{ props.tags.TrackArtist }

+

{ props.tags.TrackTitle }

+

{ props.tags.AlbumTitle }

+

+ { Math.round(+props.duration / 60) }: + { (+props.duration % 60).toString().padStart(2, "0") } +

+
+ ) +} + +interface PlayBarProps { + playing: boolean, + setPlaying: React.Dispatch> +} + +function PlayBar({ playing, setPlaying }: PlayBarProps) { + const [position, setPosition] = useState(0); + const [duration, setDuration] = useState(0); + const [seekBarSize, setSeekBarSize] = useState(0); + const seekBarRef = React.createRef(); + + useEffect(() => { + const unlisten = appWindow.listen("playback_info", ({ payload, }) => { + const info = payload as playbackInfo; + const pos_ = Array.isArray(info.position) ? info.position![0] : 0; + const dur_ = Array.isArray(info.duration) ? info.duration![0] : 0; + + setPosition(pos_); + setDuration(dur_); + let progress = ((dur_/pos_) * 100); + setSeekBarSize(progress) + }) + return () => { unlisten.then((f) => f()) } + }, []); + + const seek = (event: React.MouseEvent) => { + event.stopPropagation(); + let rect = seekBarRef.current!.getBoundingClientRect(); + let val = ((event.clientX-rect.left) / (rect.width))*position; + + invoke('seek', { time: Math.round(val * 1000) }).then() + }; + + const wheelVolume = (event: React.WheelEvent) => { + let x = volumeSlider.value; + if (event.deltaY < 0) { + volumeSlider.value++; + } else { + volumeSlider.value--; + } + invoke('set_volume', { volume: volumeSlider.value }).then(() => {}) + }; + + return ( +
+
+
+
+
+
+ + + + +
+
+ + + { + invoke('set_volume', { volume: volume.target.value }).then(() => {}) + }} /> +

+ { Math.floor(+duration / 60).toString().padStart(2, "0") }: + { (+duration % 60).toString().padStart(2, "0") }/ + { Math.floor(+position / 60).toString().padStart(2, "0") }: + { (+position % 60).toString().padStart(2, "0") } + +

+
+
+
+ ) +} + +interface NowPlayingProps { + title: string, + artist: string, + album: string, + artwork: JSX.Element +} + +function NowPlaying({ title, artist, album, artwork }: NowPlayingProps) { + return ( +
+
+ { artwork } +
+

{ title }

+

{ artist }

+

{ album }

+
+ ) +} + +interface QueueProps { + songs: JSX.Element[], +} + +function Queue({ songs }: QueueProps) { + return ( +
+ { songs } +
+ ) +} + +interface QueueSongProps { + song: any, + location: "Library" | {"Playlist": string}, + index: number, +} + +function QueueSong({ song, location, index }: QueueSongProps) { + // console.log(song.tags); + + let removeFromQueue = () => { + invoke('remove_from_queue', { index: index }).then(() => {}) + } + + let playNow = () => { + invoke('play_now', { uuid: song.uuid, location: location }).then(() => {}) + } + + return ( +
+ +
+

{ song.tags.TrackTitle }

+

{ song.tags.TrackArtist }

+
+
+ ) +} + +function getConfig(): any { + invoke('get_config').then( (_config) => { + let config = _config as Config; + if (config.libraries.libraries.length == 0) { + invoke('create_new_library').then(() => {}) + } else { + // console.log("else"); + invoke('lib_already_created').then(() => {}) + } + }) +}