From 95f27a2acc0ff170ea287679893813499bc6475f Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Wed, 9 Oct 2024 20:31:56 +0200 Subject: [PATCH 01/54] playlistView and initial addToPlaylist button --- src/main/router/songs-pool-router.ts | 20 ++- .../src/components/scenes/MainScene.tsx | 47 ++++---- .../src/components/song/PlaylistView.tsx | 114 ++++++++++++++++++ src/renderer/src/components/song/SongView.tsx | 3 +- .../song/context-menu/items/AddToPlaylist.tsx | 29 +++++ .../song/context-menu/items/PlayNext.tsx | 30 ++--- 6 files changed, 186 insertions(+), 57 deletions(-) create mode 100644 src/renderer/src/components/song/PlaylistView.tsx create mode 100644 src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx diff --git a/src/main/router/songs-pool-router.ts b/src/main/router/songs-pool-router.ts index f7e7fa9a..2795b2fe 100644 --- a/src/main/router/songs-pool-router.ts +++ b/src/main/router/songs-pool-router.ts @@ -1,20 +1,20 @@ -import { Router } from '../lib/route-pass/Router'; -import { none, some } from '../lib/rust-like-utils-backend/Optional'; -import { filter } from '../lib/song/filter'; -import order from '../lib/song/order'; -import { indexMapper } from '../lib/song/indexMapper'; -import { Storage } from '../lib/storage/Storage'; - - +import { Router } from "../lib/route-pass/Router"; +import { none, some } from "../lib/rust-like-utils-backend/Optional"; +import { filter } from "../lib/song/filter"; +import order from "../lib/song/order"; +import { indexMapper } from "../lib/song/indexMapper"; +import { Storage } from "../lib/storage/Storage"; Router.respond("query::songsPool::init", (_evt, payload) => { const indexes = Storage.getTable("system").get("indexes"); + console.log(indexes); if (indexes.isNone) { return none(); } const filtered = filter(indexes.value, payload); + console.log(filtered); return some({ initialIndex: 0, @@ -22,8 +22,6 @@ Router.respond("query::songsPool::init", (_evt, payload) => { }); }); - - const BUFFER_SIZE = 50; Router.respond("query::songsPool", (_evt, request, payload) => { @@ -59,4 +57,4 @@ Router.respond("query::songsPool", (_evt, request, payload) => { total: songs.length, items: songs.slice(request.index * BUFFER_SIZE, (request.index + 1) * BUFFER_SIZE) }); -}); \ No newline at end of file +}); diff --git a/src/renderer/src/components/scenes/MainScene.tsx b/src/renderer/src/components/scenes/MainScene.tsx index 19d4dc1b..436e8b42 100644 --- a/src/renderer/src/components/scenes/MainScene.tsx +++ b/src/renderer/src/components/scenes/MainScene.tsx @@ -1,25 +1,22 @@ -import SongView from '../song/SongView'; -import { createEffect, createSignal, onMount } from 'solid-js'; -import Fa from 'solid-fa'; -import { faGear, faHeadphonesSimple, faListUl, faMusic } from '@fortawesome/free-solid-svg-icons'; -import { GLOBAL_ICON_SCALE } from '../../App'; -import SongDetail from '../song/SongDetail'; -import QueueView from '../queue/QueueView'; -import NoticeContainer from '../notice/NoticeContainer'; -import SettingsView from '../settings/SettingsView'; - - +import SongView from "../song/SongView"; +import { createEffect, createSignal, onMount } from "solid-js"; +import Fa from "solid-fa"; +import { faGear, faHeadphonesSimple, faListUl, faMusic } from "@fortawesome/free-solid-svg-icons"; +import { GLOBAL_ICON_SCALE } from "../../App"; +import SongDetail from "../song/SongDetail"; +import QueueView from "../queue/QueueView"; +import NoticeContainer from "../notice/NoticeContainer"; +import SettingsView from "../settings/SettingsView"; +import PlaylistView from "../song/PlaylistView"; const [active, setActive] = createSignal(0); -export { active } +export { active }; export const ACTIVE_ALL_SONGS = 0; export const ACTIVE_QUEUE = 1; export const ACTIVE_PLAYLISTS = 2; export const ACTIVE_SETTINGS = 3; - - export default function MainScene() { let sidePane; @@ -33,31 +30,31 @@ export default function MainScene() {
- - -
Playlists
- + + + +
- +
- +
); -} \ No newline at end of file +} diff --git a/src/renderer/src/components/song/PlaylistView.tsx b/src/renderer/src/components/song/PlaylistView.tsx new file mode 100644 index 00000000..80b1427b --- /dev/null +++ b/src/renderer/src/components/song/PlaylistView.tsx @@ -0,0 +1,114 @@ +import { Component, createEffect, createSignal, onCleanup, onMount } from "solid-js"; +import { Optional, ResourceID, SongsQueryPayload, Tag } from "../../../../@types"; +import { SearchQueryError } from "../../../../main/lib/search-parser/@search-types"; +import { namespace } from "../../App"; +import "../../assets/css/song/song-view.css"; +import Impulse from "../../lib/Impulse"; +import { none, some } from "../../lib/rust-like-utils-client/Optional"; +import InfiniteScroller from "../InfiniteScroller"; +import Search from "../search/Search"; +import PlayNext from "./context-menu/items/PlayNext"; +import SongItem from "./SongItem"; + +// export type SongViewProps = { +// isAllSongs?: boolean; +// isQueue?: boolean; +// playlist?: string; +// }; + +export type PlaylistViewProps = {}; + +const PlaylistView: Component = (props) => { + // const querySignal = createSignal(""); + // const [query] = querySignal; + + // const tagsSignal = createSignal([], { equals: false }); + // const [tags] = tagsSignal; + + // const [order, setOrder] = createSignal("title:asc"); + // const [count, setCount] = createSignal(0); + + // const [, setPayload] = createSignal({ + // view: props, + // order: order(), + // tags: tags() + // }); + + // const [searchError, setSearchError] = createSignal>(none(), { + // equals: false + // }); + // const resetListing = new Impulse(); + + // const searchSongs = async () => { + // const o = order(); + // const t = tags(); + // const parsedQuery = await window.api.request("parse::search", query()); + + // if (parsedQuery.type === "error") { + // setSearchError(some(parsedQuery)); + // return; + // } + + // setSearchError(none()); + // setPayload({ + // view: props, + // searchQuery: parsedQuery, + // order: o, + // tags: t + // }); + // resetListing.pulse(); + // }; + + // onMount(() => { + // createEffect(searchSongs); + // window.api.listen("songView::reset", resetListing.pulse.bind(resetListing)); + // }); + + // onCleanup(() => { + // window.api.removeListener("songView::reset", resetListing.pulse.bind(resetListing)); + // }); + + // const createQueue = async (songResource: ResourceID) => { + // console.log("create queue"); + + // await window.api.request("queue::create", { + // startSong: songResource, + // ...payload() + // }); + // }; + + const group = namespace.create(true); + + return ( +
+ yooo + {/* + */} + {/* + No songs...
} + builder={(s) => ( + + + + + )} + /> + */} + + ); +}; + +export default PlaylistView; diff --git a/src/renderer/src/components/song/SongView.tsx b/src/renderer/src/components/song/SongView.tsx index 0d3e1bf4..46271ffc 100644 --- a/src/renderer/src/components/song/SongView.tsx +++ b/src/renderer/src/components/song/SongView.tsx @@ -9,6 +9,7 @@ import InfiniteScroller from "../InfiniteScroller"; import Search from "../search/Search"; import PlayNext from "./context-menu/items/PlayNext"; import SongItem from "./SongItem"; +import AddToPlaylist from "./context-menu/items/AddToPlaylist"; export type SongViewProps = { isAllSongs?: boolean; @@ -98,7 +99,7 @@ const SongView: Component = (props) => { builder={(s) => ( - + )} /> diff --git a/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx b/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx new file mode 100644 index 00000000..987ecce2 --- /dev/null +++ b/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx @@ -0,0 +1,29 @@ +import { Component, createSignal, Show } from "solid-js"; +import { Song } from "../../../../../../@types"; +import SongContextMenuItem from "../SongContextMenuItem"; + +type SongAddToPlaylistNextProps = { + song: Song; +}; + +const AddToPlaylist: Component = (props) => { + const [show, setShow] = createSignal(false); + + window.api.listen("queue::created", () => { + setShow(true); + }); + + window.api.listen("queue::destroyed", () => { + setShow(false); + }); + + return ( + + console.log("click", props.song)}> + Add to Playlist + + + ); +}; + +export default AddToPlaylist; diff --git a/src/renderer/src/components/song/context-menu/items/PlayNext.tsx b/src/renderer/src/components/song/context-menu/items/PlayNext.tsx index f1a1993c..fe4d59b7 100644 --- a/src/renderer/src/components/song/context-menu/items/PlayNext.tsx +++ b/src/renderer/src/components/song/context-menu/items/PlayNext.tsx @@ -1,20 +1,14 @@ -import { Component, createSignal, Show } from 'solid-js'; -import { Song } from '../../../../../../@types'; -import SongContextMenuItem from '../SongContextMenuItem'; - - +import { Component, createSignal, Show } from "solid-js"; +import { Song } from "../../../../../../@types"; +import SongContextMenuItem from "../SongContextMenuItem"; type SongPlayNextProps = { - path: Song["path"] -} - - + path: Song["path"]; +}; -const PlayNext: Component = props => { +const PlayNext: Component = (props) => { const [show, setShow] = createSignal(false); - - window.api.listen("queue::created", () => { setShow(true); }); @@ -23,17 +17,13 @@ const PlayNext: Component = props => { setShow(false); }); - - return ( - window.api.request('queue::playNext', props.path)} - >Play Next + window.api.request("queue::playNext", props.path)}> + Play Next + ); }; - - -export default PlayNext; \ No newline at end of file +export default PlayNext; From fcaf442220c9ba5bf71cc33b27f9ce33cac6af49 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Wed, 9 Oct 2024 21:43:51 +0200 Subject: [PATCH 02/54] add playlist-router and playlist storage --- src/RequestAPI.d.ts | 5 +++++ src/main/router/import.ts | 1 + src/main/router/playlist-router.ts | 20 +++++++++++++++++++ .../song/context-menu/items/AddToPlaylist.tsx | 4 +++- 4 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/main/router/playlist-router.ts diff --git a/src/RequestAPI.d.ts b/src/RequestAPI.d.ts index f9606e2e..38b931fe 100644 --- a/src/RequestAPI.d.ts +++ b/src/RequestAPI.d.ts @@ -37,6 +37,11 @@ export type RequestAPI = { "queue::create": (payload: QueueCreatePayload) => void; "queue::shuffle": () => void; + "playlist::add": (playlistName: string, song: ResourceID) => void; + "playlist::remove": (song: ResourceID) => void; + "playlist::create": (name: string) => void; + "playlist::delete": (name: string) => void; + "dir::select": () => Optional; "dir::autoGetOsuDir": () => Optional; "dir::submit": (dir: string) => void; diff --git a/src/main/router/import.ts b/src/main/router/import.ts index 21daaaf7..6fe5b71e 100644 --- a/src/main/router/import.ts +++ b/src/main/router/import.ts @@ -11,3 +11,4 @@ import "./queue-router"; import "./resource-router"; import "./settings-router"; import "./songs-pool-router"; +import "./playlist-router"; diff --git a/src/main/router/playlist-router.ts b/src/main/router/playlist-router.ts new file mode 100644 index 00000000..74eb52fe --- /dev/null +++ b/src/main/router/playlist-router.ts @@ -0,0 +1,20 @@ +import { Router } from "../lib/route-pass/Router"; +import { Storage } from "../lib/storage/Storage"; + +Router.respond("playlist::add", (_evt, playlistName, song) => { + console.log("add this to " + playlistName + ": " + song); + + const playlists = Storage.getTable("playlists"); + let playlist = playlists.get(playlistName); + //temporary, playlist should already exist + if (playlist.isNone) { + // create playlist + playlists.write(playlistName, []); + } + playlist = playlists.get(playlistName); + + playlist.value.push(song); + playlists.write(playlistName, playlist.value); + console.log("MONKA", playlists); + console.log(playlist.value); +}); diff --git a/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx b/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx index 987ecce2..f2bae56d 100644 --- a/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx +++ b/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx @@ -19,7 +19,9 @@ const AddToPlaylist: Component = (props) => { return ( - console.log("click", props.song)}> + window.api.request("playlist::add", "PlaylistOne", props.song.path)} + > Add to Playlist From 2880308d24f2bddf914246cb5bb2f33f3da0967b Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Wed, 9 Oct 2024 22:23:10 +0200 Subject: [PATCH 03/54] show playlist name on the UI --- src/RequestAPI.d.ts | 2 + src/main/router/playlist-router.ts | 50 +++++++++++- .../src/components/song/PlaylistView.tsx | 80 +++---------------- 3 files changed, 60 insertions(+), 72 deletions(-) diff --git a/src/RequestAPI.d.ts b/src/RequestAPI.d.ts index 38b931fe..34124124 100644 --- a/src/RequestAPI.d.ts +++ b/src/RequestAPI.d.ts @@ -64,6 +64,8 @@ export type RequestAPI = { ) => InfiniteScrollerResponse; "query::queue::init": () => InfiniteScrollerInitResponse; "query::queue": (request: InfiniteScrollerRequest) => InfiniteScrollerResponse; + "query::playlists::init": () => InfiniteScrollerInitResponse; + "query::playlists": (request: InfiniteScrollerRequest) => InfiniteScrollerResponse; "save::localVolume": (volume: number, song: ResourceID) => void; diff --git a/src/main/router/playlist-router.ts b/src/main/router/playlist-router.ts index 74eb52fe..16d861df 100644 --- a/src/main/router/playlist-router.ts +++ b/src/main/router/playlist-router.ts @@ -1,4 +1,5 @@ import { Router } from "../lib/route-pass/Router"; +import { none, some } from "../lib/rust-like-utils-backend/Optional"; import { Storage } from "../lib/storage/Storage"; Router.respond("playlist::add", (_evt, playlistName, song) => { @@ -13,8 +14,55 @@ Router.respond("playlist::add", (_evt, playlistName, song) => { } playlist = playlists.get(playlistName); + //todo: check if song is already in playlist playlist.value.push(song); playlists.write(playlistName, playlist.value); - console.log("MONKA", playlists); + console.log( + "MONKA", + playlists.getStruct(), + Object.keys(Storage.getTable("playlists").getStruct()) + ); console.log(playlist.value); }); + +const BUFFER_SIZE = 50; + +Router.respond("query::playlists::init", (_evt) => { + const playlists = Storage.getTable("playlists").getStruct(); + const count = Object.keys(playlists).length; + + return some({ + initialIndex: 0, + count: count + }); +}); + +Router.respond("query::playlists", (_evt, request) => { + const playlists = Object.keys(Storage.getTable("playlists").getStruct()); + + if (request.index < 0 || request.index > Math.floor(playlists.length / BUFFER_SIZE)) { + return none(); + } + + const start = request.index * BUFFER_SIZE; + + if (request.direction === "up") { + return some({ + index: request.index - 1, + total: playlists.length, + items: playlists.slice(start, start + BUFFER_SIZE) + }); + } + + return some({ + index: request.index + 1, + total: playlists.length, + items: playlists.slice(start, start + BUFFER_SIZE) + }); + + return some({ + index: request.index + 1, + total: playlists.length, + items: playlists + }); +}); diff --git a/src/renderer/src/components/song/PlaylistView.tsx b/src/renderer/src/components/song/PlaylistView.tsx index 80b1427b..50ea1acd 100644 --- a/src/renderer/src/components/song/PlaylistView.tsx +++ b/src/renderer/src/components/song/PlaylistView.tsx @@ -19,69 +19,14 @@ import SongItem from "./SongItem"; export type PlaylistViewProps = {}; const PlaylistView: Component = (props) => { - // const querySignal = createSignal(""); - // const [query] = querySignal; - - // const tagsSignal = createSignal([], { equals: false }); - // const [tags] = tagsSignal; - - // const [order, setOrder] = createSignal("title:asc"); - // const [count, setCount] = createSignal(0); - - // const [, setPayload] = createSignal({ - // view: props, - // order: order(), - // tags: tags() - // }); - - // const [searchError, setSearchError] = createSignal>(none(), { - // equals: false - // }); - // const resetListing = new Impulse(); - - // const searchSongs = async () => { - // const o = order(); - // const t = tags(); - // const parsedQuery = await window.api.request("parse::search", query()); - - // if (parsedQuery.type === "error") { - // setSearchError(some(parsedQuery)); - // return; - // } - - // setSearchError(none()); - // setPayload({ - // view: props, - // searchQuery: parsedQuery, - // order: o, - // tags: t - // }); - // resetListing.pulse(); - // }; - - // onMount(() => { - // createEffect(searchSongs); - // window.api.listen("songView::reset", resetListing.pulse.bind(resetListing)); - // }); - - // onCleanup(() => { - // window.api.removeListener("songView::reset", resetListing.pulse.bind(resetListing)); - // }); - - // const createQueue = async (songResource: ResourceID) => { - // console.log("create queue"); - - // await window.api.request("queue::create", { - // startSong: songResource, - // ...payload() - // }); - // }; + const [count, setCount] = createSignal(0); + const resetListing = new Impulse(); + const [payload, setPayload] = createSignal({}); const group = namespace.create(true); return (
- yooo {/* = (props) => { error={searchError} /> */} - {/* No songs...
} - builder={(s) => ( - - - - - )} + fallback={
No playlists...
} + builder={(s) =>
{s}
} /> - */} ); }; From ee93ab13754fd5645937fabd6545d1924114381d Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Wed, 9 Oct 2024 22:56:33 +0200 Subject: [PATCH 04/54] add playlistItem --- src/main/router/playlist-router.ts | 12 ++--- .../src/components/playlist/PlaylistItem.tsx | 28 ++++++++++ .../src/components/playlist/PlaylistView.tsx | 41 +++++++++++++++ .../src/components/scenes/MainScene.tsx | 2 +- .../src/components/song/PlaylistView.tsx | 52 ------------------- 5 files changed, 75 insertions(+), 60 deletions(-) create mode 100644 src/renderer/src/components/playlist/PlaylistItem.tsx create mode 100644 src/renderer/src/components/playlist/PlaylistView.tsx delete mode 100644 src/renderer/src/components/song/PlaylistView.tsx diff --git a/src/main/router/playlist-router.ts b/src/main/router/playlist-router.ts index 16d861df..ee592746 100644 --- a/src/main/router/playlist-router.ts +++ b/src/main/router/playlist-router.ts @@ -40,7 +40,11 @@ Router.respond("query::playlists::init", (_evt) => { Router.respond("query::playlists", (_evt, request) => { const playlists = Object.keys(Storage.getTable("playlists").getStruct()); - if (request.index < 0 || request.index > Math.floor(playlists.length / BUFFER_SIZE)) { + if ( + playlists === undefined || + request.index < 0 || + request.index > Math.floor(playlists.length / BUFFER_SIZE) + ) { return none(); } @@ -59,10 +63,4 @@ Router.respond("query::playlists", (_evt, request) => { total: playlists.length, items: playlists.slice(start, start + BUFFER_SIZE) }); - - return some({ - index: request.index + 1, - total: playlists.length, - items: playlists - }); }); diff --git a/src/renderer/src/components/playlist/PlaylistItem.tsx b/src/renderer/src/components/playlist/PlaylistItem.tsx new file mode 100644 index 00000000..a0fc82ff --- /dev/null +++ b/src/renderer/src/components/playlist/PlaylistItem.tsx @@ -0,0 +1,28 @@ +import { Component } from "solid-js"; +import SongImage from "../song/SongImage"; + +type PlaylistItemProps = { + playlistName: string; + group: string; +}; + +const PlaylistItem: Component = (props) => { + return ( +
+
+ + +
+

{props.playlistName}

+

727 songs

+

7 hours 27 minutes

+
+
+
+ ); +}; + +export default PlaylistItem; diff --git a/src/renderer/src/components/playlist/PlaylistView.tsx b/src/renderer/src/components/playlist/PlaylistView.tsx new file mode 100644 index 00000000..6ec54d2d --- /dev/null +++ b/src/renderer/src/components/playlist/PlaylistView.tsx @@ -0,0 +1,41 @@ +import { Component, createSignal } from "solid-js"; +import "../../assets/css/song/song-view.css"; +import InfiniteScroller from "../InfiniteScroller"; +import PlaylistItem from "./PlaylistItem"; +import { namespace } from "@renderer/App"; + +export type PlaylistViewProps = {}; + +const PlaylistView: Component = (props) => { + const [count, setCount] = createSignal(0); + // const resetListing = new Impulse(); + // const [payload, setPayload] = createSignal({}); + + const group = namespace.create(true); + + return ( +
+ {/* + */} + You have {count()} playlists + No playlists...
} + builder={(s) => } + /> + + ); +}; + +export default PlaylistView; diff --git a/src/renderer/src/components/scenes/MainScene.tsx b/src/renderer/src/components/scenes/MainScene.tsx index 436e8b42..29b7b28c 100644 --- a/src/renderer/src/components/scenes/MainScene.tsx +++ b/src/renderer/src/components/scenes/MainScene.tsx @@ -7,7 +7,7 @@ import SongDetail from "../song/SongDetail"; import QueueView from "../queue/QueueView"; import NoticeContainer from "../notice/NoticeContainer"; import SettingsView from "../settings/SettingsView"; -import PlaylistView from "../song/PlaylistView"; +import PlaylistView from "../playlist/PlaylistView"; const [active, setActive] = createSignal(0); diff --git a/src/renderer/src/components/song/PlaylistView.tsx b/src/renderer/src/components/song/PlaylistView.tsx deleted file mode 100644 index 50ea1acd..00000000 --- a/src/renderer/src/components/song/PlaylistView.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { Component, createEffect, createSignal, onCleanup, onMount } from "solid-js"; -import { Optional, ResourceID, SongsQueryPayload, Tag } from "../../../../@types"; -import { SearchQueryError } from "../../../../main/lib/search-parser/@search-types"; -import { namespace } from "../../App"; -import "../../assets/css/song/song-view.css"; -import Impulse from "../../lib/Impulse"; -import { none, some } from "../../lib/rust-like-utils-client/Optional"; -import InfiniteScroller from "../InfiniteScroller"; -import Search from "../search/Search"; -import PlayNext from "./context-menu/items/PlayNext"; -import SongItem from "./SongItem"; - -// export type SongViewProps = { -// isAllSongs?: boolean; -// isQueue?: boolean; -// playlist?: string; -// }; - -export type PlaylistViewProps = {}; - -const PlaylistView: Component = (props) => { - const [count, setCount] = createSignal(0); - const resetListing = new Impulse(); - const [payload, setPayload] = createSignal({}); - - const group = namespace.create(true); - - return ( -
- {/* - */} - No playlists...
} - builder={(s) =>
{s}
} - /> - - ); -}; - -export default PlaylistView; From 1dbb91b3aa6b166d247efa012d417370b2efeb72 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Wed, 9 Oct 2024 23:22:31 +0200 Subject: [PATCH 05/54] Switched to songs instead of ResourceIDs, implemented PlaylistSongs api --- src/@types.d.ts | 2 +- src/RequestAPI.d.ts | 9 ++++- src/main/router/playlist-router.ts | 38 ++++++++++++++++++ .../components/playlist/PlaylistSongsView.tsx | 40 +++++++++++++++++++ .../src/components/playlist/PlaylistView.tsx | 1 + .../song/context-menu/items/AddToPlaylist.tsx | 2 +- 6 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 src/renderer/src/components/playlist/PlaylistSongsView.tsx diff --git a/src/@types.d.ts b/src/@types.d.ts index 0b7e4430..e840d5ae 100644 --- a/src/@types.d.ts +++ b/src/@types.d.ts @@ -121,7 +121,7 @@ export type TableMap = { songs: { [key: ResourceID]: Song }; audio: { [key: ResourceID]: AudioSource }; images: { [key: ResourceID]: ImageSource }; - playlists: { [key: string]: ResourceID[] }; + playlists: { [key: string]: Song[] }; settings: Settings; system: System; }; diff --git a/src/RequestAPI.d.ts b/src/RequestAPI.d.ts index 34124124..7e403ec9 100644 --- a/src/RequestAPI.d.ts +++ b/src/RequestAPI.d.ts @@ -37,8 +37,8 @@ export type RequestAPI = { "queue::create": (payload: QueueCreatePayload) => void; "queue::shuffle": () => void; - "playlist::add": (playlistName: string, song: ResourceID) => void; - "playlist::remove": (song: ResourceID) => void; + "playlist::add": (playlistName: string, song: Song) => void; + "playlist::remove": (song: Song) => void; "playlist::create": (name: string) => void; "playlist::delete": (name: string) => void; @@ -66,6 +66,11 @@ export type RequestAPI = { "query::queue": (request: InfiniteScrollerRequest) => InfiniteScrollerResponse; "query::playlists::init": () => InfiniteScrollerInitResponse; "query::playlists": (request: InfiniteScrollerRequest) => InfiniteScrollerResponse; + "query::playlistSongs::init": (playlistName: string) => InfiniteScrollerInitResponse; + "query::playlistSongs": ( + playlistName: string, + request: InfiniteScrollerRequest + ) => InfiniteScrollerResponse; "save::localVolume": (volume: number, song: ResourceID) => void; diff --git a/src/main/router/playlist-router.ts b/src/main/router/playlist-router.ts index ee592746..fea6a601 100644 --- a/src/main/router/playlist-router.ts +++ b/src/main/router/playlist-router.ts @@ -64,3 +64,41 @@ Router.respond("query::playlists", (_evt, request) => { items: playlists.slice(start, start + BUFFER_SIZE) }); }); + +Router.respond("query::playlistSongs::init", (_evt, playlistName) => { + const songs = Storage.getTable("playlists").get(playlistName); + const count = Object.keys(songs).length; + + return some({ + initialIndex: 0, + count: count + }); +}); + +Router.respond("query::playlistSongs", (_evt, playlistName, request) => { + const songs = Storage.getTable("playlists").get(playlistName).value; + + if ( + songs === undefined || + request.index < 0 || + request.index > Math.floor(songs.length / BUFFER_SIZE) + ) { + return none(); + } + + const start = request.index * BUFFER_SIZE; + + if (request.direction === "up") { + return some({ + index: request.index - 1, + total: songs.length, + items: songs.slice(start, start + BUFFER_SIZE) + }); + } + + return some({ + index: request.index + 1, + total: songs.length, + items: songs.slice(start, start + BUFFER_SIZE) + }); +}); diff --git a/src/renderer/src/components/playlist/PlaylistSongsView.tsx b/src/renderer/src/components/playlist/PlaylistSongsView.tsx new file mode 100644 index 00000000..f44ec72c --- /dev/null +++ b/src/renderer/src/components/playlist/PlaylistSongsView.tsx @@ -0,0 +1,40 @@ +import { Component } from "solid-js"; +import InfiniteScroller from "../InfiniteScroller"; +import SongItem from "../song/SongItem"; +import SongContextMenuItem from "../song/context-menu/SongContextMenuItem"; + +type PlaylistSongsProps = { + playlistName: string; + group: string; +}; + +const PlaylistSongsView: Component = (props) => { + return ( +
+ No queue...
} + builder={(s) => ( + window.api.request("queue::play", s.path)} + // onDrop={onDrop(s)} + > + {/* window.api.request("queue::removeSong", s.path)}> + Remove from queue + */} + + )} + /> + + ); +}; + +export default PlaylistSongsView; diff --git a/src/renderer/src/components/playlist/PlaylistView.tsx b/src/renderer/src/components/playlist/PlaylistView.tsx index 6ec54d2d..09feee27 100644 --- a/src/renderer/src/components/playlist/PlaylistView.tsx +++ b/src/renderer/src/components/playlist/PlaylistView.tsx @@ -13,6 +13,7 @@ const PlaylistView: Component = (props) => { const group = namespace.create(true); + //todo: make something like App.tsx or MainScene.tsx to load a playlist (scene signal) or something with Routers return (
{/* = (props) => { return ( window.api.request("playlist::add", "PlaylistOne", props.song.path)} + onClick={() => window.api.request("playlist::add", "PlaylistOne", props.song)} > Add to Playlist From 342e3b4387290532b33ec8b65f16d12196783473 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Thu, 10 Oct 2024 19:04:49 +0200 Subject: [PATCH 06/54] changed router type from Song[] to Playlist, playlist info shown on ui --- src/@types.d.ts | 9 ++++- src/RequestAPI.d.ts | 3 +- src/main/router/playlist-router.ts | 39 +++++++++++++------ src/main/router/songs-pool-router.ts | 4 +- .../src/components/playlist/PlaylistItem.tsx | 9 +++-- .../src/components/playlist/PlaylistView.tsx | 2 +- 6 files changed, 46 insertions(+), 20 deletions(-) diff --git a/src/@types.d.ts b/src/@types.d.ts index e840d5ae..758528cc 100644 --- a/src/@types.d.ts +++ b/src/@types.d.ts @@ -121,11 +121,18 @@ export type TableMap = { songs: { [key: ResourceID]: Song }; audio: { [key: ResourceID]: AudioSource }; images: { [key: ResourceID]: ImageSource }; - playlists: { [key: string]: Song[] }; + playlists: { [key: string]: Playlist }; settings: Settings; system: System; }; +export type Playlist = { + name: string; + count: number; + length: number; // total length in seconds + songs: Song[]; +}; + // I guess this is definition of all binary blob files that can be access from the database code? export type BlobMap = { times; diff --git a/src/RequestAPI.d.ts b/src/RequestAPI.d.ts index 7e403ec9..c3ef8a34 100644 --- a/src/RequestAPI.d.ts +++ b/src/RequestAPI.d.ts @@ -5,6 +5,7 @@ import type { InfiniteScrollerRequest, InfiniteScrollerResponse, Optional, + Playlist, QueueCreatePayload, ResourceID, ResourceTables, @@ -65,7 +66,7 @@ export type RequestAPI = { "query::queue::init": () => InfiniteScrollerInitResponse; "query::queue": (request: InfiniteScrollerRequest) => InfiniteScrollerResponse; "query::playlists::init": () => InfiniteScrollerInitResponse; - "query::playlists": (request: InfiniteScrollerRequest) => InfiniteScrollerResponse; + "query::playlists": (request: InfiniteScrollerRequest) => InfiniteScrollerResponse; "query::playlistSongs::init": (playlistName: string) => InfiniteScrollerInitResponse; "query::playlistSongs": ( playlistName: string, diff --git a/src/main/router/playlist-router.ts b/src/main/router/playlist-router.ts index fea6a601..95f177a0 100644 --- a/src/main/router/playlist-router.ts +++ b/src/main/router/playlist-router.ts @@ -1,3 +1,4 @@ +import { Playlist } from "../../@types"; import { Router } from "../lib/route-pass/Router"; import { none, some } from "../lib/rust-like-utils-backend/Optional"; import { Storage } from "../lib/storage/Storage"; @@ -5,17 +6,20 @@ import { Storage } from "../lib/storage/Storage"; Router.respond("playlist::add", (_evt, playlistName, song) => { console.log("add this to " + playlistName + ": " + song); + //Storage.removeTable("playlists"); const playlists = Storage.getTable("playlists"); let playlist = playlists.get(playlistName); //temporary, playlist should already exist if (playlist.isNone) { // create playlist - playlists.write(playlistName, []); + const empty = { count: 0, length: 0, songs: [] }; + playlists.write(playlistName, empty); } playlist = playlists.get(playlistName); - //todo: check if song is already in playlist - playlist.value.push(song); + playlist.value.songs.push(song); + playlist.value.count = playlist.value.count + 1; + playlist.value.length = playlist.value.length + song.duration; playlists.write(playlistName, playlist.value); console.log( "MONKA", @@ -40,10 +44,23 @@ Router.respond("query::playlists::init", (_evt) => { Router.respond("query::playlists", (_evt, request) => { const playlists = Object.keys(Storage.getTable("playlists").getStruct()); + //todo: there has to be a better way to do this + const p = Storage.getTable("playlists"); + let test: Playlist[] = []; + playlists.forEach((v) => { + const plist = p.get(v); + test.push({ + name: v, + count: plist.value.count, + length: plist.value.length, + songs: plist.value.songs + }); + }); + if ( - playlists === undefined || + test === undefined || request.index < 0 || - request.index > Math.floor(playlists.length / BUFFER_SIZE) + request.index > Math.floor(test.length / BUFFER_SIZE) ) { return none(); } @@ -53,21 +70,21 @@ Router.respond("query::playlists", (_evt, request) => { if (request.direction === "up") { return some({ index: request.index - 1, - total: playlists.length, - items: playlists.slice(start, start + BUFFER_SIZE) + total: test.length, + items: test.slice(start, start + BUFFER_SIZE) }); } return some({ index: request.index + 1, - total: playlists.length, - items: playlists.slice(start, start + BUFFER_SIZE) + total: test.length, + items: test.slice(start, start + BUFFER_SIZE) }); }); Router.respond("query::playlistSongs::init", (_evt, playlistName) => { const songs = Storage.getTable("playlists").get(playlistName); - const count = Object.keys(songs).length; + const count = Object.keys(songs.value.songs).length; return some({ initialIndex: 0, @@ -76,7 +93,7 @@ Router.respond("query::playlistSongs::init", (_evt, playlistName) => { }); Router.respond("query::playlistSongs", (_evt, playlistName, request) => { - const songs = Storage.getTable("playlists").get(playlistName).value; + const songs = Storage.getTable("playlists").get(playlistName).value.songs; if ( songs === undefined || diff --git a/src/main/router/songs-pool-router.ts b/src/main/router/songs-pool-router.ts index 2795b2fe..4f30060e 100644 --- a/src/main/router/songs-pool-router.ts +++ b/src/main/router/songs-pool-router.ts @@ -7,14 +7,14 @@ import { Storage } from "../lib/storage/Storage"; Router.respond("query::songsPool::init", (_evt, payload) => { const indexes = Storage.getTable("system").get("indexes"); - console.log(indexes); + //console.log(indexes); if (indexes.isNone) { return none(); } const filtered = filter(indexes.value, payload); - console.log(filtered); + // console.log(filtered); return some({ initialIndex: 0, diff --git a/src/renderer/src/components/playlist/PlaylistItem.tsx b/src/renderer/src/components/playlist/PlaylistItem.tsx index a0fc82ff..ff9c8ef7 100644 --- a/src/renderer/src/components/playlist/PlaylistItem.tsx +++ b/src/renderer/src/components/playlist/PlaylistItem.tsx @@ -1,8 +1,9 @@ import { Component } from "solid-js"; import SongImage from "../song/SongImage"; +import { Playlist } from "src/@types"; type PlaylistItemProps = { - playlistName: string; + playlist: Playlist; group: string; }; @@ -16,9 +17,9 @@ const PlaylistItem: Component = (props) => { />
-

{props.playlistName}

-

727 songs

-

7 hours 27 minutes

+

{props.playlist.name}

+

{props.playlist.count} songs

+

{props.playlist.length}

diff --git a/src/renderer/src/components/playlist/PlaylistView.tsx b/src/renderer/src/components/playlist/PlaylistView.tsx index 09feee27..d86b1d53 100644 --- a/src/renderer/src/components/playlist/PlaylistView.tsx +++ b/src/renderer/src/components/playlist/PlaylistView.tsx @@ -33,7 +33,7 @@ const PlaylistView: Component = (props) => { setCount={setCount} // reset={resetListing} fallback={
No playlists...
} - builder={(s) => } + builder={(s) => } /> ); From af9072422901b16d6c5d37ad2d381c24544f2f23 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Fri, 11 Oct 2024 01:07:07 +0200 Subject: [PATCH 07/54] implement the other playlist request APIs --- src/RequestAPI.d.ts | 4 +- src/main/router/playlist-router.ts | 43 +++++++++++++++---- .../src/components/playlist/PlaylistItem.tsx | 22 +++++++++- .../components/playlist/PlaylistSongsView.tsx | 3 +- .../src/components/playlist/PlaylistView.tsx | 3 +- 5 files changed, 60 insertions(+), 15 deletions(-) diff --git a/src/RequestAPI.d.ts b/src/RequestAPI.d.ts index 61fa56cb..17a0d591 100644 --- a/src/RequestAPI.d.ts +++ b/src/RequestAPI.d.ts @@ -39,7 +39,7 @@ export type RequestAPI = { "queue::shuffle": () => void; "playlist::add": (playlistName: string, song: Song) => void; - "playlist::remove": (song: Song) => void; + "playlist::remove": (playlistName: string, song: Song) => void; "playlist::create": (name: string) => void; "playlist::delete": (name: string) => void; @@ -70,7 +70,7 @@ export type RequestAPI = { "query::playlistSongs::init": (playlistName: string) => InfiniteScrollerInitResponse; "query::playlistSongs": ( playlistName: string, - request: InfiniteScrollerRequest + request: InfiniteScrollerRequest, ) => InfiniteScrollerResponse; "save::localVolume": (volume: number, song: ResourceID) => void; diff --git a/src/main/router/playlist-router.ts b/src/main/router/playlist-router.ts index 95f177a0..45af8148 100644 --- a/src/main/router/playlist-router.ts +++ b/src/main/router/playlist-router.ts @@ -12,7 +12,7 @@ Router.respond("playlist::add", (_evt, playlistName, song) => { //temporary, playlist should already exist if (playlist.isNone) { // create playlist - const empty = { count: 0, length: 0, songs: [] }; + const empty = { name: playlistName, count: 0, length: 0, songs: [] }; playlists.write(playlistName, empty); } playlist = playlists.get(playlistName); @@ -24,11 +24,36 @@ Router.respond("playlist::add", (_evt, playlistName, song) => { console.log( "MONKA", playlists.getStruct(), - Object.keys(Storage.getTable("playlists").getStruct()) + Object.keys(Storage.getTable("playlists").getStruct()), ); console.log(playlist.value); }); +Router.respond("playlist::create", (_evt, name) => { + console.log("create playlist " + name); + //todo: check if playlist already exists + const playlists = Storage.getTable("playlists"); + const empty = { name: name, count: 0, length: 0, songs: [] }; + playlists.write(name, empty); +}); + +Router.respond("playlist::delete", (_evt, name) => { + console.log("delete playlist " + name); + const playlists = Storage.getTable("playlists"); + playlists.delete(name); +}); + +Router.respond("playlist::remove", (_evt, playlistName, song) => { + console.log("delete song from " + playlistName, song); + const playlists = Storage.getTable("playlists"); + let playlist = playlists.get(playlistName); + const songIndex = playlist.value.songs.indexOf(song, 0); + if (songIndex > -1) { + playlist.value.songs.splice(songIndex, 1); + playlists.write(playlistName, playlist); + } +}); + const BUFFER_SIZE = 50; Router.respond("query::playlists::init", (_evt) => { @@ -37,7 +62,7 @@ Router.respond("query::playlists::init", (_evt) => { return some({ initialIndex: 0, - count: count + count: count, }); }); @@ -53,7 +78,7 @@ Router.respond("query::playlists", (_evt, request) => { name: v, count: plist.value.count, length: plist.value.length, - songs: plist.value.songs + songs: plist.value.songs, }); }); @@ -71,14 +96,14 @@ Router.respond("query::playlists", (_evt, request) => { return some({ index: request.index - 1, total: test.length, - items: test.slice(start, start + BUFFER_SIZE) + items: test.slice(start, start + BUFFER_SIZE), }); } return some({ index: request.index + 1, total: test.length, - items: test.slice(start, start + BUFFER_SIZE) + items: test.slice(start, start + BUFFER_SIZE), }); }); @@ -88,7 +113,7 @@ Router.respond("query::playlistSongs::init", (_evt, playlistName) => { return some({ initialIndex: 0, - count: count + count: count, }); }); @@ -109,13 +134,13 @@ Router.respond("query::playlistSongs", (_evt, playlistName, request) => { return some({ index: request.index - 1, total: songs.length, - items: songs.slice(start, start + BUFFER_SIZE) + items: songs.slice(start, start + BUFFER_SIZE), }); } return some({ index: request.index + 1, total: songs.length, - items: songs.slice(start, start + BUFFER_SIZE) + items: songs.slice(start, start + BUFFER_SIZE), }); }); diff --git a/src/renderer/src/components/playlist/PlaylistItem.tsx b/src/renderer/src/components/playlist/PlaylistItem.tsx index ff9c8ef7..e16058a7 100644 --- a/src/renderer/src/components/playlist/PlaylistItem.tsx +++ b/src/renderer/src/components/playlist/PlaylistItem.tsx @@ -7,9 +7,27 @@ type PlaylistItemProps = { group: string; }; +function formatPlaylistTime(seconds: number) { + let minutes = 0; + let hours = 0; + if (seconds > 60) { + minutes = Math.floor(seconds / 60); + if (minutes > 60) { + hours = Math.floor(minutes / 60); + } + } + + return hours + " hours " + minutes + " minutes"; +} + const PlaylistItem: Component = (props) => { return ( -
+
{ + console.log(props.playlist.songs); + }} + >
= (props) => {

{props.playlist.name}

{props.playlist.count} songs

-

{props.playlist.length}

+

{formatPlaylistTime(Math.round(props.playlist.length))}

diff --git a/src/renderer/src/components/playlist/PlaylistSongsView.tsx b/src/renderer/src/components/playlist/PlaylistSongsView.tsx index f44ec72c..ad7547df 100644 --- a/src/renderer/src/components/playlist/PlaylistSongsView.tsx +++ b/src/renderer/src/components/playlist/PlaylistSongsView.tsx @@ -13,11 +13,12 @@ const PlaylistSongsView: Component = (props) => {
No queue...
} + fallback={
No songs...
} builder={(s) => ( Date: Fri, 11 Oct 2024 23:03:33 +0200 Subject: [PATCH 08/54] basic playlist functionality on new ui --- .../src/components/playlist/PlaylistItem.tsx | 6 +- .../src/components/playlist/PlaylistView.tsx | 25 +++++++- .../src/components/scenes/MainScene.tsx | 60 ------------------- .../song/song-detail/SongControls.tsx | 3 +- .../components/song/song-list/SongList.tsx | 3 +- .../src/scenes/main-scene/MainScene.tsx | 4 ++ .../src/scenes/main-scene/main.utils.ts | 5 ++ 7 files changed, 40 insertions(+), 66 deletions(-) delete mode 100644 src/renderer/src/components/scenes/MainScene.tsx diff --git a/src/renderer/src/components/playlist/PlaylistItem.tsx b/src/renderer/src/components/playlist/PlaylistItem.tsx index e16058a7..b87b0033 100644 --- a/src/renderer/src/components/playlist/PlaylistItem.tsx +++ b/src/renderer/src/components/playlist/PlaylistItem.tsx @@ -1,6 +1,7 @@ import { Component } from "solid-js"; import SongImage from "../song/SongImage"; import { Playlist } from "src/@types"; +import IconButton from "../icon-button/IconButton"; type PlaylistItemProps = { playlist: Playlist; @@ -23,7 +24,7 @@ function formatPlaylistTime(seconds: number) { const PlaylistItem: Component = (props) => { return (
{ console.log(props.playlist.songs); }} @@ -38,6 +39,9 @@ const PlaylistItem: Component = (props) => {

{props.playlist.name}

{props.playlist.count} songs

{formatPlaylistTime(Math.round(props.playlist.length))}

+ window.api.request("playlist::delete", props.playlist.name)}> + +
diff --git a/src/renderer/src/components/playlist/PlaylistView.tsx b/src/renderer/src/components/playlist/PlaylistView.tsx index 1a42c3c6..2791aa46 100644 --- a/src/renderer/src/components/playlist/PlaylistView.tsx +++ b/src/renderer/src/components/playlist/PlaylistView.tsx @@ -4,13 +4,21 @@ import InfiniteScroller from "../InfiniteScroller"; import PlaylistItem from "./PlaylistItem"; import { namespace } from "@renderer/App"; import Impulse from "@renderer/lib/Impulse"; +import IconButton from "../icon-button/IconButton"; export type PlaylistViewProps = {}; + const PlaylistView: Component = (props) => { const [count, setCount] = createSignal(0); - // const resetListing = new Impulse(); + const resetListing = new Impulse(); // const [payload, setPayload] = createSignal({}); + const [playlistName, setPlaylistName] = createSignal(""); + + const createPlaylist = () => { + window.api.request("playlist::create", playlistName()); + setPlaylistName(""); + } const group = namespace.create(true); @@ -25,14 +33,25 @@ const PlaylistView: Component = (props) => { error={searchError} /> */} - You have {count()} playlists + + +

You have {count()} playlists

No playlists...} builder={(s) => } /> diff --git a/src/renderer/src/components/scenes/MainScene.tsx b/src/renderer/src/components/scenes/MainScene.tsx deleted file mode 100644 index 29b7b28c..00000000 --- a/src/renderer/src/components/scenes/MainScene.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import SongView from "../song/SongView"; -import { createEffect, createSignal, onMount } from "solid-js"; -import Fa from "solid-fa"; -import { faGear, faHeadphonesSimple, faListUl, faMusic } from "@fortawesome/free-solid-svg-icons"; -import { GLOBAL_ICON_SCALE } from "../../App"; -import SongDetail from "../song/SongDetail"; -import QueueView from "../queue/QueueView"; -import NoticeContainer from "../notice/NoticeContainer"; -import SettingsView from "../settings/SettingsView"; -import PlaylistView from "../playlist/PlaylistView"; - -const [active, setActive] = createSignal(0); - -export { active }; -export const ACTIVE_ALL_SONGS = 0; -export const ACTIVE_QUEUE = 1; -export const ACTIVE_PLAYLISTS = 2; -export const ACTIVE_SETTINGS = 3; - -export default function MainScene() { - let sidePane; - - onMount(() => { - createEffect(() => { - sidePane.children[active()]?.scrollIntoView(); - }); - }); - - return ( -
- - -
- - - - -
- -
- -
- - -
- ); -} diff --git a/src/renderer/src/components/song/song-detail/SongControls.tsx b/src/renderer/src/components/song/song-detail/SongControls.tsx index e2c94c8d..3a5c24e8 100644 --- a/src/renderer/src/components/song/song-detail/SongControls.tsx +++ b/src/renderer/src/components/song/song-detail/SongControls.tsx @@ -94,7 +94,8 @@ const SongControls: Component = () => { {/* Right part */}
- + {/* // TODO - modal or something so the user can select a playlist */} + window.api.request("playlist::add", "test", song())} title="Add to playlist">
diff --git a/src/renderer/src/components/song/song-list/SongList.tsx b/src/renderer/src/components/song/song-list/SongList.tsx index c2c434c9..7ed064a8 100644 --- a/src/renderer/src/components/song/song-list/SongList.tsx +++ b/src/renderer/src/components/song/song-list/SongList.tsx @@ -4,6 +4,7 @@ import { namespace } from "../../../App"; import Impulse from "../../../lib/Impulse"; import { none, some } from "../../../lib/rust-like-utils-client/Optional"; import InfiniteScroller from "../../InfiniteScroller"; +import AddToPlaylist from "../context-menu/items/AddToPlaylist"; import PlayNext from "../context-menu/items/PlayNext"; import SongItem from "../song-item/SongItem"; import SongListSearch from "../song-list-search/SongListSearch"; @@ -91,7 +92,7 @@ const SongList: Component = (props) => { builder={(s) => ( - + )} /> diff --git a/src/renderer/src/scenes/main-scene/MainScene.tsx b/src/renderer/src/scenes/main-scene/MainScene.tsx index ebff102d..bcfcb4a4 100644 --- a/src/renderer/src/scenes/main-scene/MainScene.tsx +++ b/src/renderer/src/scenes/main-scene/MainScene.tsx @@ -1,3 +1,4 @@ +import PlaylistView from "@renderer/components/playlist/PlaylistView"; import SongDetail from "../../components/song/song-detail/SongDetail"; import SongList from "../../components/song/song-list/SongList"; import { mainActiveTab, setMainActiveTab, Tab, TABS } from "./main.utils"; @@ -72,6 +73,9 @@ const TabContent: Component = () => { + + + diff --git a/src/renderer/src/scenes/main-scene/main.utils.ts b/src/renderer/src/scenes/main-scene/main.utils.ts index f8451609..e1b22072 100644 --- a/src/renderer/src/scenes/main-scene/main.utils.ts +++ b/src/renderer/src/scenes/main-scene/main.utils.ts @@ -12,6 +12,11 @@ export const TABS = { value: "songs", icon: "ri-music-fill", }, + PLAYLISTS: { + label: "Playlists", + value: "playlists", + icon: "ri-settings-fill", + }, SETTINGS: { label: "Settings", value: "settings", From 3b360dc39a5b47f851c82b770463dc7c20c86a1a Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Fri, 11 Oct 2024 23:23:45 +0200 Subject: [PATCH 09/54] changed file structure to be in line with the rest --- .../playlist/{ => playlist-item}/PlaylistItem.tsx | 4 ++-- .../PlaylistSongList.tsx} | 12 ++++++------ .../playlist/{ => playlist-view}/PlaylistView.tsx | 8 ++++---- src/renderer/src/scenes/main-scene/MainScene.tsx | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) rename src/renderer/src/components/playlist/{ => playlist-item}/PlaylistItem.tsx (92%) rename src/renderer/src/components/playlist/{PlaylistSongsView.tsx => playlist-song-list/PlaylistSongList.tsx} (73%) rename src/renderer/src/components/playlist/{ => playlist-view}/PlaylistView.tsx (89%) diff --git a/src/renderer/src/components/playlist/PlaylistItem.tsx b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx similarity index 92% rename from src/renderer/src/components/playlist/PlaylistItem.tsx rename to src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx index b87b0033..c1b69572 100644 --- a/src/renderer/src/components/playlist/PlaylistItem.tsx +++ b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx @@ -1,7 +1,7 @@ import { Component } from "solid-js"; -import SongImage from "../song/SongImage"; +import SongImage from "../../song/SongImage"; import { Playlist } from "src/@types"; -import IconButton from "../icon-button/IconButton"; +import IconButton from "../../icon-button/IconButton"; type PlaylistItemProps = { playlist: Playlist; diff --git a/src/renderer/src/components/playlist/PlaylistSongsView.tsx b/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx similarity index 73% rename from src/renderer/src/components/playlist/PlaylistSongsView.tsx rename to src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx index ad7547df..1ada9266 100644 --- a/src/renderer/src/components/playlist/PlaylistSongsView.tsx +++ b/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx @@ -1,14 +1,14 @@ import { Component } from "solid-js"; -import InfiniteScroller from "../InfiniteScroller"; -import SongItem from "../song/SongItem"; -import SongContextMenuItem from "../song/context-menu/SongContextMenuItem"; +import InfiniteScroller from "../../InfiniteScroller"; +import SongContextMenuItem from "../../song/context-menu/SongContextMenuItem"; +import SongItem from "../../song/song-item/SongItem"; -type PlaylistSongsProps = { +type PlaylistSongListProps = { playlistName: string; group: string; }; -const PlaylistSongsView: Component = (props) => { +const PlaylistSongList: Component = (props) => { return (
= (props) => { ); }; -export default PlaylistSongsView; +export default PlaylistSongList; diff --git a/src/renderer/src/components/playlist/PlaylistView.tsx b/src/renderer/src/components/playlist/playlist-view/PlaylistView.tsx similarity index 89% rename from src/renderer/src/components/playlist/PlaylistView.tsx rename to src/renderer/src/components/playlist/playlist-view/PlaylistView.tsx index 2791aa46..c802f61d 100644 --- a/src/renderer/src/components/playlist/PlaylistView.tsx +++ b/src/renderer/src/components/playlist/playlist-view/PlaylistView.tsx @@ -1,10 +1,10 @@ import { Component, createSignal, onCleanup, onMount } from "solid-js"; -import "../../assets/css/song/song-view.css"; -import InfiniteScroller from "../InfiniteScroller"; -import PlaylistItem from "./PlaylistItem"; +import "../../../assets/css/song/song-view.css"; +import InfiniteScroller from "../../InfiniteScroller"; +import PlaylistItem from "../playlist-item/PlaylistItem"; import { namespace } from "@renderer/App"; import Impulse from "@renderer/lib/Impulse"; -import IconButton from "../icon-button/IconButton"; +import IconButton from "../../icon-button/IconButton"; export type PlaylistViewProps = {}; diff --git a/src/renderer/src/scenes/main-scene/MainScene.tsx b/src/renderer/src/scenes/main-scene/MainScene.tsx index bcfcb4a4..8cee7f04 100644 --- a/src/renderer/src/scenes/main-scene/MainScene.tsx +++ b/src/renderer/src/scenes/main-scene/MainScene.tsx @@ -1,4 +1,4 @@ -import PlaylistView from "@renderer/components/playlist/PlaylistView"; +import PlaylistView from "@renderer/components/playlist/playlist-view/PlaylistView"; import SongDetail from "../../components/song/song-detail/SongDetail"; import SongList from "../../components/song/song-list/SongList"; import { mainActiveTab, setMainActiveTab, Tab, TABS } from "./main.utils"; From 512a25b314f77f3010d6bd1d377f33893a4653f3 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Sat, 12 Oct 2024 00:56:31 +0200 Subject: [PATCH 10/54] playlistItem styling --- .../playlist/playlist-item/PlaylistItem.tsx | 42 ++++++++++----- .../playlist/playlist-item/styles.css | 52 +++++++++++++++++++ .../playlist/playlist-view/PlaylistView.tsx | 4 +- .../src/scenes/main-scene/main.utils.ts | 2 +- 4 files changed, 84 insertions(+), 16 deletions(-) create mode 100644 src/renderer/src/components/playlist/playlist-item/styles.css diff --git a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx index c1b69572..18170e27 100644 --- a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx +++ b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx @@ -2,6 +2,7 @@ import { Component } from "solid-js"; import SongImage from "../../song/SongImage"; import { Playlist } from "src/@types"; import IconButton from "../../icon-button/IconButton"; +import "./styles.css"; type PlaylistItemProps = { playlist: Playlist; @@ -21,27 +22,42 @@ function formatPlaylistTime(seconds: number) { return hours + " hours " + minutes + " minutes"; } +function getSongImage(playlist: Playlist) { + const songs = playlist.songs + if(songs.length === 0 || songs[0].bg === undefined || songs[0].bg === "") { + return ""; + } else { + return songs[0].bg; + } +} + const PlaylistItem: Component = (props) => { return (
{ console.log(props.playlist.songs); }} > -
- +
+
+ +
-
-

{props.playlist.name}

-

{props.playlist.count} songs

-

{formatPlaylistTime(Math.round(props.playlist.length))}

- window.api.request("playlist::delete", props.playlist.name)}> - - +
+
+

{props.playlist.name}

+

{props.playlist.count} songs

+ {/*

{formatPlaylistTime(Math.round(props.playlist.length))}

*/} +
+
+ window.api.request("playlist::delete", props.playlist.name)}> + + +
diff --git a/src/renderer/src/components/playlist/playlist-item/styles.css b/src/renderer/src/components/playlist/playlist-item/styles.css new file mode 100644 index 00000000..6833846c --- /dev/null +++ b/src/renderer/src/components/playlist/playlist-item/styles.css @@ -0,0 +1,52 @@ +.playlist-item { + --image-size: 70px; + + .playlist-item-container { + margin-top: 20px; + margin-left: 8px; + display: flex; + flex-direction: row; + + .playlist-item__playlist-img { + margin: auto 6px auto 6px; + border-radius: var(--rounded-lg); + .song-image { + width: var(--image-size); + height: var(--image-size); + background-size: cover; + background-position: center; + border-radius: var(--rounded-lg); + } + + } + + .playlist-item__playlist-info { + display: flex; + flex-direction: row; + margin-left: 6px; + justify-content: space-between; + width: 100%; + + .playlist-item__playlist-info__text { + display: flex; + flex-direction: column; + justify-content: center; + font-weight: 300; + line-height: 24px; + } + + .playlist-item__playlist-info__text h3 { + font-size: 28px; + } + + .playlist-item__playlist-info__button { + display: flex; + flex-direction: column; + justify-content: center; + margin-right: 8px; + color: lightcoral; + + } + } + } +} \ No newline at end of file diff --git a/src/renderer/src/components/playlist/playlist-view/PlaylistView.tsx b/src/renderer/src/components/playlist/playlist-view/PlaylistView.tsx index c802f61d..13121b63 100644 --- a/src/renderer/src/components/playlist/playlist-view/PlaylistView.tsx +++ b/src/renderer/src/components/playlist/playlist-view/PlaylistView.tsx @@ -35,7 +35,7 @@ const PlaylistView: Component = (props) => { */} -

You have {count()} playlists

+ {/*

You have {count()} playlists

*/} Date: Sat, 12 Oct 2024 01:40:03 +0200 Subject: [PATCH 11/54] fix static analysis failing --- src/main/router/playlist-router.ts | 41 ++++++++++++++++++------------ 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/main/router/playlist-router.ts b/src/main/router/playlist-router.ts index 45af8148..00745f5e 100644 --- a/src/main/router/playlist-router.ts +++ b/src/main/router/playlist-router.ts @@ -4,29 +4,17 @@ import { none, some } from "../lib/rust-like-utils-backend/Optional"; import { Storage } from "../lib/storage/Storage"; Router.respond("playlist::add", (_evt, playlistName, song) => { - console.log("add this to " + playlistName + ": " + song); - - //Storage.removeTable("playlists"); const playlists = Storage.getTable("playlists"); let playlist = playlists.get(playlistName); - //temporary, playlist should already exist + if (playlist.isNone) { - // create playlist - const empty = { name: playlistName, count: 0, length: 0, songs: [] }; - playlists.write(playlistName, empty); + return; } - playlist = playlists.get(playlistName); playlist.value.songs.push(song); playlist.value.count = playlist.value.count + 1; playlist.value.length = playlist.value.length + song.duration; playlists.write(playlistName, playlist.value); - console.log( - "MONKA", - playlists.getStruct(), - Object.keys(Storage.getTable("playlists").getStruct()), - ); - console.log(playlist.value); }); Router.respond("playlist::create", (_evt, name) => { @@ -47,10 +35,15 @@ Router.respond("playlist::remove", (_evt, playlistName, song) => { console.log("delete song from " + playlistName, song); const playlists = Storage.getTable("playlists"); let playlist = playlists.get(playlistName); + + if(playlist.isNone){ + return; + } + const songIndex = playlist.value.songs.indexOf(song, 0); if (songIndex > -1) { playlist.value.songs.splice(songIndex, 1); - playlists.write(playlistName, playlist); + playlists.write(playlistName, playlist.value); } }); @@ -74,6 +67,11 @@ Router.respond("query::playlists", (_evt, request) => { let test: Playlist[] = []; playlists.forEach((v) => { const plist = p.get(v); + + if(plist.isNone){ + return; + } + test.push({ name: v, count: plist.value.count, @@ -109,6 +107,11 @@ Router.respond("query::playlists", (_evt, request) => { Router.respond("query::playlistSongs::init", (_evt, playlistName) => { const songs = Storage.getTable("playlists").get(playlistName); + + if(songs.isNone){ + return none(); + } + const count = Object.keys(songs.value.songs).length; return some({ @@ -118,7 +121,13 @@ Router.respond("query::playlistSongs::init", (_evt, playlistName) => { }); Router.respond("query::playlistSongs", (_evt, playlistName, request) => { - const songs = Storage.getTable("playlists").get(playlistName).value.songs; + const playlist = Storage.getTable("playlists").get(playlistName); + + if(playlist.isNone){ + return none(); + } + + const songs = playlist.value.songs; if ( songs === undefined || From 5fc464622a2eb927bd8e28bb0d1040461c0bf915 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Sat, 12 Oct 2024 01:43:54 +0200 Subject: [PATCH 12/54] fix warnings --- .../playlist/playlist-item/PlaylistItem.tsx | 22 +++++++++---------- .../playlist-song-list/PlaylistSongList.tsx | 1 - .../playlist/playlist-view/PlaylistView.tsx | 7 +++--- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx index 18170e27..22f05890 100644 --- a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx +++ b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx @@ -9,18 +9,18 @@ type PlaylistItemProps = { group: string; }; -function formatPlaylistTime(seconds: number) { - let minutes = 0; - let hours = 0; - if (seconds > 60) { - minutes = Math.floor(seconds / 60); - if (minutes > 60) { - hours = Math.floor(minutes / 60); - } - } +// function formatPlaylistTime(seconds: number) { +// let minutes = 0; +// let hours = 0; +// if (seconds > 60) { +// minutes = Math.floor(seconds / 60); +// if (minutes > 60) { +// hours = Math.floor(minutes / 60); +// } +// } - return hours + " hours " + minutes + " minutes"; -} +// return hours + " hours " + minutes + " minutes"; +// } function getSongImage(playlist: Playlist) { const songs = playlist.songs diff --git a/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx b/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx index 1ada9266..6572e841 100644 --- a/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx +++ b/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx @@ -1,6 +1,5 @@ import { Component } from "solid-js"; import InfiniteScroller from "../../InfiniteScroller"; -import SongContextMenuItem from "../../song/context-menu/SongContextMenuItem"; import SongItem from "../../song/song-item/SongItem"; type PlaylistSongListProps = { diff --git a/src/renderer/src/components/playlist/playlist-view/PlaylistView.tsx b/src/renderer/src/components/playlist/playlist-view/PlaylistView.tsx index 13121b63..3079667b 100644 --- a/src/renderer/src/components/playlist/playlist-view/PlaylistView.tsx +++ b/src/renderer/src/components/playlist/playlist-view/PlaylistView.tsx @@ -1,4 +1,4 @@ -import { Component, createSignal, onCleanup, onMount } from "solid-js"; +import { Component, createSignal } from "solid-js"; import "../../../assets/css/song/song-view.css"; import InfiniteScroller from "../../InfiniteScroller"; import PlaylistItem from "../playlist-item/PlaylistItem"; @@ -8,9 +8,8 @@ import IconButton from "../../icon-button/IconButton"; export type PlaylistViewProps = {}; - -const PlaylistView: Component = (props) => { - const [count, setCount] = createSignal(0); +const PlaylistView: Component = () => { + const [_count, setCount] = createSignal(0); const resetListing = new Impulse(); // const [payload, setPayload] = createSignal({}); const [playlistName, setPlaylistName] = createSignal(""); From e715cddbde9c6ea7e441beec979a731f8e6a3231 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Sat, 12 Oct 2024 01:49:23 +0200 Subject: [PATCH 13/54] more warnings fixed --- src/main/router/playlist-router.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/router/playlist-router.ts b/src/main/router/playlist-router.ts index 00745f5e..44f01986 100644 --- a/src/main/router/playlist-router.ts +++ b/src/main/router/playlist-router.ts @@ -5,7 +5,7 @@ import { Storage } from "../lib/storage/Storage"; Router.respond("playlist::add", (_evt, playlistName, song) => { const playlists = Storage.getTable("playlists"); - let playlist = playlists.get(playlistName); + const playlist = playlists.get(playlistName); if (playlist.isNone) { return; @@ -34,7 +34,7 @@ Router.respond("playlist::delete", (_evt, name) => { Router.respond("playlist::remove", (_evt, playlistName, song) => { console.log("delete song from " + playlistName, song); const playlists = Storage.getTable("playlists"); - let playlist = playlists.get(playlistName); + const playlist = playlists.get(playlistName); if(playlist.isNone){ return; @@ -64,7 +64,7 @@ Router.respond("query::playlists", (_evt, request) => { //todo: there has to be a better way to do this const p = Storage.getTable("playlists"); - let test: Playlist[] = []; + const playlistsInfo: Playlist[] = []; playlists.forEach((v) => { const plist = p.get(v); @@ -72,7 +72,7 @@ Router.respond("query::playlists", (_evt, request) => { return; } - test.push({ + playlistsInfo.push({ name: v, count: plist.value.count, length: plist.value.length, @@ -81,9 +81,9 @@ Router.respond("query::playlists", (_evt, request) => { }); if ( - test === undefined || + playlistsInfo === undefined || request.index < 0 || - request.index > Math.floor(test.length / BUFFER_SIZE) + request.index > Math.floor(playlistsInfo.length / BUFFER_SIZE) ) { return none(); } @@ -93,15 +93,15 @@ Router.respond("query::playlists", (_evt, request) => { if (request.direction === "up") { return some({ index: request.index - 1, - total: test.length, - items: test.slice(start, start + BUFFER_SIZE), + total: playlistsInfo.length, + items: playlistsInfo.slice(start, start + BUFFER_SIZE), }); } return some({ index: request.index + 1, - total: test.length, - items: test.slice(start, start + BUFFER_SIZE), + total: playlistsInfo.length, + items: playlistsInfo.slice(start, start + BUFFER_SIZE), }); }); From f0934f6dc00647e40cd588e1881ea063e610cb4f Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Sat, 12 Oct 2024 15:33:57 +0200 Subject: [PATCH 14/54] basic playlist scenes --- src/main/router/playlist-router.ts | 8 +- .../playlist/playlist-item/PlaylistItem.tsx | 19 +++-- .../playlist/playlist-list/PlaylistList.tsx | 81 +++++++++++++++++++ .../playlist-song-list/PlaylistSongList.tsx | 2 +- .../playlist/playlist-view/PlaylistView.tsx | 74 ++++++----------- .../playlist-view/playlist-view.utils.ts | 9 +++ 6 files changed, 128 insertions(+), 65 deletions(-) create mode 100644 src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx create mode 100644 src/renderer/src/components/playlist/playlist-view/playlist-view.utils.ts diff --git a/src/main/router/playlist-router.ts b/src/main/router/playlist-router.ts index 44f01986..8f54c0f6 100644 --- a/src/main/router/playlist-router.ts +++ b/src/main/router/playlist-router.ts @@ -36,7 +36,7 @@ Router.respond("playlist::remove", (_evt, playlistName, song) => { const playlists = Storage.getTable("playlists"); const playlist = playlists.get(playlistName); - if(playlist.isNone){ + if (playlist.isNone) { return; } @@ -68,7 +68,7 @@ Router.respond("query::playlists", (_evt, request) => { playlists.forEach((v) => { const plist = p.get(v); - if(plist.isNone){ + if (plist.isNone) { return; } @@ -108,7 +108,7 @@ Router.respond("query::playlists", (_evt, request) => { Router.respond("query::playlistSongs::init", (_evt, playlistName) => { const songs = Storage.getTable("playlists").get(playlistName); - if(songs.isNone){ + if (songs.isNone) { return none(); } @@ -123,7 +123,7 @@ Router.respond("query::playlistSongs::init", (_evt, playlistName) => { Router.respond("query::playlistSongs", (_evt, playlistName, request) => { const playlist = Storage.getTable("playlists").get(playlistName); - if(playlist.isNone){ + if (playlist.isNone) { return none(); } diff --git a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx index 22f05890..6c0d9220 100644 --- a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx +++ b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx @@ -1,8 +1,9 @@ -import { Component } from "solid-js"; -import SongImage from "../../song/SongImage"; -import { Playlist } from "src/@types"; import IconButton from "../../icon-button/IconButton"; +import SongImage from "../../song/SongImage"; +import { PLAYLIST_SCENE_SONGS, setPlaylistActiveScene } from "../playlist-view/playlist-view.utils"; import "./styles.css"; +import { Component } from "solid-js"; +import { Playlist } from "src/@types"; type PlaylistItemProps = { playlist: Playlist; @@ -23,8 +24,8 @@ type PlaylistItemProps = { // } function getSongImage(playlist: Playlist) { - const songs = playlist.songs - if(songs.length === 0 || songs[0].bg === undefined || songs[0].bg === "") { + const songs = playlist.songs; + if (songs.length === 0 || songs[0].bg === undefined || songs[0].bg === "") { return ""; } else { return songs[0].bg; @@ -37,14 +38,12 @@ const PlaylistItem: Component = (props) => { class="playlist-item" onClick={() => { console.log(props.playlist.songs); + setPlaylistActiveScene(PLAYLIST_SCENE_SONGS); }} >
- +
@@ -54,7 +53,7 @@ const PlaylistItem: Component = (props) => { {/*

{formatPlaylistTime(Math.round(props.playlist.length))}

*/}
- window.api.request("playlist::delete", props.playlist.name)}> + window.api.request("playlist::delete", props.playlist.name)}>
diff --git a/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx b/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx new file mode 100644 index 00000000..02600cdc --- /dev/null +++ b/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx @@ -0,0 +1,81 @@ +import "../../../assets/css/song/song-view.css"; +import InfiniteScroller from "../../InfiniteScroller"; +import IconButton from "../../icon-button/IconButton"; +import PlaylistItem from "../playlist-item/PlaylistItem"; +import { + PLAYLIST_SCENE_CREATE, + setPlaylistActiveScene, +} from "../playlist-view/playlist-view.utils"; +import { namespace } from "@renderer/App"; +import Impulse from "@renderer/lib/Impulse"; +import { Component, createSignal } from "solid-js"; + +export type PlaylistListProps = {}; + +const PlaylistList: Component = () => { + const [_count, setCount] = createSignal(0); + const resetListing = new Impulse(); + // const [payload, setPayload] = createSignal({}); + const [playlistName, setPlaylistName] = createSignal(""); + + const createPlaylist = () => { + // last check is probably unnecessary + if (playlistName().length === 0 || playlistName() === undefined || playlistName() === "") { + return; + } + window.api.request("playlist::create", playlistName().trim()); + setPlaylistName(""); + }; + + const group = namespace.create(true); + + return ( +
+ {/* + */} + + + {/*

You have {count()} playlists

*/} + No playlists...
} + builder={(s) => } + /> +
+ ); +}; + +export default PlaylistList; diff --git a/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx b/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx index 6572e841..8c66b42c 100644 --- a/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx +++ b/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx @@ -1,6 +1,6 @@ -import { Component } from "solid-js"; import InfiniteScroller from "../../InfiniteScroller"; import SongItem from "../../song/song-item/SongItem"; +import { Component } from "solid-js"; type PlaylistSongListProps = { playlistName: string; diff --git a/src/renderer/src/components/playlist/playlist-view/PlaylistView.tsx b/src/renderer/src/components/playlist/playlist-view/PlaylistView.tsx index 3079667b..f7873859 100644 --- a/src/renderer/src/components/playlist/playlist-view/PlaylistView.tsx +++ b/src/renderer/src/components/playlist/playlist-view/PlaylistView.tsx @@ -1,59 +1,33 @@ -import { Component, createSignal } from "solid-js"; -import "../../../assets/css/song/song-view.css"; -import InfiniteScroller from "../../InfiniteScroller"; -import PlaylistItem from "../playlist-item/PlaylistItem"; -import { namespace } from "@renderer/App"; -import Impulse from "@renderer/lib/Impulse"; -import IconButton from "../../icon-button/IconButton"; +import PlaylistList from "../playlist-list/PlaylistList"; +import { + PLAYLIST_SCENE_CREATE, + PLAYLIST_SCENE_SONGS, + PLAYLIST_SCENE_LIST, + playlistActiveScene, + setPlaylistActiveScene, +} from "./playlist-view.utils"; +import { Component, Match, Switch } from "solid-js"; export type PlaylistViewProps = {}; const PlaylistView: Component = () => { - const [_count, setCount] = createSignal(0); - const resetListing = new Impulse(); - // const [payload, setPayload] = createSignal({}); - const [playlistName, setPlaylistName] = createSignal(""); - - const createPlaylist = () => { - window.api.request("playlist::create", playlistName()); - setPlaylistName(""); - } - - const group = namespace.create(true); - - //todo: make something like App.tsx or MainScene.tsx to load a playlist (scene signal) or something with Routers return (
- {/* - */} - - - {/*

You have {count()} playlists

*/} - No playlists...
} - builder={(s) => } - /> + idk
}> + + + + + + + + + +
); }; diff --git a/src/renderer/src/components/playlist/playlist-view/playlist-view.utils.ts b/src/renderer/src/components/playlist/playlist-view/playlist-view.utils.ts new file mode 100644 index 00000000..e350b5aa --- /dev/null +++ b/src/renderer/src/components/playlist/playlist-view/playlist-view.utils.ts @@ -0,0 +1,9 @@ +import { createSignal } from "solid-js"; + +const PLAYLIST_SCENE_LIST = 0; +const PLAYLIST_SCENE_CREATE = 1; +const PLAYLIST_SCENE_SONGS = 2; + +const [playlistActiveScene, setPlaylistActiveScene] = createSignal(PLAYLIST_SCENE_LIST); +export { playlistActiveScene, setPlaylistActiveScene }; +export { PLAYLIST_SCENE_CREATE, PLAYLIST_SCENE_SONGS, PLAYLIST_SCENE_LIST }; From 43e37a65fae2566e64173309b78711a2adcd8ab8 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Sat, 12 Oct 2024 16:08:39 +0200 Subject: [PATCH 15/54] show song list when clicking on a playlist --- src/@types.d.ts | 5 +++++ src/RequestAPI.d.ts | 7 ++++-- src/main/router/playlist-router.ts | 8 +++---- .../playlist-create/PlaylistCreate.tsx | 16 ++++++++++++++ .../playlist/playlist-item/PlaylistItem.tsx | 8 +++++-- .../playlist-song-list/PlaylistSongList.tsx | 22 ++++++++++++++----- .../playlist/playlist-view/PlaylistView.tsx | 12 +++++----- .../playlist-view/playlist-view.utils.ts | 2 ++ 8 files changed, 60 insertions(+), 20 deletions(-) create mode 100644 src/renderer/src/components/playlist/playlist-create/PlaylistCreate.tsx diff --git a/src/@types.d.ts b/src/@types.d.ts index 5f433c29..a46cc842 100644 --- a/src/@types.d.ts +++ b/src/@types.d.ts @@ -194,6 +194,11 @@ export type QueueCreatePayload = { startSong: ResourceID; }; +// idk if this is necessary because i'm only passing a string +export type PlaylistSongsQueryPayload = { + playlistName: string; +}; + export type OsuSearchAbleProperties = | "bpm" | "artist" diff --git a/src/RequestAPI.d.ts b/src/RequestAPI.d.ts index 373d4fa8..350a7746 100644 --- a/src/RequestAPI.d.ts +++ b/src/RequestAPI.d.ts @@ -6,6 +6,7 @@ import type { InfiniteScrollerResponse, Optional, Playlist, + PlaylistSongsQueryPayload, QueueCreatePayload, ResourceID, ResourceTables, @@ -74,10 +75,12 @@ export type RequestAPI = { "query::queue": (request: InfiniteScrollerRequest) => InfiniteScrollerResponse; "query::playlists::init": () => InfiniteScrollerInitResponse; "query::playlists": (request: InfiniteScrollerRequest) => InfiniteScrollerResponse; - "query::playlistSongs::init": (playlistName: string) => InfiniteScrollerInitResponse; + "query::playlistSongs::init": ( + payload: PlaylistSongsQueryPayload, + ) => InfiniteScrollerInitResponse; "query::playlistSongs": ( - playlistName: string, request: InfiniteScrollerRequest, + payload: PlaylistSongsQueryPayload, ) => InfiniteScrollerResponse; "save::localVolume": (volume: number, song: ResourceID) => void; diff --git a/src/main/router/playlist-router.ts b/src/main/router/playlist-router.ts index 8f54c0f6..44403357 100644 --- a/src/main/router/playlist-router.ts +++ b/src/main/router/playlist-router.ts @@ -105,8 +105,8 @@ Router.respond("query::playlists", (_evt, request) => { }); }); -Router.respond("query::playlistSongs::init", (_evt, playlistName) => { - const songs = Storage.getTable("playlists").get(playlistName); +Router.respond("query::playlistSongs::init", (_evt, payload) => { + const songs = Storage.getTable("playlists").get(payload.playlistName); if (songs.isNone) { return none(); @@ -120,8 +120,8 @@ Router.respond("query::playlistSongs::init", (_evt, playlistName) => { }); }); -Router.respond("query::playlistSongs", (_evt, playlistName, request) => { - const playlist = Storage.getTable("playlists").get(playlistName); +Router.respond("query::playlistSongs", (_evt, request, payload) => { + const playlist = Storage.getTable("playlists").get(payload.playlistName); if (playlist.isNone) { return none(); diff --git a/src/renderer/src/components/playlist/playlist-create/PlaylistCreate.tsx b/src/renderer/src/components/playlist/playlist-create/PlaylistCreate.tsx new file mode 100644 index 00000000..9f44c448 --- /dev/null +++ b/src/renderer/src/components/playlist/playlist-create/PlaylistCreate.tsx @@ -0,0 +1,16 @@ +import { PLAYLIST_SCENE_LIST, setPlaylistActiveScene } from "../playlist-view/playlist-view.utils"; +import { Component } from "solid-js"; + +export type PlaylistCreateProps = {}; + +const PlaylistCreate: Component = () => { + return ( +
+ +
+ ); +}; + +export default PlaylistCreate; diff --git a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx index 6c0d9220..f6a6c2cb 100644 --- a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx +++ b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx @@ -1,6 +1,10 @@ import IconButton from "../../icon-button/IconButton"; import SongImage from "../../song/SongImage"; -import { PLAYLIST_SCENE_SONGS, setPlaylistActiveScene } from "../playlist-view/playlist-view.utils"; +import { + PLAYLIST_SCENE_SONGS, + setActivePlaylistName, + setPlaylistActiveScene, +} from "../playlist-view/playlist-view.utils"; import "./styles.css"; import { Component } from "solid-js"; import { Playlist } from "src/@types"; @@ -37,7 +41,7 @@ const PlaylistItem: Component = (props) => {
{ - console.log(props.playlist.songs); + setActivePlaylistName(props.playlist.name); setPlaylistActiveScene(PLAYLIST_SCENE_SONGS); }} > diff --git a/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx b/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx index 8c66b42c..65badd1f 100644 --- a/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx +++ b/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx @@ -1,19 +1,31 @@ import InfiniteScroller from "../../InfiniteScroller"; import SongItem from "../../song/song-item/SongItem"; -import { Component } from "solid-js"; +import { PLAYLIST_SCENE_LIST, setPlaylistActiveScene } from "../playlist-view/playlist-view.utils"; +import { namespace } from "@renderer/App"; +import { Component, createSignal } from "solid-js"; +import { PlaylistSongsQueryPayload } from "src/@types"; type PlaylistSongListProps = { playlistName: string; - group: string; }; const PlaylistSongList: Component = (props) => { + const group = namespace.create(true); + + const [payload, _setPlayload] = createSignal({ + playlistName: props.playlistName, + }); + return (
+ = (props) => { builder={(s) => ( window.api.request("queue::play", s.path)} + onSelect={() => window.api.request("queue::play", s)} // onDrop={onDrop(s)} > {/* window.api.request("queue::removeSong", s.path)}> diff --git a/src/renderer/src/components/playlist/playlist-view/PlaylistView.tsx b/src/renderer/src/components/playlist/playlist-view/PlaylistView.tsx index f7873859..7232a761 100644 --- a/src/renderer/src/components/playlist/playlist-view/PlaylistView.tsx +++ b/src/renderer/src/components/playlist/playlist-view/PlaylistView.tsx @@ -1,10 +1,12 @@ +import PlaylistCreate from "../playlist-create/PlaylistCreate"; import PlaylistList from "../playlist-list/PlaylistList"; +import PlaylistSongList from "../playlist-song-list/PlaylistSongList"; import { PLAYLIST_SCENE_CREATE, PLAYLIST_SCENE_SONGS, PLAYLIST_SCENE_LIST, playlistActiveScene, - setPlaylistActiveScene, + activePlaylistName, } from "./playlist-view.utils"; import { Component, Match, Switch } from "solid-js"; @@ -18,14 +20,10 @@ const PlaylistView: Component = () => { - + - +
diff --git a/src/renderer/src/components/playlist/playlist-view/playlist-view.utils.ts b/src/renderer/src/components/playlist/playlist-view/playlist-view.utils.ts index e350b5aa..f9287627 100644 --- a/src/renderer/src/components/playlist/playlist-view/playlist-view.utils.ts +++ b/src/renderer/src/components/playlist/playlist-view/playlist-view.utils.ts @@ -5,5 +5,7 @@ const PLAYLIST_SCENE_CREATE = 1; const PLAYLIST_SCENE_SONGS = 2; const [playlistActiveScene, setPlaylistActiveScene] = createSignal(PLAYLIST_SCENE_LIST); +const [activePlaylistName, setActivePlaylistName] = createSignal(""); export { playlistActiveScene, setPlaylistActiveScene }; +export { activePlaylistName, setActivePlaylistName }; export { PLAYLIST_SCENE_CREATE, PLAYLIST_SCENE_SONGS, PLAYLIST_SCENE_LIST }; From 288b33979017b31e5a028ed8e6d4ce6de6593c0a Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Sat, 12 Oct 2024 18:03:42 +0200 Subject: [PATCH 16/54] play songs from playlist with working queue + styling --- src/main/router/queue-router.ts | 19 +++- .../playlist/playlist-item/styles.css | 86 +++++++++---------- .../playlist-song-list/PlaylistSongList.tsx | 77 +++++++++++------ .../playlist/playlist-song-list/styles.css | 38 ++++++++ 4 files changed, 147 insertions(+), 73 deletions(-) create mode 100644 src/renderer/src/components/playlist/playlist-song-list/styles.css diff --git a/src/main/router/queue-router.ts b/src/main/router/queue-router.ts index b62e7abd..260bd6e3 100644 --- a/src/main/router/queue-router.ts +++ b/src/main/router/queue-router.ts @@ -79,8 +79,23 @@ function getIndexes(view: QueueView): SongIndex[] { } if (view.playlist) { - //todo get playlist - return []; + const indexes = Storage.getTable("system").get("indexes"); + const playlist = Storage.getTable("playlists").get(view.playlist); + + if (indexes.isNone || playlist.isNone) { + return []; + } + + const songs: SongIndex[] = []; + // is there a more efficient way? + for (let i = 0; i < playlist.value.count; ++i) { + let song = indexes.value.find((v) => v.id === playlist.value.songs[i].audio); + if (song !== undefined) { + songs.push(song); + } + } + + return songs; } return []; diff --git a/src/renderer/src/components/playlist/playlist-item/styles.css b/src/renderer/src/components/playlist/playlist-item/styles.css index 6833846c..976da5c4 100644 --- a/src/renderer/src/components/playlist/playlist-item/styles.css +++ b/src/renderer/src/components/playlist/playlist-item/styles.css @@ -1,52 +1,50 @@ .playlist-item { - --image-size: 70px; + --image-size: 70px; - .playlist-item-container { - margin-top: 20px; - margin-left: 8px; - display: flex; - flex-direction: row; - - .playlist-item__playlist-img { - margin: auto 6px auto 6px; - border-radius: var(--rounded-lg); - .song-image { - width: var(--image-size); - height: var(--image-size); - background-size: cover; - background-position: center; - border-radius: var(--rounded-lg); - } + .playlist-item-container { + margin-top: 20px; + margin-left: 8px; + display: flex; + flex-direction: row; - } + .playlist-item__playlist-img { + margin: auto 6px auto 6px; + border-radius: var(--rounded-lg); + .song-image { + width: var(--image-size); + height: var(--image-size); + background-size: cover; + background-position: center; + border-radius: var(--rounded-lg); + } + } - .playlist-item__playlist-info { - display: flex; - flex-direction: row; - margin-left: 6px; - justify-content: space-between; - width: 100%; + .playlist-item__playlist-info { + display: flex; + flex-direction: row; + margin-left: 6px; + justify-content: space-between; + width: 100%; - .playlist-item__playlist-info__text { - display: flex; - flex-direction: column; - justify-content: center; - font-weight: 300; - line-height: 24px; - } + .playlist-item__playlist-info__text { + display: flex; + flex-direction: column; + justify-content: center; + font-weight: 300; + line-height: 24px; + } - .playlist-item__playlist-info__text h3 { - font-size: 28px; - } + .playlist-item__playlist-info__text h3 { + font-size: 28px; + } - .playlist-item__playlist-info__button { - display: flex; - flex-direction: column; - justify-content: center; - margin-right: 8px; - color: lightcoral; - - } - } + .playlist-item__playlist-info__button { + display: flex; + flex-direction: column; + justify-content: center; + margin-right: 8px; + color: lightcoral; + } } -} \ No newline at end of file + } +} diff --git a/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx b/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx index 65badd1f..ccc7ef4a 100644 --- a/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx +++ b/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx @@ -1,9 +1,11 @@ import InfiniteScroller from "../../InfiniteScroller"; import SongItem from "../../song/song-item/SongItem"; import { PLAYLIST_SCENE_LIST, setPlaylistActiveScene } from "../playlist-view/playlist-view.utils"; +import "./styles.css"; import { namespace } from "@renderer/App"; +import IconButton from "@renderer/components/icon-button/IconButton"; import { Component, createSignal } from "solid-js"; -import { PlaylistSongsQueryPayload } from "src/@types"; +import { PlaylistSongsQueryPayload, ResourceID } from "src/@types"; type PlaylistSongListProps = { playlistName: string; @@ -16,35 +18,56 @@ const PlaylistSongList: Component = (props) => { playlistName: props.playlistName, }); + const createQueue = async (songResource: ResourceID) => { + await window.api.request("queue::create", { + startSong: songResource, + order: "", + tags: [], + view: { playlist: props.playlistName }, + }); + }; + return ( -
- - No songs...
} - builder={(s) => ( - window.api.request("queue::play", s)} - // onDrop={onDrop(s)} - > - {/* window.api.request("queue::removeSong", s.path)}> +
+
+
+ setPlaylistActiveScene(PLAYLIST_SCENE_LIST)}> + + +

{props.playlistName}

+
+
+ + + +
+
+
+ No songs in playlist...
} + builder={(s) => ( + + {/* window.api.request("queue::removeSong", s.path)}> Remove from queue */} - - )} - /> + + )} + /> +
); }; diff --git a/src/renderer/src/components/playlist/playlist-song-list/styles.css b/src/renderer/src/components/playlist/playlist-song-list/styles.css new file mode 100644 index 00000000..de077913 --- /dev/null +++ b/src/renderer/src/components/playlist/playlist-song-list/styles.css @@ -0,0 +1,38 @@ +.playlist-song-list { + margin-top: 24px; + .playlist-song-list__top { + width: 100%; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + + .playlist-song-list__top__left { + display: flex; + flex-direction: row; + align-items: center; + margin-left: 12px; + font-size: 20px; + } + + .playlist-song-list__top__left > * + * { + margin-left: 18px; + } + + .playlist-song-list__top__right { + margin-right: 16px; + } + } + + .playlist-song-list__list { + margin-top: 24px; + .song-item { + margin: 12px 12px; + } + } +} + +.icon-button { + padding: 0px; + margin: 0px; +} From 728dd8f587bc6a1b3dd14467bf301607e270a304 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Sat, 12 Oct 2024 18:05:33 +0200 Subject: [PATCH 17/54] lint fix --- src/main/router/queue-router.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/router/queue-router.ts b/src/main/router/queue-router.ts index 260bd6e3..c33aab03 100644 --- a/src/main/router/queue-router.ts +++ b/src/main/router/queue-router.ts @@ -89,7 +89,7 @@ function getIndexes(view: QueueView): SongIndex[] { const songs: SongIndex[] = []; // is there a more efficient way? for (let i = 0; i < playlist.value.count; ++i) { - let song = indexes.value.find((v) => v.id === playlist.value.songs[i].audio); + const song = indexes.value.find((v) => v.id === playlist.value.songs[i].audio); if (song !== undefined) { songs.push(song); } From d84f1a30a86205ad2cd4b96084518859b396cb4a Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Sat, 12 Oct 2024 21:15:13 +0200 Subject: [PATCH 18/54] implement playlist creation scene --- .../playlist-create/PlaylistCreate.tsx | 41 +++++++++++-- .../playlist/playlist-create/styles.css | 60 +++++++++++++++++++ .../playlist/playlist-list/PlaylistList.tsx | 11 ---- .../playlist/playlist-song-list/styles.css | 5 +- .../playlist/playlist-view/PlaylistView.tsx | 1 + .../playlist/playlist-view/styles.css | 4 ++ 6 files changed, 102 insertions(+), 20 deletions(-) create mode 100644 src/renderer/src/components/playlist/playlist-create/styles.css create mode 100644 src/renderer/src/components/playlist/playlist-view/styles.css diff --git a/src/renderer/src/components/playlist/playlist-create/PlaylistCreate.tsx b/src/renderer/src/components/playlist/playlist-create/PlaylistCreate.tsx index 9f44c448..ab049435 100644 --- a/src/renderer/src/components/playlist/playlist-create/PlaylistCreate.tsx +++ b/src/renderer/src/components/playlist/playlist-create/PlaylistCreate.tsx @@ -1,14 +1,45 @@ import { PLAYLIST_SCENE_LIST, setPlaylistActiveScene } from "../playlist-view/playlist-view.utils"; -import { Component } from "solid-js"; +import "./styles.css"; +import IconButton from "@renderer/components/icon-button/IconButton"; +import { Component, createSignal } from "solid-js"; export type PlaylistCreateProps = {}; const PlaylistCreate: Component = () => { + const [playlistName, setPlaylistName] = createSignal(""); + + const createPlaylist = () => { + // last check is probably unnecessary + if (playlistName().length === 0 || playlistName() === undefined || playlistName() === "") { + return; + } + window.api.request("playlist::create", playlistName().trim()); + setPlaylistActiveScene(PLAYLIST_SCENE_LIST); + setPlaylistName(""); + }; + return ( -
- +
+
+
+ setPlaylistActiveScene(PLAYLIST_SCENE_LIST)}> + + +

New playlist

+
+
+

Name

+ { + setPlaylistName(e.target.value); + }} + /> +
+
+
); }; diff --git a/src/renderer/src/components/playlist/playlist-create/styles.css b/src/renderer/src/components/playlist/playlist-create/styles.css new file mode 100644 index 00000000..8c046e49 --- /dev/null +++ b/src/renderer/src/components/playlist/playlist-create/styles.css @@ -0,0 +1,60 @@ +.playlist-create { + display: flex; + flex-direction: column; + justify-content: space-between; + height: 100%; + margin-left: 20px; + margin-right: 20px; + .playlist-create__top { + margin-top: 24px; + .playlist-create__top__header { + display: flex; + flex-direction: row; + align-items: center; + gap: 20px; + font-size: 20px; + color: #eff1f5; + + i { + color: #eff1f599; + } + } + + .playlist-create__top__body { + display: flex; + flex-direction: column; + margin-top: 24px; + gap: 8px; + color: #ffffffd1; + + input { + height: 44px; + border-radius: 8px; + background-color: #84898f33; + border: none; + color: #ffffffd1; + padding: 10px 16px 10px 16px; + } + } + } + + .playlist-create__footer { + button { + width: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + margin-bottom: 24px; + height: 36px; + background-color: white; + color: black; + font-weight: 600; + border-radius: 6px; + } + + /* button:hover { + cursor: pointer; + } */ + } +} diff --git a/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx b/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx index 02600cdc..30e37fc4 100644 --- a/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx +++ b/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx @@ -16,16 +16,6 @@ const PlaylistList: Component = () => { const [_count, setCount] = createSignal(0); const resetListing = new Impulse(); // const [payload, setPayload] = createSignal({}); - const [playlistName, setPlaylistName] = createSignal(""); - - const createPlaylist = () => { - // last check is probably unnecessary - if (playlistName().length === 0 || playlistName() === undefined || playlistName() === "") { - return; - } - window.api.request("playlist::create", playlistName().trim()); - setPlaylistName(""); - }; const group = namespace.create(true); @@ -53,7 +43,6 @@ const PlaylistList: Component = () => {
window.api.request("playlist::delete", props.playlist.name)}> - +
diff --git a/src/renderer/src/components/playlist/playlist-item/styles.css b/src/renderer/src/components/playlist/playlist-item/styles.css index 976da5c4..2dd574dd 100644 --- a/src/renderer/src/components/playlist/playlist-item/styles.css +++ b/src/renderer/src/components/playlist/playlist-item/styles.css @@ -1,27 +1,27 @@ .playlist-item { - --image-size: 70px; + --image-size: 71px; .playlist-item-container { - margin-top: 20px; - margin-left: 8px; display: flex; flex-direction: row; + gap: 16px; .playlist-item__playlist-img { - margin: auto 6px auto 6px; + /* margin: auto 6px auto 6px; */ border-radius: var(--rounded-lg); .song-image { width: var(--image-size); height: var(--image-size); background-size: cover; background-position: center; - border-radius: var(--rounded-lg); + border-radius: 8px; } } .playlist-item__playlist-info { display: flex; flex-direction: row; + align-items: center; margin-left: 6px; justify-content: space-between; width: 100%; @@ -30,20 +30,29 @@ display: flex; flex-direction: column; justify-content: center; - font-weight: 300; + font-weight: 500; line-height: 24px; + font-size: 16px; + color: #eff1f5; } .playlist-item__playlist-info__text h3 { - font-size: 28px; + font-size: 30px; + line-height: 30px; + font-weight: 700; } .playlist-item__playlist-info__button { display: flex; flex-direction: column; justify-content: center; - margin-right: 8px; - color: lightcoral; + align-items: center; + height: 40px; + width: 40px; + color: #eff1f5; + border: 1px solid #f2f4fc1a; + border-radius: 8px; + z-index: 3; } } } diff --git a/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx b/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx index 30e37fc4..94d15b1b 100644 --- a/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx +++ b/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx @@ -6,6 +6,7 @@ import { PLAYLIST_SCENE_CREATE, setPlaylistActiveScene, } from "../playlist-view/playlist-view.utils"; +import "./styles.css"; import { namespace } from "@renderer/App"; import Impulse from "@renderer/lib/Impulse"; import { Component, createSignal } from "solid-js"; @@ -15,7 +16,6 @@ export type PlaylistListProps = {}; const PlaylistList: Component = () => { const [_count, setCount] = createSignal(0); const resetListing = new Impulse(); - // const [payload, setPayload] = createSignal({}); const group = namespace.create(true); @@ -29,40 +29,38 @@ const PlaylistList: Component = () => { error={searchError} /> */} - ); }; diff --git a/src/renderer/src/components/playlist/playlist-list/styles.css b/src/renderer/src/components/playlist/playlist-list/styles.css new file mode 100644 index 00000000..9066c77b --- /dev/null +++ b/src/renderer/src/components/playlist/playlist-list/styles.css @@ -0,0 +1,51 @@ +.playlist-list { + margin: 24px 20px; + .playlist-list__header { + display: flex; + flex-direction: row; + align-items: center; + margin-bottom: 24px; + + .playlist-list__header__input-container { + height: 40px; + display: flex; + align-items: center; + flex: 1; + border: 1px solid #f2f4fc1a; + border-radius: 8px; + padding: 8px 12px; + + .playlist-list__header__input { + flex: 1; + background-color: transparent; + border: none; + font-size: 16px; + color: white; + } + + .playlist-list__header__search-icon { + font-size: 20px; + color: #eff1f599; + } + } + + .icon-button { + font-size: 20px; + width: 20px; + height: 20px; + color: #eff1f5; + border: 1px solid #f2f4fc1a; + border-radius: 8px; + padding: 9px; + margin: 0px 0px 0px 6px; /* why is this button so weird */ + } + } + + .playlist-list__body { + .list { + display: flex; + flex-direction: column; + gap: 16px; + } + } +} diff --git a/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx b/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx index ccc7ef4a..fe3629e8 100644 --- a/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx +++ b/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx @@ -48,9 +48,6 @@ const PlaylistSongList: Component = (props) => { apiData={payload()} apiInitKey={"query::playlistSongs::init"} apiInitData={payload()} - // setCount={setCount} - // reset={resetListing} - // onLoadItems={onSongsLoad} fallback={
No songs in playlist...
} builder={(s) => ( = (props) => { selectable={true} draggable={true} onSelect={createQueue} - // onDrop={onDrop(s)} - > - {/* window.api.request("queue::removeSong", s.path)}> - Remove from queue - */} - + > )} /> diff --git a/src/renderer/src/components/playlist/playlist-song-list/styles.css b/src/renderer/src/components/playlist/playlist-song-list/styles.css index fb3d8024..20c0e176 100644 --- a/src/renderer/src/components/playlist/playlist-song-list/styles.css +++ b/src/renderer/src/components/playlist/playlist-song-list/styles.css @@ -1,7 +1,8 @@ .playlist-song-list { - margin-top: 24px; + margin: 24px 20px; .playlist-song-list__top { width: 100%; + margin-bottom: 24px; display: flex; flex-direction: row; justify-content: space-between; @@ -11,25 +12,38 @@ display: flex; flex-direction: row; align-items: center; - margin-left: 12px; font-size: 20px; - gap: 18px; + line-height: 24px; + font-weight: 500; + gap: 20px; + + .icon-button { + font-size: 20px; + color: #eff1f599; + } } .playlist-song-list__top__right { - margin-right: 16px; + display: flex; + align-items: center; + justify-content: center; + border: 1px solid #f2f4fc1a; + color: #eff1f5; + width: 40px; + height: 40px; + border-radius: 8px; + + .icon-button { + font-size: 20px; + } } } .playlist-song-list__list { - margin-top: 24px; - .song-item { - margin: 12px 12px; + .list { + display: flex; + flex-direction: column; + gap: 16px; } } } - -.icon-button { - padding: 0px; - margin: 0px; -} From 30e497d63f722267768730e979471945c666b6ff Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Sat, 12 Oct 2024 22:46:55 +0200 Subject: [PATCH 20/54] avoid entering playlist when deleting it (event propagation) --- .../src/components/playlist/playlist-item/PlaylistItem.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx index 42b747c1..2e7a9b2a 100644 --- a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx +++ b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx @@ -37,6 +37,11 @@ function getSongImage(playlist: Playlist) { } const PlaylistItem: Component = (props) => { + const deletePlaylist = (e: Event, playlistName: string) => { + e.stopPropagation(); + window.api.request("playlist::delete", playlistName); + }; + return (
= (props) => { {/*

{formatPlaylistTime(Math.round(props.playlist.length))}

*/}
- window.api.request("playlist::delete", props.playlist.name)}> + deletePlaylist(e, props.playlist.name)}>
From 8b6b35452aa200c47a504d8a68ed2114c01da0af Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Sat, 12 Oct 2024 23:03:13 +0200 Subject: [PATCH 21/54] automatically refresh scene when deleting a playlist --- .../playlist/playlist-item/PlaylistItem.tsx | 34 +++---------------- .../playlist-item/playlist-item.utils.ts | 30 ++++++++++++++++ .../playlist/playlist-list/PlaylistList.tsx | 7 ++-- 3 files changed, 40 insertions(+), 31 deletions(-) create mode 100644 src/renderer/src/components/playlist/playlist-item/playlist-item.utils.ts diff --git a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx index 2e7a9b2a..eeb34472 100644 --- a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx +++ b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx @@ -5,43 +5,19 @@ import { setActivePlaylistName, setPlaylistActiveScene, } from "../playlist-view/playlist-view.utils"; +import { deletePlaylist, getSongImage } from "./playlist-item.utils"; import "./styles.css"; +import Impulse from "@renderer/lib/Impulse"; import { Component } from "solid-js"; import { Playlist } from "src/@types"; -type PlaylistItemProps = { +export type PlaylistItemProps = { playlist: Playlist; group: string; + reset: Impulse; }; -// function formatPlaylistTime(seconds: number) { -// let minutes = 0; -// let hours = 0; -// if (seconds > 60) { -// minutes = Math.floor(seconds / 60); -// if (minutes > 60) { -// hours = Math.floor(minutes / 60); -// } -// } - -// return hours + " hours " + minutes + " minutes"; -// } - -function getSongImage(playlist: Playlist) { - const songs = playlist.songs; - if (songs.length === 0 || songs[0].bg === undefined || songs[0].bg === "") { - return ""; - } else { - return songs[0].bg; - } -} - const PlaylistItem: Component = (props) => { - const deletePlaylist = (e: Event, playlistName: string) => { - e.stopPropagation(); - window.api.request("playlist::delete", playlistName); - }; - return (
= (props) => { {/*

{formatPlaylistTime(Math.round(props.playlist.length))}

*/}
- deletePlaylist(e, props.playlist.name)}> + deletePlaylist(e, props)}>
diff --git a/src/renderer/src/components/playlist/playlist-item/playlist-item.utils.ts b/src/renderer/src/components/playlist/playlist-item/playlist-item.utils.ts new file mode 100644 index 00000000..c0fcde06 --- /dev/null +++ b/src/renderer/src/components/playlist/playlist-item/playlist-item.utils.ts @@ -0,0 +1,30 @@ +import { PlaylistItemProps } from "./PlaylistItem"; +import { Playlist } from "src/@types"; + +export function getSongImage(playlist: Playlist) { + const songs = playlist.songs; + if (songs.length === 0 || songs[0].bg === undefined || songs[0].bg === "") { + return ""; + } else { + return songs[0].bg; + } +} + +export function deletePlaylist(e: Event, props: PlaylistItemProps) { + e.stopPropagation(); + window.api.request("playlist::delete", props.playlist.name); + props.reset.pulse(); +} + +// function formatPlaylistTime(seconds: number) { +// let minutes = 0; +// let hours = 0; +// if (seconds > 60) { +// minutes = Math.floor(seconds / 60); +// if (minutes > 60) { +// hours = Math.floor(minutes / 60); +// } +// } + +// return hours + " hours " + minutes + " minutes"; +// } diff --git a/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx b/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx index 94d15b1b..edb2ecdd 100644 --- a/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx +++ b/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx @@ -14,6 +14,7 @@ import { Component, createSignal } from "solid-js"; export type PlaylistListProps = {}; const PlaylistList: Component = () => { + // const [playlistSearch, setPlaylistSearch] = createSignal(""); const [_count, setCount] = createSignal(0); const resetListing = new Impulse(); @@ -37,7 +38,7 @@ const PlaylistList: Component = () => { class="playlist-list__header__input" placeholder="Search in your playlists... (WIP)" // onInput={(e) => { - // setPlaylistName(e.target.value); + // setPlaylistSearch(e.target.value); // }} /> @@ -58,7 +59,9 @@ const PlaylistList: Component = () => { setCount={setCount} reset={resetListing} fallback={
No playlists...
} - builder={(s) => } + builder={(s) => ( + + )} /> From 8d3e66d341eda3afa830a854f4910906eed3ddd0 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Sun, 13 Oct 2024 01:09:39 +0200 Subject: [PATCH 22/54] new playlist creation box --- .../playlist-create/PlaylistCreateBox.tsx | 51 +++++++++++++ .../playlist/playlist-create/styles.css | 71 +++++++++++++++++++ .../playlist/playlist-list/PlaylistList.tsx | 21 ++++-- .../playlist/playlist-list/styles.css | 6 ++ 4 files changed, 143 insertions(+), 6 deletions(-) create mode 100644 src/renderer/src/components/playlist/playlist-create/PlaylistCreateBox.tsx diff --git a/src/renderer/src/components/playlist/playlist-create/PlaylistCreateBox.tsx b/src/renderer/src/components/playlist/playlist-create/PlaylistCreateBox.tsx new file mode 100644 index 00000000..3d838a17 --- /dev/null +++ b/src/renderer/src/components/playlist/playlist-create/PlaylistCreateBox.tsx @@ -0,0 +1,51 @@ +import SongImage from "@renderer/components/song/SongImage"; +import Impulse from "@renderer/lib/Impulse"; +import { Component, createSignal, Setter } from "solid-js"; + +export type PlaylistCreateBoxProps = { + group: string; + isOpen: Setter; + reset: Impulse; +}; +const PlaylistCreateBox: Component = (props) => { + const [playlistName, setPlaylistName] = createSignal(""); + + const createPlaylist = () => { + // last check is probably unnecessary + if (playlistName().length === 0 || playlistName() === undefined || playlistName() === "") { + return; + } + window.api.request("playlist::create", playlistName().trim()); + setPlaylistName(""); + props.reset.pulse(); + props.isOpen(false); + }; + + return ( +
+
+

Create a new playlist

+ +
+
+
+ +
+
+ { + setPlaylistName(e.target.value); + }} + /> + +
+
+
+ ); +}; + +export default PlaylistCreateBox; diff --git a/src/renderer/src/components/playlist/playlist-create/styles.css b/src/renderer/src/components/playlist/playlist-create/styles.css index 1fa82621..93788e84 100644 --- a/src/renderer/src/components/playlist/playlist-create/styles.css +++ b/src/renderer/src/components/playlist/playlist-create/styles.css @@ -37,6 +37,7 @@ font-size: 16px; line-height: 24px; font-weight: 400; + font-family: "Nunito"; } } } @@ -61,3 +62,73 @@ } */ } } + +.playlist-create-box { + background-color: #0d0d0df2; + border-radius: 12px; + margin-bottom: 24px; + + .playlist-create-box__header { + display: flex; + flex-direction: row; + justify-content: space-between; + padding: 16px; + + button { + font-size: 20px; + } + } + + .playlist-create-box__body { + display: flex; + flex-direction: row; + margin: 16px; + margin-top: 0px; + + .playlist-create-box__body__image { + border-radius: 8px; + margin-right: 16px; + .song-image { + width: 83px; + height: 83px; + background-size: cover; + background-position: center; + border-radius: 8px; + } + } + + .playlist-create-box__body__input { + display: flex; + flex-direction: column; + gap: 12px; + width: 100%; + + input { + height: 36px; + border-radius: 8px; + background-color: #84898f33; + border: none; + color: #ffffff; + padding: 10px 0px 10px 16px; + font-size: 16px; + line-height: 24px; + font-weight: 400; + font-family: "Nunito"; + } + + button { + width: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + margin-bottom: 24px; + height: 36px; + background-color: #ffffffeb; + color: black; + font-weight: 600; + border-radius: 8px; + } + } + } +} diff --git a/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx b/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx index edb2ecdd..f8902994 100644 --- a/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx +++ b/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx @@ -1,15 +1,16 @@ import "../../../assets/css/song/song-view.css"; import InfiniteScroller from "../../InfiniteScroller"; import IconButton from "../../icon-button/IconButton"; +import PlaylistCreateBox from "../playlist-create/PlaylistCreateBox"; import PlaylistItem from "../playlist-item/PlaylistItem"; -import { - PLAYLIST_SCENE_CREATE, - setPlaylistActiveScene, -} from "../playlist-view/playlist-view.utils"; +// import { +// PLAYLIST_SCENE_CREATE, +// setPlaylistActiveScene, +// } from "../playlist-view/playlist-view.utils"; import "./styles.css"; import { namespace } from "@renderer/App"; import Impulse from "@renderer/lib/Impulse"; -import { Component, createSignal } from "solid-js"; +import { Component, createSignal, Match, Switch } from "solid-js"; export type PlaylistListProps = {}; @@ -17,6 +18,7 @@ const PlaylistList: Component = () => { // const [playlistSearch, setPlaylistSearch] = createSignal(""); const [_count, setCount] = createSignal(0); const resetListing = new Impulse(); + const [showCreateBox, setShowCreateBox] = createSignal(false); const group = namespace.create(true); @@ -45,14 +47,21 @@ const PlaylistList: Component = () => { { - setPlaylistActiveScene(PLAYLIST_SCENE_CREATE); + // setPlaylistActiveScene(PLAYLIST_SCENE_CREATE); + setShowCreateBox(true); }} + data-open={showCreateBox()} >
+ + + + + Date: Sun, 13 Oct 2024 17:48:30 +0200 Subject: [PATCH 23/54] fix styling, playlists refresh when adding a song --- src/ListenAPI.d.ts | 3 ++ src/main/router/playlist-router.ts | 6 ++- .../playlist/playlist-create/styles.css | 5 ++- .../playlist/playlist-list/PlaylistList.tsx | 27 +++++++----- .../playlist/playlist-list/styles.css | 42 +++++++++++-------- .../playlist-song-list/PlaylistSongList.tsx | 9 +++- .../song/song-detail/SongControls.tsx | 5 ++- 7 files changed, 64 insertions(+), 33 deletions(-) diff --git a/src/ListenAPI.d.ts b/src/ListenAPI.d.ts index d8499784..86c2b46b 100644 --- a/src/ListenAPI.d.ts +++ b/src/ListenAPI.d.ts @@ -14,6 +14,9 @@ export type ListenAPI = { "songView::reset": () => void; + "playlist::resetList": () => void; + "playlist::resetSongList": () => void; + "window::maximizeChange": (maximized: boolean) => void; notify: (notice: NoticeType) => void; diff --git a/src/main/router/playlist-router.ts b/src/main/router/playlist-router.ts index 44403357..53dc4d64 100644 --- a/src/main/router/playlist-router.ts +++ b/src/main/router/playlist-router.ts @@ -2,8 +2,10 @@ import { Playlist } from "../../@types"; import { Router } from "../lib/route-pass/Router"; import { none, some } from "../lib/rust-like-utils-backend/Optional"; import { Storage } from "../lib/storage/Storage"; +import errorIgnored from "../lib/tungsten/errorIgnored"; +import { mainWindow } from "../main"; -Router.respond("playlist::add", (_evt, playlistName, song) => { +Router.respond("playlist::add", async (_evt, playlistName, song) => { const playlists = Storage.getTable("playlists"); const playlist = playlists.get(playlistName); @@ -15,6 +17,8 @@ Router.respond("playlist::add", (_evt, playlistName, song) => { playlist.value.count = playlist.value.count + 1; playlist.value.length = playlist.value.length + song.duration; playlists.write(playlistName, playlist.value); + await Router.dispatch(mainWindow, "playlist::resetList").catch(errorIgnored); + await Router.dispatch(mainWindow, "playlist::resetSongList").catch(errorIgnored); }); Router.respond("playlist::create", (_evt, name) => { diff --git a/src/renderer/src/components/playlist/playlist-create/styles.css b/src/renderer/src/components/playlist/playlist-create/styles.css index 93788e84..9b7f5823 100644 --- a/src/renderer/src/components/playlist/playlist-create/styles.css +++ b/src/renderer/src/components/playlist/playlist-create/styles.css @@ -37,7 +37,7 @@ font-size: 16px; line-height: 24px; font-weight: 400; - font-family: "Nunito"; + font-family: inherit; } } } @@ -113,7 +113,8 @@ font-size: 16px; line-height: 24px; font-weight: 400; - font-family: "Nunito"; + font-family: inherit; + width: 100%; } button { diff --git a/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx b/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx index f8902994..d58fa706 100644 --- a/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx +++ b/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx @@ -10,7 +10,7 @@ import PlaylistItem from "../playlist-item/PlaylistItem"; import "./styles.css"; import { namespace } from "@renderer/App"; import Impulse from "@renderer/lib/Impulse"; -import { Component, createSignal, Match, Switch } from "solid-js"; +import { Component, createSignal, Match, onCleanup, onMount, Switch } from "solid-js"; export type PlaylistListProps = {}; @@ -22,6 +22,11 @@ const PlaylistList: Component = () => { const group = namespace.create(true); + onMount(() => window.api.listen("playlist::resetList", resetListing.pulse.bind(resetListing))); + onCleanup(() => + window.api.removeListener("playlist::resetList", resetListing.pulse.bind(resetListing)), + ); + return (
{/* = () => { />
- { - // setPlaylistActiveScene(PLAYLIST_SCENE_CREATE); - setShowCreateBox(true); - }} - data-open={showCreateBox()} - > - - +
+ { + // setPlaylistActiveScene(PLAYLIST_SCENE_CREATE); + setShowCreateBox(!showCreateBox()); + }} + data-open={showCreateBox()} + > + + +
diff --git a/src/renderer/src/components/playlist/playlist-list/styles.css b/src/renderer/src/components/playlist/playlist-list/styles.css index 33ff2f39..e3015934 100644 --- a/src/renderer/src/components/playlist/playlist-list/styles.css +++ b/src/renderer/src/components/playlist/playlist-list/styles.css @@ -7,42 +7,48 @@ margin-bottom: 24px; .playlist-list__header__input-container { - height: 40px; display: flex; - align-items: center; + flex-direction: row; + justify-content: space-between; flex: 1; + height: 40px; + align-items: center; border: 1px solid #f2f4fc1a; border-radius: 8px; - padding: 8px 12px; + /* padding: 8px 12px; */ + margin-right: 8px; .playlist-list__header__input { - flex: 1; background-color: transparent; border: none; font-size: 16px; color: white; - font-family: "Nunito"; + font-family: inherit; + margin-left: 12px; + width: 100%; } - .playlist-list__header__search-icon { font-size: 20px; color: #eff1f599; + margin-right: 12px; } } - .icon-button { - font-size: 20px; - width: 20px; - height: 20px; - color: #eff1f5; - border: 1px solid #f2f4fc1a; - border-radius: 8px; - padding: 9px; - margin: 0px 0px 0px 6px; /* why is this button so weird */ + .playlist-list__header__create-playlist { + .icon-button { + font-size: 20px; + width: 20px; + height: 20px; + color: #eff1f5; + border: 1px solid #f2f4fc1a; + border-radius: 8px; + padding: 9px; + margin: 0px; /* why is this button so weird */ - &[data-open="true"] { - background-color: #ffffffeb; - color: #0d0d0df2; + &[data-open="true"] { + background-color: #ffffffeb; + color: #0d0d0df2; + } } } } diff --git a/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx b/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx index fe3629e8..56bb52fa 100644 --- a/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx +++ b/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx @@ -4,7 +4,8 @@ import { PLAYLIST_SCENE_LIST, setPlaylistActiveScene } from "../playlist-view/pl import "./styles.css"; import { namespace } from "@renderer/App"; import IconButton from "@renderer/components/icon-button/IconButton"; -import { Component, createSignal } from "solid-js"; +import Impulse from "@renderer/lib/Impulse"; +import { Component, createSignal, onCleanup, onMount } from "solid-js"; import { PlaylistSongsQueryPayload, ResourceID } from "src/@types"; type PlaylistSongListProps = { @@ -18,6 +19,11 @@ const PlaylistSongList: Component = (props) => { playlistName: props.playlistName, }); + const reset = new Impulse(); + + onMount(() => window.api.listen("playlist::resetSongList", reset.pulse.bind(reset))); + onCleanup(() => window.api.removeListener("playlist::resetSongList", reset.pulse.bind(reset))); + const createQueue = async (songResource: ResourceID) => { await window.api.request("queue::create", { startSong: songResource, @@ -48,6 +54,7 @@ const PlaylistSongList: Component = (props) => { apiData={payload()} apiInitKey={"query::playlistSongs::init"} apiInitData={payload()} + reset={reset} fallback={
No songs in playlist...
} builder={(s) => ( = () => { {/* Right part */}
{/* // TODO - modal or something so the user can select a playlist */} - window.api.request("playlist::add", "test", song())} title="Add to playlist"> + window.api.request("playlist::add", "test", song())} + title="Add to playlist" + >
From af2649cb11edf2aeac11176870394874c7bd097e Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Sun, 13 Oct 2024 18:55:24 +0200 Subject: [PATCH 24/54] add playlist edit mode --- src/main/router/playlist-router.ts | 11 ++++-- .../playlist/playlist-item/PlaylistItem.tsx | 2 +- .../playlist/playlist-item/styles.css | 8 +++++ .../playlist-song-list/PlaylistSongList.tsx | 35 +++++++++++++------ .../playlist/playlist-song-list/styles.css | 25 +++++++++++++ 5 files changed, 67 insertions(+), 14 deletions(-) diff --git a/src/main/router/playlist-router.ts b/src/main/router/playlist-router.ts index 53dc4d64..fc30b0f3 100644 --- a/src/main/router/playlist-router.ts +++ b/src/main/router/playlist-router.ts @@ -35,8 +35,8 @@ Router.respond("playlist::delete", (_evt, name) => { playlists.delete(name); }); -Router.respond("playlist::remove", (_evt, playlistName, song) => { - console.log("delete song from " + playlistName, song); +Router.respond("playlist::remove", async (_evt, playlistName, song) => { + console.log("delete " + song.title + " from " + playlistName); const playlists = Storage.getTable("playlists"); const playlist = playlists.get(playlistName); @@ -44,10 +44,15 @@ Router.respond("playlist::remove", (_evt, playlistName, song) => { return; } - const songIndex = playlist.value.songs.indexOf(song, 0); + // i assume that audio is the primary key + const songIndex = playlist.value.songs.findIndex((s) => s.audio === song.audio); + if (songIndex > -1) { playlist.value.songs.splice(songIndex, 1); + playlist.value.count = playlist.value.count - 1; + playlist.value.length = playlist.value.length - song.duration; playlists.write(playlistName, playlist.value); + await Router.dispatch(mainWindow, "playlist::resetSongList").catch(errorIgnored); } }); diff --git a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx index eeb34472..b42c76d6 100644 --- a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx +++ b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx @@ -38,7 +38,7 @@ const PlaylistItem: Component = (props) => { {/*

{formatPlaylistTime(Math.round(props.playlist.length))}

*/}
- deletePlaylist(e, props)}> + deletePlaylist(e, props)} data-open={"false"}>
diff --git a/src/renderer/src/components/playlist/playlist-item/styles.css b/src/renderer/src/components/playlist/playlist-item/styles.css index 2dd574dd..624e9b52 100644 --- a/src/renderer/src/components/playlist/playlist-item/styles.css +++ b/src/renderer/src/components/playlist/playlist-item/styles.css @@ -53,6 +53,14 @@ border: 1px solid #f2f4fc1a; border-radius: 8px; z-index: 3; + + .icon-button { + border-radius: 8px; + &[data-open="true"] { + background-color: #ffffffeb; + color: #0d0d0df2; + } + } } } } diff --git a/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx b/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx index 56bb52fa..16e91b59 100644 --- a/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx +++ b/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx @@ -5,8 +5,8 @@ import "./styles.css"; import { namespace } from "@renderer/App"; import IconButton from "@renderer/components/icon-button/IconButton"; import Impulse from "@renderer/lib/Impulse"; -import { Component, createSignal, onCleanup, onMount } from "solid-js"; -import { PlaylistSongsQueryPayload, ResourceID } from "src/@types"; +import { Component, createSignal, Match, onCleanup, onMount, Switch } from "solid-js"; +import { PlaylistSongsQueryPayload, ResourceID, Song } from "src/@types"; type PlaylistSongListProps = { playlistName: string; @@ -19,6 +19,8 @@ const PlaylistSongList: Component = (props) => { playlistName: props.playlistName, }); + const [editMode, setEditMode] = createSignal(false); + const reset = new Impulse(); onMount(() => window.api.listen("playlist::resetSongList", reset.pulse.bind(reset))); @@ -33,6 +35,10 @@ const PlaylistSongList: Component = (props) => { }); }; + const deleteSong = async (playlistName: string, song: Song) => { + await window.api.request("playlist::remove", playlistName, song); + }; + return (
@@ -43,7 +49,7 @@ const PlaylistSongList: Component = (props) => {

{props.playlistName}

- + setEditMode(!editMode())} data-open={editMode()}>
@@ -57,13 +63,22 @@ const PlaylistSongList: Component = (props) => { reset={reset} fallback={
No songs in playlist...
} builder={(s) => ( - +
+ + + + deleteSong(props.playlistName, s)}> + + + + +
)} />
diff --git a/src/renderer/src/components/playlist/playlist-song-list/styles.css b/src/renderer/src/components/playlist/playlist-song-list/styles.css index 20c0e176..3053fbe4 100644 --- a/src/renderer/src/components/playlist/playlist-song-list/styles.css +++ b/src/renderer/src/components/playlist/playlist-song-list/styles.css @@ -35,6 +35,11 @@ .icon-button { font-size: 20px; + border-radius: 8px; + &[data-open="true"] { + background-color: #ffffffeb; + color: #0d0d0df2; + } } } } @@ -45,5 +50,25 @@ flex-direction: column; gap: 16px; } + + .playlist-song-list__list__item { + display: flex; + width: 100%; + flex-direction: row; + align-items: center; + justify-content: center; + + .song-item { + width: 100%; + } + + .icon-button { + margin-left: 12px; + margin-right: -2px; + color: lightcoral; + border-radius: 8px; + border: 1px solid #f2f4fc1a; + } + } } } From 7811f9db2cab826072ef02f8ae0969926d06ead9 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Mon, 14 Oct 2024 20:18:48 +0200 Subject: [PATCH 25/54] tailwind my beloved --- .../playlist-create/PlaylistCreateBox.tsx | 27 +++++-- .../playlist/playlist-item/PlaylistItem.tsx | 27 ++++--- .../playlist/playlist-item/styles.css | 67 ----------------- .../playlist/playlist-list/PlaylistList.tsx | 19 ++--- .../playlist/playlist-list/styles.css | 63 ---------------- .../playlist-song-list/PlaylistSongList.tsx | 33 ++++++--- .../playlist/playlist-song-list/styles.css | 74 ------------------- .../playlist/playlist-view/PlaylistView.tsx | 3 +- .../playlist/playlist-view/styles.css | 4 - .../components/song/song-item/SongItem.tsx | 2 +- .../components/song/song-list/SongList.tsx | 1 - 11 files changed, 70 insertions(+), 250 deletions(-) delete mode 100644 src/renderer/src/components/playlist/playlist-item/styles.css delete mode 100644 src/renderer/src/components/playlist/playlist-list/styles.css delete mode 100644 src/renderer/src/components/playlist/playlist-song-list/styles.css delete mode 100644 src/renderer/src/components/playlist/playlist-view/styles.css diff --git a/src/renderer/src/components/playlist/playlist-create/PlaylistCreateBox.tsx b/src/renderer/src/components/playlist/playlist-create/PlaylistCreateBox.tsx index 3d838a17..cc5b88d5 100644 --- a/src/renderer/src/components/playlist/playlist-create/PlaylistCreateBox.tsx +++ b/src/renderer/src/components/playlist/playlist-create/PlaylistCreateBox.tsx @@ -22,26 +22,37 @@ const PlaylistCreateBox: Component = (props) => { }; return ( -
-
+
+

Create a new playlist

-
-
-
- +
+
+
-
+
{ setPlaylistName(e.target.value); }} /> - +
diff --git a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx index b42c76d6..85d2333e 100644 --- a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx +++ b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx @@ -6,7 +6,6 @@ import { setPlaylistActiveScene, } from "../playlist-view/playlist-view.utils"; import { deletePlaylist, getSongImage } from "./playlist-item.utils"; -import "./styles.css"; import Impulse from "@renderer/lib/Impulse"; import { Component } from "solid-js"; import { Playlist } from "src/@types"; @@ -20,25 +19,33 @@ export type PlaylistItemProps = { const PlaylistItem: Component = (props) => { return (
{ setActivePlaylistName(props.playlist.name); setPlaylistActiveScene(PLAYLIST_SCENE_SONGS); }} > -
-
- +
+
+
-
-
-

{props.playlist.name}

+
+
+

{props.playlist.name}

{props.playlist.count} songs

{/*

{formatPlaylistTime(Math.round(props.playlist.length))}

*/}
-
- deletePlaylist(e, props)} data-open={"false"}> +
+ deletePlaylist(e, props)} + data-open={"false"} + >
diff --git a/src/renderer/src/components/playlist/playlist-item/styles.css b/src/renderer/src/components/playlist/playlist-item/styles.css deleted file mode 100644 index 624e9b52..00000000 --- a/src/renderer/src/components/playlist/playlist-item/styles.css +++ /dev/null @@ -1,67 +0,0 @@ -.playlist-item { - --image-size: 71px; - - .playlist-item-container { - display: flex; - flex-direction: row; - gap: 16px; - - .playlist-item__playlist-img { - /* margin: auto 6px auto 6px; */ - border-radius: var(--rounded-lg); - .song-image { - width: var(--image-size); - height: var(--image-size); - background-size: cover; - background-position: center; - border-radius: 8px; - } - } - - .playlist-item__playlist-info { - display: flex; - flex-direction: row; - align-items: center; - margin-left: 6px; - justify-content: space-between; - width: 100%; - - .playlist-item__playlist-info__text { - display: flex; - flex-direction: column; - justify-content: center; - font-weight: 500; - line-height: 24px; - font-size: 16px; - color: #eff1f5; - } - - .playlist-item__playlist-info__text h3 { - font-size: 30px; - line-height: 30px; - font-weight: 700; - } - - .playlist-item__playlist-info__button { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - height: 40px; - width: 40px; - color: #eff1f5; - border: 1px solid #f2f4fc1a; - border-radius: 8px; - z-index: 3; - - .icon-button { - border-radius: 8px; - &[data-open="true"] { - background-color: #ffffffeb; - color: #0d0d0df2; - } - } - } - } - } -} diff --git a/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx b/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx index d58fa706..9af532cb 100644 --- a/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx +++ b/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx @@ -1,4 +1,3 @@ -import "../../../assets/css/song/song-view.css"; import InfiniteScroller from "../../InfiniteScroller"; import IconButton from "../../icon-button/IconButton"; import PlaylistCreateBox from "../playlist-create/PlaylistCreateBox"; @@ -7,7 +6,6 @@ import PlaylistItem from "../playlist-item/PlaylistItem"; // PLAYLIST_SCENE_CREATE, // setPlaylistActiveScene, // } from "../playlist-view/playlist-view.utils"; -import "./styles.css"; import { namespace } from "@renderer/App"; import Impulse from "@renderer/lib/Impulse"; import { Component, createSignal, Match, onCleanup, onMount, Switch } from "solid-js"; @@ -28,7 +26,7 @@ const PlaylistList: Component = () => { ); return ( -
+
{/* = () => { error={searchError} /> */} -
-
+
+
{ // setPlaylistSearch(e.target.value); // }} /> - +
-
+
{ // setPlaylistActiveScene(PLAYLIST_SCENE_CREATE); setShowCreateBox(!showCreateBox()); }} + classList={{ "bg-accent text-thick-material": showCreateBox() }} data-open={showCreateBox()} > @@ -63,7 +63,7 @@ const PlaylistList: Component = () => {
-
+
@@ -75,6 +75,7 @@ const PlaylistList: Component = () => { setCount={setCount} reset={resetListing} fallback={
No playlists...
} + class="flex flex-col gap-4" builder={(s) => ( )} diff --git a/src/renderer/src/components/playlist/playlist-list/styles.css b/src/renderer/src/components/playlist/playlist-list/styles.css deleted file mode 100644 index e3015934..00000000 --- a/src/renderer/src/components/playlist/playlist-list/styles.css +++ /dev/null @@ -1,63 +0,0 @@ -.playlist-list { - margin: 24px 20px; - .playlist-list__header { - display: flex; - flex-direction: row; - align-items: center; - margin-bottom: 24px; - - .playlist-list__header__input-container { - display: flex; - flex-direction: row; - justify-content: space-between; - flex: 1; - height: 40px; - align-items: center; - border: 1px solid #f2f4fc1a; - border-radius: 8px; - /* padding: 8px 12px; */ - margin-right: 8px; - - .playlist-list__header__input { - background-color: transparent; - border: none; - font-size: 16px; - color: white; - font-family: inherit; - margin-left: 12px; - width: 100%; - } - .playlist-list__header__search-icon { - font-size: 20px; - color: #eff1f599; - margin-right: 12px; - } - } - - .playlist-list__header__create-playlist { - .icon-button { - font-size: 20px; - width: 20px; - height: 20px; - color: #eff1f5; - border: 1px solid #f2f4fc1a; - border-radius: 8px; - padding: 9px; - margin: 0px; /* why is this button so weird */ - - &[data-open="true"] { - background-color: #ffffffeb; - color: #0d0d0df2; - } - } - } - } - - .playlist-list__body { - .list { - display: flex; - flex-direction: column; - gap: 16px; - } - } -} diff --git a/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx b/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx index 16e91b59..e56fb677 100644 --- a/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx +++ b/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx @@ -1,7 +1,6 @@ import InfiniteScroller from "../../InfiniteScroller"; import SongItem from "../../song/song-item/SongItem"; import { PLAYLIST_SCENE_LIST, setPlaylistActiveScene } from "../playlist-view/playlist-view.utils"; -import "./styles.css"; import { namespace } from "@renderer/App"; import IconButton from "@renderer/components/icon-button/IconButton"; import Impulse from "@renderer/lib/Impulse"; @@ -40,30 +39,39 @@ const PlaylistSongList: Component = (props) => { }; return ( -
-
-
- setPlaylistActiveScene(PLAYLIST_SCENE_LIST)}> +
+
+
+ setPlaylistActiveScene(PLAYLIST_SCENE_LIST)} + class="text-xl text-text" + >

{props.playlistName}

-
- setEditMode(!editMode())} data-open={editMode()}> +
+ setEditMode(!editMode())} + data-open={editMode()} + class="rounded-lg text-xl" + classList={{ "bg-accent text-thick-material": editMode() }} + >
-
+
No songs in playlist...
} builder={(s) => ( -
+
= (props) => { > - deleteSong(props.playlistName, s)}> - + deleteSong(props.playlistName, s)} + class="ml-3 mr-[-2px] rounded-lg border border-stroke text-rose-300" + > + diff --git a/src/renderer/src/components/playlist/playlist-song-list/styles.css b/src/renderer/src/components/playlist/playlist-song-list/styles.css deleted file mode 100644 index 3053fbe4..00000000 --- a/src/renderer/src/components/playlist/playlist-song-list/styles.css +++ /dev/null @@ -1,74 +0,0 @@ -.playlist-song-list { - margin: 24px 20px; - .playlist-song-list__top { - width: 100%; - margin-bottom: 24px; - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - - .playlist-song-list__top__left { - display: flex; - flex-direction: row; - align-items: center; - font-size: 20px; - line-height: 24px; - font-weight: 500; - gap: 20px; - - .icon-button { - font-size: 20px; - color: #eff1f599; - } - } - - .playlist-song-list__top__right { - display: flex; - align-items: center; - justify-content: center; - border: 1px solid #f2f4fc1a; - color: #eff1f5; - width: 40px; - height: 40px; - border-radius: 8px; - - .icon-button { - font-size: 20px; - border-radius: 8px; - &[data-open="true"] { - background-color: #ffffffeb; - color: #0d0d0df2; - } - } - } - } - - .playlist-song-list__list { - .list { - display: flex; - flex-direction: column; - gap: 16px; - } - - .playlist-song-list__list__item { - display: flex; - width: 100%; - flex-direction: row; - align-items: center; - justify-content: center; - - .song-item { - width: 100%; - } - - .icon-button { - margin-left: 12px; - margin-right: -2px; - color: lightcoral; - border-radius: 8px; - border: 1px solid #f2f4fc1a; - } - } - } -} diff --git a/src/renderer/src/components/playlist/playlist-view/PlaylistView.tsx b/src/renderer/src/components/playlist/playlist-view/PlaylistView.tsx index 9c4dcefa..f3eb5a3e 100644 --- a/src/renderer/src/components/playlist/playlist-view/PlaylistView.tsx +++ b/src/renderer/src/components/playlist/playlist-view/PlaylistView.tsx @@ -8,14 +8,13 @@ import { playlistActiveScene, activePlaylistName, } from "./playlist-view.utils"; -import "./styles.css"; import { Component, Match, Switch } from "solid-js"; export type PlaylistViewProps = {}; const PlaylistView: Component = () => { return ( -
+
idk
}> diff --git a/src/renderer/src/components/playlist/playlist-view/styles.css b/src/renderer/src/components/playlist/playlist-view/styles.css deleted file mode 100644 index cc0043bc..00000000 --- a/src/renderer/src/components/playlist/playlist-view/styles.css +++ /dev/null @@ -1,4 +0,0 @@ -.playlist-view { - height: 100%; - overflow-y: auto; -} diff --git a/src/renderer/src/components/song/song-item/SongItem.tsx b/src/renderer/src/components/song/song-item/SongItem.tsx index 825bf2d6..32595137 100644 --- a/src/renderer/src/components/song/song-item/SongItem.tsx +++ b/src/renderer/src/components/song/song-item/SongItem.tsx @@ -54,7 +54,7 @@ const SongItem: Component = ({ return (
Date: Mon, 14 Oct 2024 22:47:48 +0200 Subject: [PATCH 26/54] use Button component instead of IconButton --- src/renderer/src/components/button/Button.tsx | 1 + .../playlist-create/PlaylistCreateBox.tsx | 7 +- .../playlist/playlist-item/PlaylistItem.tsx | 21 +++--- .../playlist/playlist-list/PlaylistList.tsx | 73 +++++++++++-------- .../playlist-song-list/PlaylistSongList.tsx | 35 +++++---- 5 files changed, 76 insertions(+), 61 deletions(-) diff --git a/src/renderer/src/components/button/Button.tsx b/src/renderer/src/components/button/Button.tsx index 6262ce25..d731902c 100644 --- a/src/renderer/src/components/button/Button.tsx +++ b/src/renderer/src/components/button/Button.tsx @@ -15,6 +15,7 @@ const buttonStyles = cva( size: { medium: "px-4 py-2", large: "px-7 py-2.5", + icon: "h-10 w-10", }, }, defaultVariants: { diff --git a/src/renderer/src/components/playlist/playlist-create/PlaylistCreateBox.tsx b/src/renderer/src/components/playlist/playlist-create/PlaylistCreateBox.tsx index cc5b88d5..a1b6b0b5 100644 --- a/src/renderer/src/components/playlist/playlist-create/PlaylistCreateBox.tsx +++ b/src/renderer/src/components/playlist/playlist-create/PlaylistCreateBox.tsx @@ -1,3 +1,4 @@ +import IconButton from "@renderer/components/icon-button/IconButton"; import SongImage from "@renderer/components/song/SongImage"; import Impulse from "@renderer/lib/Impulse"; import { Component, createSignal, Setter } from "solid-js"; @@ -25,9 +26,9 @@ const PlaylistCreateBox: Component = (props) => {

Create a new playlist

- + props.isOpen(false)}> + +
diff --git a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx index 85d2333e..23b22e77 100644 --- a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx +++ b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx @@ -1,4 +1,3 @@ -import IconButton from "../../icon-button/IconButton"; import SongImage from "../../song/SongImage"; import { PLAYLIST_SCENE_SONGS, @@ -6,6 +5,7 @@ import { setPlaylistActiveScene, } from "../playlist-view/playlist-view.utils"; import { deletePlaylist, getSongImage } from "./playlist-item.utils"; +import Button from "@renderer/components/button/Button"; import Impulse from "@renderer/lib/Impulse"; import { Component } from "solid-js"; import { Playlist } from "src/@types"; @@ -39,16 +39,15 @@ const PlaylistItem: Component = (props) => {

{props.playlist.count} songs

{/*

{formatPlaylistTime(Math.round(props.playlist.length))}

*/}
-
- deletePlaylist(e, props)} - data-open={"false"} - > - - -
+
diff --git a/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx b/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx index 9af532cb..44a318e2 100644 --- a/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx +++ b/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx @@ -1,5 +1,4 @@ import InfiniteScroller from "../../InfiniteScroller"; -import IconButton from "../../icon-button/IconButton"; import PlaylistCreateBox from "../playlist-create/PlaylistCreateBox"; import PlaylistItem from "../playlist-item/PlaylistItem"; // import { @@ -7,6 +6,7 @@ import PlaylistItem from "../playlist-item/PlaylistItem"; // setPlaylistActiveScene, // } from "../playlist-view/playlist-view.utils"; import { namespace } from "@renderer/App"; +import Button from "@renderer/components/button/Button"; import Impulse from "@renderer/lib/Impulse"; import { Component, createSignal, Match, onCleanup, onMount, Switch } from "solid-js"; @@ -26,7 +26,7 @@ const PlaylistList: Component = () => { ); return ( -
+
{/* = () => { error={searchError} /> */} -
-
- { - // setPlaylistSearch(e.target.value); - // }} - /> - +
+
+
+ { + // setPlaylistSearch(e.target.value); + // }} + /> + +
+
+ {/* // TODO: fix button misaligning when the scrollbar appears */} + +
-
- { - // setPlaylistActiveScene(PLAYLIST_SCENE_CREATE); - setShowCreateBox(!showCreateBox()); - }} - classList={{ "bg-accent text-thick-material": showCreateBox() }} - data-open={showCreateBox()} - > - - -
-
- -
+
+ +
No playlists...
} - class="flex flex-col gap-4" + class="mx-5 my-6 flex w-full flex-col gap-4" builder={(s) => ( )} diff --git a/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx b/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx index e56fb677..fc03037e 100644 --- a/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx +++ b/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx @@ -2,6 +2,7 @@ import InfiniteScroller from "../../InfiniteScroller"; import SongItem from "../../song/song-item/SongItem"; import { PLAYLIST_SCENE_LIST, setPlaylistActiveScene } from "../playlist-view/playlist-view.utils"; import { namespace } from "@renderer/App"; +import Button from "@renderer/components/button/Button"; import IconButton from "@renderer/components/icon-button/IconButton"; import Impulse from "@renderer/lib/Impulse"; import { Component, createSignal, Match, onCleanup, onMount, Switch } from "solid-js"; @@ -46,20 +47,19 @@ const PlaylistSongList: Component = (props) => { onClick={() => setPlaylistActiveScene(PLAYLIST_SCENE_LIST)} class="text-xl text-text" > - - -

{props.playlistName}

-
-
- setEditMode(!editMode())} - data-open={editMode()} - class="rounded-lg text-xl" - classList={{ "bg-accent text-thick-material": editMode() }} - > - + +

{props.playlistName}

+
= (props) => { > - deleteSong(props.playlistName, s)} - class="ml-3 mr-[-2px] rounded-lg border border-stroke text-rose-300" > - - + +
From bcbd77c39243b11d3ca1c900c8f1466c5cd3d286 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Tue, 15 Oct 2024 16:08:31 +0200 Subject: [PATCH 27/54] fix buttons, add rename playlist api --- src/RequestAPI.d.ts | 1 + src/main/router/playlist-router.ts | 17 ++++++- .../playlist/playlist-item/PlaylistItem.tsx | 4 +- .../playlist/playlist-list/PlaylistList.tsx | 10 ++-- .../playlist-song-list/PlaylistSongList.tsx | 48 +++++++++++++++++-- 5 files changed, 68 insertions(+), 12 deletions(-) diff --git a/src/RequestAPI.d.ts b/src/RequestAPI.d.ts index 350a7746..358a8abb 100644 --- a/src/RequestAPI.d.ts +++ b/src/RequestAPI.d.ts @@ -43,6 +43,7 @@ export type RequestAPI = { "playlist::remove": (playlistName: string, song: Song) => void; "playlist::create": (name: string) => void; "playlist::delete": (name: string) => void; + "playlist::rename": (oldName: string, newName: string) => void; "dir::select": () => Optional; "dir::autoGetOsuDir": () => Optional; diff --git a/src/main/router/playlist-router.ts b/src/main/router/playlist-router.ts index fc30b0f3..450af860 100644 --- a/src/main/router/playlist-router.ts +++ b/src/main/router/playlist-router.ts @@ -5,6 +5,8 @@ import { Storage } from "../lib/storage/Storage"; import errorIgnored from "../lib/tungsten/errorIgnored"; import { mainWindow } from "../main"; +const BUFFER_SIZE = 50; + Router.respond("playlist::add", async (_evt, playlistName, song) => { const playlists = Storage.getTable("playlists"); const playlist = playlists.get(playlistName); @@ -56,7 +58,20 @@ Router.respond("playlist::remove", async (_evt, playlistName, song) => { } }); -const BUFFER_SIZE = 50; +Router.respond("playlist::rename", (_evt, oldName, newName) => { + console.log("rename from " + oldName + " to " + newName); + const playlists = Storage.getTable("playlists"); + const oldPlaylist = playlists.get(oldName); + + if (oldPlaylist.isNone) { + return; + } + + oldPlaylist.value.name = newName; + //todo: check if the new name is already used + playlists.write(newName, oldPlaylist.value); + playlists.delete(oldName); +}); Router.respond("query::playlists::init", (_evt) => { const playlists = Storage.getTable("playlists").getStruct(); diff --git a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx index 23b22e77..2439ea4f 100644 --- a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx +++ b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx @@ -23,9 +23,10 @@ const PlaylistItem: Component = (props) => { setActivePlaylistName(props.playlist.name); setPlaylistActiveScene(PLAYLIST_SCENE_SONGS); }} + class="max-w-[428px]" >
-
+
= (props) => {
From 6335b185eeb581dbe65b4c1d974fb017d5a6a1e2 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Tue, 15 Oct 2024 17:12:28 +0200 Subject: [PATCH 28/54] add playlistNames api --- src/@types.d.ts | 4 ++++ src/RequestAPI.d.ts | 2 ++ src/main/router/playlist-router.ts | 9 +++++++++ 3 files changed, 15 insertions(+) diff --git a/src/@types.d.ts b/src/@types.d.ts index a46cc842..1a5b7d45 100644 --- a/src/@types.d.ts +++ b/src/@types.d.ts @@ -246,3 +246,7 @@ export type InfiniteScrollerInitResponse = Optional<{ initialIndex: number; count: number; }>; + +export type PlaylistNamesResponse = Optional<{ + playlistNames: string[]; +}>; diff --git a/src/RequestAPI.d.ts b/src/RequestAPI.d.ts index 358a8abb..75afad62 100644 --- a/src/RequestAPI.d.ts +++ b/src/RequestAPI.d.ts @@ -6,6 +6,7 @@ import type { InfiniteScrollerResponse, Optional, Playlist, + PlaylistNamesResponse, PlaylistSongsQueryPayload, QueueCreatePayload, ResourceID, @@ -83,6 +84,7 @@ export type RequestAPI = { request: InfiniteScrollerRequest, payload: PlaylistSongsQueryPayload, ) => InfiniteScrollerResponse; + "query::playlistNames": () => PlaylistNamesResponse; "save::localVolume": (volume: number, song: ResourceID) => void; diff --git a/src/main/router/playlist-router.ts b/src/main/router/playlist-router.ts index 450af860..882f32ca 100644 --- a/src/main/router/playlist-router.ts +++ b/src/main/router/playlist-router.ts @@ -83,6 +83,15 @@ Router.respond("query::playlists::init", (_evt) => { }); }); +Router.respond("query::playlistNames", () => { + const playlists = Storage.getTable("playlists").getStruct(); + const names = Object.keys(playlists); + + return some({ + playlistNames: names, + }); +}); + Router.respond("query::playlists", (_evt, request) => { const playlists = Object.keys(Storage.getTable("playlists").getStruct()); From 7f5246425831dcfeeae03ae244a92cbe5504782d Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Wed, 16 Oct 2024 23:26:04 +0200 Subject: [PATCH 29/54] temporary context menu to edit playlists --- .../playlist/playlist-item/ContextMenuBox.tsx | 34 ++++++++++++ .../playlist/playlist-item/PlaylistItem.tsx | 54 ++++++++++++++++--- .../playlist-item/playlist-item.utils.ts | 9 ++++ .../playlist/playlist-list/PlaylistList.tsx | 27 +++++++--- 4 files changed, 110 insertions(+), 14 deletions(-) create mode 100644 src/renderer/src/components/playlist/playlist-item/ContextMenuBox.tsx diff --git a/src/renderer/src/components/playlist/playlist-item/ContextMenuBox.tsx b/src/renderer/src/components/playlist/playlist-item/ContextMenuBox.tsx new file mode 100644 index 00000000..b14123f1 --- /dev/null +++ b/src/renderer/src/components/playlist/playlist-item/ContextMenuBox.tsx @@ -0,0 +1,34 @@ +import { PlaylistItemProps } from "./PlaylistItem"; +import { deletePlaylist } from "./playlist-item.utils"; +import { Component, Setter } from "solid-js"; + +type ContextMenuBoxProps = { + playlistItem: PlaylistItemProps; + editSignal: Setter; +}; + +const ContextMenuBox: Component = (props) => { + return ( +
+
+ + +
+
+ ); +}; + +export default ContextMenuBox; diff --git a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx index 2439ea4f..4a1439d0 100644 --- a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx +++ b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx @@ -4,10 +4,11 @@ import { setActivePlaylistName, setPlaylistActiveScene, } from "../playlist-view/playlist-view.utils"; -import { deletePlaylist, getSongImage } from "./playlist-item.utils"; +import ContextMenuBox from "./ContextMenuBox"; +import { getSongImage, renamePlaylist } from "./playlist-item.utils"; import Button from "@renderer/components/button/Button"; import Impulse from "@renderer/lib/Impulse"; -import { Component } from "solid-js"; +import { Component, createSignal, Match, Switch } from "solid-js"; import { Playlist } from "src/@types"; export type PlaylistItemProps = { @@ -17,11 +18,17 @@ export type PlaylistItemProps = { }; const PlaylistItem: Component = (props) => { + const [showBox, setShowBox] = createSignal(false); + const [playlistName, setPlaylistName] = createSignal(""); + const [editMode, setEditMode] = createSignal(false); + return (
{ - setActivePlaylistName(props.playlist.name); - setPlaylistActiveScene(PLAYLIST_SCENE_SONGS); + if (!editMode()) { + setActivePlaylistName(props.playlist.name); + setPlaylistActiveScene(PLAYLIST_SCENE_SONGS); + } }} class="max-w-[428px]" > @@ -36,7 +43,30 @@ const PlaylistItem: Component = (props) => {
-

{props.playlist.name}

+ {/*

{props.playlist.name}

*/} + + + { + setPlaylistName(e.target.value); + }} + onKeyPress={async (e) => { + if (e.key == "Enter") { + await renamePlaylist(props.playlist.name, playlistName()); + setEditMode(false); + props.reset.pulse(); + } + }} + /> + + +

{props.playlist.name}

+
+

{props.playlist.count} songs

{/*

{formatPlaylistTime(Math.round(props.playlist.length))}

*/}
@@ -46,11 +76,23 @@ const PlaylistItem: Component = (props) => { size={"icon"} class="flex items-center justify-center border" classList={{ "bg-accent text-thick-material": false }} - onClick={(e) => deletePlaylist(e, props)} + // onClick={(e) => deletePlaylist(e, props)} + onClick={(e) => { + e.stopPropagation(); + setShowBox(!showBox()); + }} >
+ +
+ + + + + +
); diff --git a/src/renderer/src/components/playlist/playlist-item/playlist-item.utils.ts b/src/renderer/src/components/playlist/playlist-item/playlist-item.utils.ts index c0fcde06..a654ee7c 100644 --- a/src/renderer/src/components/playlist/playlist-item/playlist-item.utils.ts +++ b/src/renderer/src/components/playlist/playlist-item/playlist-item.utils.ts @@ -28,3 +28,12 @@ export function deletePlaylist(e: Event, props: PlaylistItemProps) { // return hours + " hours " + minutes + " minutes"; // } +export const renamePlaylist = async (oldName: string, newName: string) => { + newName = newName.trim(); + if (newName === undefined || newName === "" || newName === oldName) { + return; + } + + await window.api.request("playlist::rename", oldName, newName); + // reset.pulse(); +}; diff --git a/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx b/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx index e746778e..33bff173 100644 --- a/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx +++ b/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx @@ -47,14 +47,25 @@ const PlaylistList: Component = () => { // setPlaylistSearch(e.target.value); // }} /> - + {/* this whole switch-match only for -translate-y-[], classlist doesn't work, if there's a better way pls tell me */} + + + + + + + +
{/* // TODO: fix button misaligning when the scrollbar appears */} From 8b9e26b523768bb740aefba01957f43652e9080d Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Thu, 17 Oct 2024 15:04:40 +0200 Subject: [PATCH 30/54] fix errors, add none order type, remove old playlist create scene --- src/@types.d.ts | 9 +- src/main/lib/song/order.ts | 5 +- src/main/router/playlist-router.ts | 2 +- .../playlist-create/PlaylistCreate.tsx | 47 ------ .../playlist/playlist-create/styles.css | 135 ------------------ .../playlist/playlist-item/PlaylistItem.tsx | 2 +- .../playlist/playlist-list/PlaylistList.tsx | 11 +- .../playlist-song-list/PlaylistSongList.tsx | 4 +- .../playlist/playlist-view/PlaylistView.tsx | 9 +- .../playlist-view/playlist-view.utils.ts | 3 +- 10 files changed, 20 insertions(+), 207 deletions(-) delete mode 100644 src/renderer/src/components/playlist/playlist-create/PlaylistCreate.tsx delete mode 100644 src/renderer/src/components/playlist/playlist-create/styles.css diff --git a/src/@types.d.ts b/src/@types.d.ts index bbd1b24c..8efc5105 100644 --- a/src/@types.d.ts +++ b/src/@types.d.ts @@ -175,7 +175,14 @@ export type Tag = { isSpecial?: boolean; }; -export type OrderOptions = "title" | "artist" | "creator" | "bpm" | "duration" | "dateAdded"; +export type OrderOptions = + | "title" + | "artist" + | "creator" + | "bpm" + | "duration" + | "dateAdded" + | "none"; export type OrderDirection = "asc" | "desc"; diff --git a/src/main/lib/song/order.ts b/src/main/lib/song/order.ts index 40fc7c74..a9eeccd0 100644 --- a/src/main/lib/song/order.ts +++ b/src/main/lib/song/order.ts @@ -1,5 +1,5 @@ import { Order, Result, Song } from "../../../@types"; -import { ok } from "../rust-like-utils-backend/Result"; +import { fail, ok } from "../rust-like-utils-backend/Result"; import { averageBPM, msToBPM } from "./average-bpm"; export default function order(ordering: Order): Result<(a: Song, b: Song) => number, string> { @@ -46,6 +46,9 @@ export default function order(ordering: Order): Result<(a: Song, b: Song) => num case "duration": return ok((a: Song, b: Song) => (a.duration - b.duration) * sortDirection); + case "none": + return fail(""); + default: return ok((a: Song, b: Song) => { if (a[option] === "") { diff --git a/src/main/router/playlist-router.ts b/src/main/router/playlist-router.ts index 882f32ca..0799a7bd 100644 --- a/src/main/router/playlist-router.ts +++ b/src/main/router/playlist-router.ts @@ -73,7 +73,7 @@ Router.respond("playlist::rename", (_evt, oldName, newName) => { playlists.delete(oldName); }); -Router.respond("query::playlists::init", (_evt) => { +Router.respond("query::playlists::init", () => { const playlists = Storage.getTable("playlists").getStruct(); const count = Object.keys(playlists).length; diff --git a/src/renderer/src/components/playlist/playlist-create/PlaylistCreate.tsx b/src/renderer/src/components/playlist/playlist-create/PlaylistCreate.tsx deleted file mode 100644 index ab049435..00000000 --- a/src/renderer/src/components/playlist/playlist-create/PlaylistCreate.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { PLAYLIST_SCENE_LIST, setPlaylistActiveScene } from "../playlist-view/playlist-view.utils"; -import "./styles.css"; -import IconButton from "@renderer/components/icon-button/IconButton"; -import { Component, createSignal } from "solid-js"; - -export type PlaylistCreateProps = {}; - -const PlaylistCreate: Component = () => { - const [playlistName, setPlaylistName] = createSignal(""); - - const createPlaylist = () => { - // last check is probably unnecessary - if (playlistName().length === 0 || playlistName() === undefined || playlistName() === "") { - return; - } - window.api.request("playlist::create", playlistName().trim()); - setPlaylistActiveScene(PLAYLIST_SCENE_LIST); - setPlaylistName(""); - }; - - return ( -
-
-
- setPlaylistActiveScene(PLAYLIST_SCENE_LIST)}> - - -

New playlist

-
-
-

Name

- { - setPlaylistName(e.target.value); - }} - /> -
-
- -
- ); -}; - -export default PlaylistCreate; diff --git a/src/renderer/src/components/playlist/playlist-create/styles.css b/src/renderer/src/components/playlist/playlist-create/styles.css deleted file mode 100644 index 9b7f5823..00000000 --- a/src/renderer/src/components/playlist/playlist-create/styles.css +++ /dev/null @@ -1,135 +0,0 @@ -.playlist-create { - display: flex; - flex-direction: column; - justify-content: space-between; - height: 100%; - margin-left: 20px; - margin-right: 20px; - .playlist-create__top { - margin-top: 24px; - .playlist-create__top__header { - display: flex; - flex-direction: row; - align-items: center; - gap: 20px; - font-size: 20px; - color: #eff1f5; - - i { - color: #eff1f599; - } - } - - .playlist-create__top__body { - display: flex; - flex-direction: column; - margin-top: 24px; - gap: 8px; - color: #ffffffd1; - - input { - height: 44px; - border-radius: 8px; - background-color: #84898f33; - border: none; - color: #ffffff; - padding: 10px 16px 10px 16px; - font-size: 16px; - line-height: 24px; - font-weight: 400; - font-family: inherit; - } - } - } - - .playlist-create__footer { - button { - width: 100%; - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - margin-bottom: 24px; - height: 42px; - background-color: #ffffffeb; - color: black; - font-weight: 600; - border-radius: 8px; - } - - /* button:hover { - cursor: pointer; - } */ - } -} - -.playlist-create-box { - background-color: #0d0d0df2; - border-radius: 12px; - margin-bottom: 24px; - - .playlist-create-box__header { - display: flex; - flex-direction: row; - justify-content: space-between; - padding: 16px; - - button { - font-size: 20px; - } - } - - .playlist-create-box__body { - display: flex; - flex-direction: row; - margin: 16px; - margin-top: 0px; - - .playlist-create-box__body__image { - border-radius: 8px; - margin-right: 16px; - .song-image { - width: 83px; - height: 83px; - background-size: cover; - background-position: center; - border-radius: 8px; - } - } - - .playlist-create-box__body__input { - display: flex; - flex-direction: column; - gap: 12px; - width: 100%; - - input { - height: 36px; - border-radius: 8px; - background-color: #84898f33; - border: none; - color: #ffffff; - padding: 10px 0px 10px 16px; - font-size: 16px; - line-height: 24px; - font-weight: 400; - font-family: inherit; - width: 100%; - } - - button { - width: 100%; - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - margin-bottom: 24px; - height: 36px; - background-color: #ffffffeb; - color: black; - font-weight: 600; - border-radius: 8px; - } - } - } -} diff --git a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx index 4a1439d0..8e210250 100644 --- a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx +++ b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx @@ -30,7 +30,7 @@ const PlaylistItem: Component = (props) => { setPlaylistActiveScene(PLAYLIST_SCENE_SONGS); } }} - class="max-w-[428px]" + class="" >
diff --git a/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx b/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx index 33bff173..0507a3d3 100644 --- a/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx +++ b/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx @@ -1,20 +1,14 @@ import InfiniteScroller from "../../InfiniteScroller"; import PlaylistCreateBox from "../playlist-create/PlaylistCreateBox"; import PlaylistItem from "../playlist-item/PlaylistItem"; -// import { -// PLAYLIST_SCENE_CREATE, -// setPlaylistActiveScene, -// } from "../playlist-view/playlist-view.utils"; import { namespace } from "@renderer/App"; import Button from "@renderer/components/button/Button"; import Impulse from "@renderer/lib/Impulse"; import { Component, createSignal, Match, onCleanup, onMount, Switch } from "solid-js"; -export type PlaylistListProps = {}; - -const PlaylistList: Component = () => { +const PlaylistList: Component = () => { // const [playlistSearch, setPlaylistSearch] = createSignal(""); - const [_count, setCount] = createSignal(0); + const [, setCount] = createSignal(0); const resetListing = new Impulse(); const [showCreateBox, setShowCreateBox] = createSignal(false); @@ -71,7 +65,6 @@ const PlaylistList: Component = () => { {/* // TODO: fix button misaligning when the scrollbar appears */}
- - - - - + + +
diff --git a/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx b/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx index eff0557b..6ab95177 100644 --- a/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx +++ b/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx @@ -5,7 +5,7 @@ import { namespace } from "@renderer/App"; import Button from "@renderer/components/button/Button"; import Impulse from "@renderer/lib/Impulse"; import { PlusIcon, SearchIcon } from "lucide-solid"; -import { Component, createSignal, Match, onCleanup, onMount, Switch } from "solid-js"; +import { Component, createSignal, onCleanup, onMount, Show } from "solid-js"; import { twMerge } from "tailwind-merge"; const PlaylistList: Component = () => { @@ -59,7 +59,6 @@ const PlaylistList: Component = () => { onClick={() => { setShowCreateBox(!showCreateBox()); }} - // bg-accent doesn't work for some reason class="rounded-lg text-xl" variant={showCreateBox() ? "accent" : "ghost"} size={"icon"} @@ -68,11 +67,9 @@ const PlaylistList: Component = () => {
- - - - - + + +
diff --git a/src/renderer/src/components/playlist/playlist-view/playlist-view.utils.ts b/src/renderer/src/components/playlist/playlist-view/playlist-view.utils.ts index d5ff3b76..4b3fd8e9 100644 --- a/src/renderer/src/components/playlist/playlist-view/playlist-view.utils.ts +++ b/src/renderer/src/components/playlist/playlist-view/playlist-view.utils.ts @@ -1,7 +1,7 @@ import { createSignal } from "solid-js"; const PLAYLIST_SCENE_LIST = 0; -const PLAYLIST_SCENE_SONGS = 2; +const PLAYLIST_SCENE_SONGS = 1; const [playlistActiveScene, setPlaylistActiveScene] = createSignal(PLAYLIST_SCENE_LIST); const [activePlaylistName, setActivePlaylistName] = createSignal(""); diff --git a/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx b/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx index 8173268e..991aadb4 100644 --- a/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx +++ b/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx @@ -1,6 +1,6 @@ -import { Component, createSignal, Show } from "solid-js"; import { Song } from "../../../../../../@types"; import SongContextMenuItem from "../SongContextMenuItem"; +import { Component, createSignal, Show } from "solid-js"; type SongAddToPlaylistNextProps = { song: Song; diff --git a/src/renderer/src/scenes/main-scene/MainScene.tsx b/src/renderer/src/scenes/main-scene/MainScene.tsx index 23536008..88209136 100644 --- a/src/renderer/src/scenes/main-scene/MainScene.tsx +++ b/src/renderer/src/scenes/main-scene/MainScene.tsx @@ -1,9 +1,9 @@ -import PlaylistView from "@renderer/components/playlist/playlist-view/PlaylistView"; import SongDetail from "../../components/song/song-detail/SongDetail"; import SongList from "../../components/song/song-list/SongList"; import { mainActiveTab, setMainActiveTab, Tab, TABS } from "./main.utils"; import "./styles.css"; import Button from "@renderer/components/button/Button"; +import PlaylistView from "@renderer/components/playlist/playlist-view/PlaylistView"; import Settings from "@renderer/components/settings/Settings"; import SongImage from "@renderer/components/song/SongImage"; import SongQueue from "@renderer/components/song/song-queue/SongQueue"; From f875cf1b9e4cd64a841ce890c17d44d89c8f9c53 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Mon, 21 Oct 2024 23:42:27 +0200 Subject: [PATCH 32/54] clearer variable names --- src/main/router/playlist-router.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/router/playlist-router.ts b/src/main/router/playlist-router.ts index 0799a7bd..270026ac 100644 --- a/src/main/router/playlist-router.ts +++ b/src/main/router/playlist-router.ts @@ -93,20 +93,19 @@ Router.respond("query::playlistNames", () => { }); Router.respond("query::playlists", (_evt, request) => { - const playlists = Object.keys(Storage.getTable("playlists").getStruct()); + const playlistNames = Object.keys(Storage.getTable("playlists").getStruct()); - //todo: there has to be a better way to do this - const p = Storage.getTable("playlists"); + const playlists = Storage.getTable("playlists"); const playlistsInfo: Playlist[] = []; - playlists.forEach((v) => { - const plist = p.get(v); + playlistNames.forEach((name) => { + const plist = playlists.get(name); if (plist.isNone) { return; } playlistsInfo.push({ - name: v, + name: name, count: plist.value.count, length: plist.value.length, songs: plist.value.songs, From 4e903d02e8408c444c9c04b60f2b07ed450be300 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Thu, 24 Oct 2024 18:46:24 +0200 Subject: [PATCH 33/54] playlist notices --- .../playlist-create/PlaylistCreateBox.tsx | 15 ++++++++++++--- .../playlist-item/playlist-item.utils.ts | 14 ++++++++++++++ .../song/context-menu/items/AddToPlaylist.tsx | 18 +++++++++++++----- .../song/song-detail/SongControls.tsx | 12 +++++++++++- 4 files changed, 50 insertions(+), 9 deletions(-) diff --git a/src/renderer/src/components/playlist/playlist-create/PlaylistCreateBox.tsx b/src/renderer/src/components/playlist/playlist-create/PlaylistCreateBox.tsx index 902b1407..3fde7b39 100644 --- a/src/renderer/src/components/playlist/playlist-create/PlaylistCreateBox.tsx +++ b/src/renderer/src/components/playlist/playlist-create/PlaylistCreateBox.tsx @@ -1,7 +1,8 @@ import Button from "@renderer/components/button/Button"; +import { addNotice } from "@renderer/components/notice/NoticeContainer"; import SongImage from "@renderer/components/song/SongImage"; import Impulse from "@renderer/lib/Impulse"; -import { XIcon } from "lucide-solid"; +import { BadgeCheckIcon, XIcon } from "lucide-solid"; import { Component, createSignal, Setter } from "solid-js"; export type PlaylistCreateBoxProps = { @@ -14,13 +15,21 @@ const PlaylistCreateBox: Component = (props) => { const createPlaylist = () => { // last check is probably unnecessary - if (playlistName().length === 0 || playlistName() === undefined || playlistName() === "") { + const name = playlistName().trim(); + if (name.length === 0 || name === undefined || name === "") { return; } - window.api.request("playlist::create", playlistName().trim()); + window.api.request("playlist::create", name); setPlaylistName(""); props.reset.pulse(); props.isOpen(false); + + addNotice({ + title: "Playlist created", + description: "The playlist " + name + " has been successfully created!", + variant: "success", + icon: , + }); }; return ( diff --git a/src/renderer/src/components/playlist/playlist-item/playlist-item.utils.ts b/src/renderer/src/components/playlist/playlist-item/playlist-item.utils.ts index a654ee7c..2f0963f8 100644 --- a/src/renderer/src/components/playlist/playlist-item/playlist-item.utils.ts +++ b/src/renderer/src/components/playlist/playlist-item/playlist-item.utils.ts @@ -1,5 +1,7 @@ +import { addNotice } from "@renderer/components/notice/NoticeContainer"; import { PlaylistItemProps } from "./PlaylistItem"; import { Playlist } from "src/@types"; +import { BadgeCheckIcon } from "lucide-solid"; export function getSongImage(playlist: Playlist) { const songs = playlist.songs; @@ -14,6 +16,12 @@ export function deletePlaylist(e: Event, props: PlaylistItemProps) { e.stopPropagation(); window.api.request("playlist::delete", props.playlist.name); props.reset.pulse(); + addNotice({ + variant: "success", + title: "Playlist deleted", + description: "Playlist " + props.playlist.name + " successfully deleted!", + icon: BadgeCheckIcon({ size: 20 }), + }); } // function formatPlaylistTime(seconds: number) { @@ -35,5 +43,11 @@ export const renamePlaylist = async (oldName: string, newName: string) => { } await window.api.request("playlist::rename", oldName, newName); + addNotice({ + title: "Renamed playlist", + description: "Playlist renamed successfully!", + variant: "success", + icon: BadgeCheckIcon({ size: 20 }), + }); // reset.pulse(); }; diff --git a/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx b/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx index 991aadb4..f6c15e5d 100644 --- a/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx +++ b/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx @@ -1,6 +1,8 @@ +import { addNotice } from "@renderer/components/notice/NoticeContainer"; import { Song } from "../../../../../../@types"; import SongContextMenuItem from "../SongContextMenuItem"; import { Component, createSignal, Show } from "solid-js"; +import { BadgeCheckIcon } from "lucide-solid"; type SongAddToPlaylistNextProps = { song: Song; @@ -17,13 +19,19 @@ const AddToPlaylist: Component = (props) => { setShow(false); }); + const addToPlaylist = () => { + window.api.request("playlist::add", "test", props.song); + addNotice({ + title: "Song added", + description: "Successfully added song to playlist!", + variant: "success", + icon: , + }); + }; + return ( - window.api.request("playlist::add", "PlaylistOne", props.song)} - > - Add to Playlist - + addToPlaylist()}>Add to Playlist ); }; diff --git a/src/renderer/src/components/song/song-detail/SongControls.tsx b/src/renderer/src/components/song/song-detail/SongControls.tsx index e845a87f..6f3d3049 100644 --- a/src/renderer/src/components/song/song-detail/SongControls.tsx +++ b/src/renderer/src/components/song/song-detail/SongControls.tsx @@ -10,8 +10,10 @@ import { handleMuteSong, } from "../song.utils"; import Button from "@renderer/components/button/Button"; +import { addNotice } from "@renderer/components/notice/NoticeContainer"; import Slider from "@renderer/components/slider/Slider"; import { + BadgeCheckIcon, CirclePlusIcon, PauseIcon, PlayIcon, @@ -165,7 +167,15 @@ const RightPart = () => { From 0235278d4ad49a91785e806caf703a436fc05f2f Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Thu, 24 Oct 2024 19:31:45 +0200 Subject: [PATCH 34/54] playlist router returns Result, show error messages --- src/RequestAPI.d.ts | 8 ++--- src/main/router/playlist-router.ts | 31 +++++++++++++++---- .../playlist-create/PlaylistCreateBox.tsx | 21 ++++++++----- .../playlist-item/playlist-item.utils.ts | 8 ++++- .../playlist-song-list/PlaylistSongList.tsx | 7 ++++- .../src/components/playlist/playlist.utils.ts | 11 +++++++ .../song/context-menu/items/AddToPlaylist.tsx | 9 ++++-- .../song/song-detail/SongControls.tsx | 9 ++++-- 8 files changed, 81 insertions(+), 23 deletions(-) create mode 100644 src/renderer/src/components/playlist/playlist.utils.ts diff --git a/src/RequestAPI.d.ts b/src/RequestAPI.d.ts index 75afad62..f0ec0383 100644 --- a/src/RequestAPI.d.ts +++ b/src/RequestAPI.d.ts @@ -40,11 +40,11 @@ export type RequestAPI = { "queue::create": (payload: QueueCreatePayload) => void; "queue::shuffle": () => void; - "playlist::add": (playlistName: string, song: Song) => void; - "playlist::remove": (playlistName: string, song: Song) => void; - "playlist::create": (name: string) => void; + "playlist::add": (playlistName: string, song: Song) => Result; + "playlist::remove": (playlistName: string, song: Song) => Result; + "playlist::create": (name: string) => Result; "playlist::delete": (name: string) => void; - "playlist::rename": (oldName: string, newName: string) => void; + "playlist::rename": (oldName: string, newName: string) => Result; "dir::select": () => Optional; "dir::autoGetOsuDir": () => Optional; diff --git a/src/main/router/playlist-router.ts b/src/main/router/playlist-router.ts index 270026ac..fd72a25b 100644 --- a/src/main/router/playlist-router.ts +++ b/src/main/router/playlist-router.ts @@ -1,6 +1,7 @@ import { Playlist } from "../../@types"; import { Router } from "../lib/route-pass/Router"; import { none, some } from "../lib/rust-like-utils-backend/Optional"; +import { fail, ok } from "../lib/rust-like-utils-backend/Result"; import { Storage } from "../lib/storage/Storage"; import errorIgnored from "../lib/tungsten/errorIgnored"; import { mainWindow } from "../main"; @@ -12,7 +13,7 @@ Router.respond("playlist::add", async (_evt, playlistName, song) => { const playlist = playlists.get(playlistName); if (playlist.isNone) { - return; + return fail("Playlist does not exist"); } playlist.value.songs.push(song); @@ -21,14 +22,23 @@ Router.respond("playlist::add", async (_evt, playlistName, song) => { playlists.write(playlistName, playlist.value); await Router.dispatch(mainWindow, "playlist::resetList").catch(errorIgnored); await Router.dispatch(mainWindow, "playlist::resetSongList").catch(errorIgnored); + + return ok({}); }); Router.respond("playlist::create", (_evt, name) => { - console.log("create playlist " + name); - //todo: check if playlist already exists + // console.log("create playlist " + name); const playlists = Storage.getTable("playlists"); + const playlistNames = Object.keys(playlists.getStruct()); + + if (playlistNames.includes(name)) { + return fail("Playlist already exists"); + } + const empty = { name: name, count: 0, length: 0, songs: [] }; playlists.write(name, empty); + + return ok({}); }); Router.respond("playlist::delete", (_evt, name) => { @@ -43,7 +53,7 @@ Router.respond("playlist::remove", async (_evt, playlistName, song) => { const playlist = playlists.get(playlistName); if (playlist.isNone) { - return; + return fail("Playlist does not exist"); } // i assume that audio is the primary key @@ -55,7 +65,9 @@ Router.respond("playlist::remove", async (_evt, playlistName, song) => { playlist.value.length = playlist.value.length - song.duration; playlists.write(playlistName, playlist.value); await Router.dispatch(mainWindow, "playlist::resetSongList").catch(errorIgnored); + return ok({}); } + return fail("Song not found in playlist"); }); Router.respond("playlist::rename", (_evt, oldName, newName) => { @@ -64,13 +76,20 @@ Router.respond("playlist::rename", (_evt, oldName, newName) => { const oldPlaylist = playlists.get(oldName); if (oldPlaylist.isNone) { - return; + return fail("Playlist does not exist"); + } + + const playlistNames = Object.keys(playlists.getStruct()); + + if (playlistNames.includes(newName)) { + return fail("Playlist already exists"); } oldPlaylist.value.name = newName; - //todo: check if the new name is already used playlists.write(newName, oldPlaylist.value); playlists.delete(oldName); + + return ok({}); }); Router.respond("query::playlists::init", () => { diff --git a/src/renderer/src/components/playlist/playlist-create/PlaylistCreateBox.tsx b/src/renderer/src/components/playlist/playlist-create/PlaylistCreateBox.tsx index 3fde7b39..9ae6c287 100644 --- a/src/renderer/src/components/playlist/playlist-create/PlaylistCreateBox.tsx +++ b/src/renderer/src/components/playlist/playlist-create/PlaylistCreateBox.tsx @@ -2,8 +2,9 @@ import Button from "@renderer/components/button/Button"; import { addNotice } from "@renderer/components/notice/NoticeContainer"; import SongImage from "@renderer/components/song/SongImage"; import Impulse from "@renderer/lib/Impulse"; -import { BadgeCheckIcon, XIcon } from "lucide-solid"; +import { CircleCheckIcon, XIcon } from "lucide-solid"; import { Component, createSignal, Setter } from "solid-js"; +import { noticeError } from "../playlist.utils"; export type PlaylistCreateBoxProps = { group: string; @@ -13,13 +14,18 @@ export type PlaylistCreateBoxProps = { const PlaylistCreateBox: Component = (props) => { const [playlistName, setPlaylistName] = createSignal(""); - const createPlaylist = () => { + const createPlaylist = async () => { // last check is probably unnecessary const name = playlistName().trim(); if (name.length === 0 || name === undefined || name === "") { return; } - window.api.request("playlist::create", name); + const result = await window.api.request("playlist::create", name); + if (result.isError) { + noticeError(result.error); + return; + } + setPlaylistName(""); props.reset.pulse(); props.isOpen(false); @@ -28,7 +34,7 @@ const PlaylistCreateBox: Component = (props) => { title: "Playlist created", description: "The playlist " + name + " has been successfully created!", variant: "success", - icon: , + icon: , }); }; @@ -58,12 +64,13 @@ const PlaylistCreateBox: Component = (props) => { setPlaylistName(e.target.value); }} /> - +
diff --git a/src/renderer/src/components/playlist/playlist-item/playlist-item.utils.ts b/src/renderer/src/components/playlist/playlist-item/playlist-item.utils.ts index 2f0963f8..cebae7ff 100644 --- a/src/renderer/src/components/playlist/playlist-item/playlist-item.utils.ts +++ b/src/renderer/src/components/playlist/playlist-item/playlist-item.utils.ts @@ -2,6 +2,7 @@ import { addNotice } from "@renderer/components/notice/NoticeContainer"; import { PlaylistItemProps } from "./PlaylistItem"; import { Playlist } from "src/@types"; import { BadgeCheckIcon } from "lucide-solid"; +import { noticeError } from "../playlist.utils"; export function getSongImage(playlist: Playlist) { const songs = playlist.songs; @@ -42,7 +43,12 @@ export const renamePlaylist = async (oldName: string, newName: string) => { return; } - await window.api.request("playlist::rename", oldName, newName); + const result = await window.api.request("playlist::rename", oldName, newName); + if (result.isError) { + noticeError(result.error); + return; + } + addNotice({ title: "Renamed playlist", description: "Playlist renamed successfully!", diff --git a/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx b/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx index ebd70028..1df0135c 100644 --- a/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx +++ b/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx @@ -7,6 +7,7 @@ import Impulse from "@renderer/lib/Impulse"; import { ArrowLeftIcon, PencilIcon, Trash2Icon } from "lucide-solid"; import { Component, createSignal, Match, onCleanup, onMount, Switch } from "solid-js"; import { PlaylistSongsQueryPayload, ResourceID, Song } from "src/@types"; +import { noticeError } from "../playlist.utils"; type PlaylistSongListProps = { playlistName: string; @@ -44,7 +45,11 @@ const PlaylistSongList: Component = (props) => { }; const deleteSong = async (playlistName: string, song: Song) => { - await window.api.request("playlist::remove", playlistName, song); + const result = await window.api.request("playlist::remove", playlistName, song); + if (result.isError) { + noticeError(result.error); + return; + } }; // const renamePlaylist = async (newName: string) => { diff --git a/src/renderer/src/components/playlist/playlist.utils.ts b/src/renderer/src/components/playlist/playlist.utils.ts new file mode 100644 index 00000000..e29dd787 --- /dev/null +++ b/src/renderer/src/components/playlist/playlist.utils.ts @@ -0,0 +1,11 @@ +import { CircleXIcon } from "lucide-solid"; +import { addNotice } from "../notice/NoticeContainer"; + +export function noticeError(error: string) { + addNotice({ + title: "Error", + description: error, + variant: "error", + icon: CircleXIcon({ size: 20 }), + }); +} diff --git a/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx b/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx index f6c15e5d..7d45a61c 100644 --- a/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx +++ b/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx @@ -3,6 +3,7 @@ import { Song } from "../../../../../../@types"; import SongContextMenuItem from "../SongContextMenuItem"; import { Component, createSignal, Show } from "solid-js"; import { BadgeCheckIcon } from "lucide-solid"; +import { noticeError } from "@renderer/components/playlist/playlist.utils"; type SongAddToPlaylistNextProps = { song: Song; @@ -19,8 +20,12 @@ const AddToPlaylist: Component = (props) => { setShow(false); }); - const addToPlaylist = () => { - window.api.request("playlist::add", "test", props.song); + const addToPlaylist = async () => { + const result = await window.api.request("playlist::add", "test", props.song); + if (result.isError) { + noticeError(result.error); + return; + } addNotice({ title: "Song added", description: "Successfully added song to playlist!", diff --git a/src/renderer/src/components/song/song-detail/SongControls.tsx b/src/renderer/src/components/song/song-detail/SongControls.tsx index 6f3d3049..1322639f 100644 --- a/src/renderer/src/components/song/song-detail/SongControls.tsx +++ b/src/renderer/src/components/song/song-detail/SongControls.tsx @@ -11,6 +11,7 @@ import { } from "../song.utils"; import Button from "@renderer/components/button/Button"; import { addNotice } from "@renderer/components/notice/NoticeContainer"; +import { noticeError } from "@renderer/components/playlist/playlist.utils"; import Slider from "@renderer/components/slider/Slider"; import { BadgeCheckIcon, @@ -167,8 +168,12 @@ const RightPart = () => { - -
-
- ); -}; - -export default ContextMenuBox; diff --git a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx index 10267ea0..cc38bf19 100644 --- a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx +++ b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx @@ -4,13 +4,20 @@ import { setActivePlaylistName, setPlaylistActiveScene, } from "../playlist-view/playlist-view.utils"; -import ContextMenuBox from "./ContextMenuBox"; import { getSongImage, renamePlaylist } from "./playlist-item.utils"; -import Button from "@renderer/components/button/Button"; +import Popover from "@renderer/components/popover/Popover"; +import SongContextMenu, { + ignoreClickInContextMenu, +} from "@renderer/components/song/context-menu/SongContextMenu"; import Impulse from "@renderer/lib/Impulse"; import { EllipsisVerticalIcon } from "lucide-solid"; -import { Component, createSignal, Match, Show, Switch } from "solid-js"; +import { Component, createSignal, Match, onMount, Switch } from "solid-js"; +import { Portal } from "solid-js/web"; import { Playlist } from "src/@types"; +import { twMerge } from "tailwind-merge"; +import DeletePlaylist from "../context-menu-items/DeletePlaylist"; +import RenamePlaylist from "../context-menu-items/RenamePlaylist"; +import draggable from "@renderer/lib/draggable/draggable"; export type PlaylistItemProps = { playlist: Playlist; @@ -19,81 +26,110 @@ export type PlaylistItemProps = { }; const PlaylistItem: Component = (props) => { - const [showBox, setShowBox] = createSignal(false); + let item: HTMLDivElement | undefined; + const [playlistName, setPlaylistName] = createSignal(""); const [editMode, setEditMode] = createSignal(false); + const [localShow, setLocalShow] = createSignal(false); + const [mousePos, setMousePos] = createSignal<[number, number]>([0, 0]); - return ( -
{ + onMount(() => { + if (!item) return; + + draggable(item, { + onClick: ignoreClickInContextMenu(() => { if (!editMode()) { setActivePlaylistName(props.playlist.name); setPlaylistActiveScene(PLAYLIST_SCENE_SONGS); } - }} - class="" - > -
-
- -
+ }), + onDrop: () => {}, + useOnlyAsOnClickBinder: true, + }); + }); -
-
- {/*

{props.playlist.name}

*/} - - - { - setPlaylistName(e.target.value); - }} - onKeyPress={async (e) => { - if (e.key == "Enter") { - await renamePlaylist(props.playlist.name, playlistName()); - setEditMode(false); - props.reset.pulse(); - } - }} - /> - - -

{props.playlist.name}

-
-
-

{props.playlist.count} songs

- {/*

{formatPlaylistTime(Math.round(props.playlist.length))}

*/} + return ( + + + + { + e.stopImmediatePropagation(); + setLocalShow(false); + }} + > + {/* can't pass this as a prop like in song-item because i need the editMode signal */} + + + + + + +
{ + e.preventDefault(); + setMousePos([e.clientX, e.clientY]); + setLocalShow(true); + }} + class="group" + ref={item} + > +
+
+
- -
-
- - - +
+
+ + + { + setPlaylistName(e.target.value); + }} + onKeyPress={async (e) => { + if (e.key == "Enter") { + await renamePlaylist(props.playlist.name, playlistName()); + setEditMode(false); + props.reset.pulse(); + } + }} + /> + + +

{props.playlist.name}

+
+
+

{props.playlist.count} songs

+
+ + + +
-
+ ); }; diff --git a/src/renderer/src/components/playlist/playlist-item/playlist-item.utils.ts b/src/renderer/src/components/playlist/playlist-item/playlist-item.utils.ts index cebae7ff..60ba687f 100644 --- a/src/renderer/src/components/playlist/playlist-item/playlist-item.utils.ts +++ b/src/renderer/src/components/playlist/playlist-item/playlist-item.utils.ts @@ -1,8 +1,8 @@ import { addNotice } from "@renderer/components/notice/NoticeContainer"; -import { PlaylistItemProps } from "./PlaylistItem"; import { Playlist } from "src/@types"; import { BadgeCheckIcon } from "lucide-solid"; import { noticeError } from "../playlist.utils"; +import Impulse from "@renderer/lib/Impulse"; export function getSongImage(playlist: Playlist) { const songs = playlist.songs; @@ -13,30 +13,17 @@ export function getSongImage(playlist: Playlist) { } } -export function deletePlaylist(e: Event, props: PlaylistItemProps) { - e.stopPropagation(); - window.api.request("playlist::delete", props.playlist.name); - props.reset.pulse(); +export function deletePlaylist(name: string, reset: Impulse) { + window.api.request("playlist::delete", name); + reset.pulse(); addNotice({ variant: "success", title: "Playlist deleted", - description: "Playlist " + props.playlist.name + " successfully deleted!", + description: "Playlist " + name + " successfully deleted!", icon: BadgeCheckIcon({ size: 20 }), }); } -// function formatPlaylistTime(seconds: number) { -// let minutes = 0; -// let hours = 0; -// if (seconds > 60) { -// minutes = Math.floor(seconds / 60); -// if (minutes > 60) { -// hours = Math.floor(minutes / 60); -// } -// } - -// return hours + " hours " + minutes + " minutes"; -// } export const renamePlaylist = async (oldName: string, newName: string) => { newName = newName.trim(); if (newName === undefined || newName === "" || newName === oldName) { @@ -55,5 +42,4 @@ export const renamePlaylist = async (oldName: string, newName: string) => { variant: "success", icon: BadgeCheckIcon({ size: 20 }), }); - // reset.pulse(); }; diff --git a/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx b/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx index 1df0135c..85fd0d41 100644 --- a/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx +++ b/src/renderer/src/components/playlist/playlist-song-list/PlaylistSongList.tsx @@ -5,32 +5,31 @@ import { namespace } from "@renderer/App"; import Button from "@renderer/components/button/Button"; import Impulse from "@renderer/lib/Impulse"; import { ArrowLeftIcon, PencilIcon, Trash2Icon } from "lucide-solid"; -import { Component, createSignal, Match, onCleanup, onMount, Switch } from "solid-js"; +import { Component, createSignal, onCleanup, onMount, Show } from "solid-js"; import { PlaylistSongsQueryPayload, ResourceID, Song } from "src/@types"; import { noticeError } from "../playlist.utils"; +import SongContextMenu from "@renderer/components/song/context-menu/SongContextMenu"; +import PlayNext from "@renderer/components/song/context-menu/items/PlayNext"; +import AddToPlaylist from "@renderer/components/song/context-menu/items/AddToPlaylist"; type PlaylistSongListProps = { playlistName: string; }; -// let localPlaylistName: string; - const PlaylistSongList: Component = (props) => { const group = namespace.create(true); - // const [playlistName, setPlaylistName] = createSignal(""); const [payload] = createSignal({ playlistName: props.playlistName, }); const [editMode, setEditMode] = createSignal(false); + const [isQueueExist, setIsQueueExist] = createSignal(false); const reset = new Impulse(); onMount(() => { window.api.listen("playlist::resetSongList", reset.pulse.bind(reset)); - // localPlaylistName = props.playlistName; - // setPayload({ playlistName: localPlaylistName }); }); onCleanup(() => window.api.removeListener("playlist::resetSongList", reset.pulse.bind(reset))); @@ -42,6 +41,7 @@ const PlaylistSongList: Component = (props) => { tags: [], view: { playlist: props.playlistName }, }); + setIsQueueExist(true); }; const deleteSong = async (playlistName: string, song: Song) => { @@ -52,18 +52,6 @@ const PlaylistSongList: Component = (props) => { } }; - // const renamePlaylist = async (newName: string) => { - // newName = newName.trim(); - // if (newName === undefined || newName === "" || newName === localPlaylistName) { - // return; - // } - - // await window.api.request("playlist::rename", localPlaylistName, newName); - // localPlaylistName = newName; - // setPayload({ playlistName: localPlaylistName }); - // reset.pulse(); - // }; - return (
@@ -75,22 +63,6 @@ const PlaylistSongList: Component = (props) => { > - {/* - - { - setPlaylistName(e.target.value); - }} - /> - - -

{localPlaylistName}

-
-
*/}

{props.playlistName}

- - + + +
)} /> diff --git a/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx b/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx index 7d45a61c..d9af6d32 100644 --- a/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx +++ b/src/renderer/src/components/song/context-menu/items/AddToPlaylist.tsx @@ -1,25 +1,15 @@ import { addNotice } from "@renderer/components/notice/NoticeContainer"; import { Song } from "../../../../../../@types"; import SongContextMenuItem from "../SongContextMenuItem"; -import { Component, createSignal, Show } from "solid-js"; -import { BadgeCheckIcon } from "lucide-solid"; +import { Component } from "solid-js"; +import { BadgeCheckIcon, PlusIcon } from "lucide-solid"; import { noticeError } from "@renderer/components/playlist/playlist.utils"; -type SongAddToPlaylistNextProps = { +type AddToPlaylistProps = { song: Song; }; -const AddToPlaylist: Component = (props) => { - const [show, setShow] = createSignal(false); - - window.api.listen("queue::created", () => { - setShow(true); - }); - - window.api.listen("queue::destroyed", () => { - setShow(false); - }); - +const AddToPlaylist: Component = (props) => { const addToPlaylist = async () => { const result = await window.api.request("playlist::add", "test", props.song); if (result.isError) { @@ -35,9 +25,14 @@ const AddToPlaylist: Component = (props) => { }; return ( - - addToPlaylist()}>Add to Playlist - + { + addToPlaylist(); + }} + > +

Add to Playlist

+ +
); }; diff --git a/src/renderer/src/components/song/song-item/SongItem.tsx b/src/renderer/src/components/song/song-item/SongItem.tsx index 403998dc..7e74d47a 100644 --- a/src/renderer/src/components/song/song-item/SongItem.tsx +++ b/src/renderer/src/components/song/song-item/SongItem.tsx @@ -96,7 +96,7 @@ const SongItem: Component = (props) => {
= (props) => { contextMenu={ - + } > diff --git a/src/renderer/src/components/song/song-queue/SongQueue.tsx b/src/renderer/src/components/song/song-queue/SongQueue.tsx index ef9a83d8..2a7b7aa6 100644 --- a/src/renderer/src/components/song/song-queue/SongQueue.tsx +++ b/src/renderer/src/components/song/song-queue/SongQueue.tsx @@ -110,7 +110,7 @@ const SongQueue: Component = () => { onDrop={onDrop(s)} contextMenu={ - + } From 4552ed9b20559a631d629fbe01c96f6c604f9cc1 Mon Sep 17 00:00:00 2001 From: D0m1nos <21263344+D0m1nos@users.noreply.github.com> Date: Fri, 25 Oct 2024 22:11:11 +0200 Subject: [PATCH 36/54] add remove song from playlist button, cleaned code --- src/main/router/playlist-router.ts | 4 -- .../context-menu-items/DeletePlaylist.tsx | 6 +-- .../context-menu-items/RemoveFromPlaylist.tsx | 26 +++++++++ .../playlist/playlist-item/PlaylistItem.tsx | 5 +- .../playlist-item/playlist-item.utils.ts | 35 ------------ .../playlist/playlist-list/PlaylistList.tsx | 12 ----- .../playlist-song-list/PlaylistSongList.tsx | 21 +++----- .../playlist/playlist-view/PlaylistView.tsx | 2 +- .../playlist-view/playlist-view.utils.ts | 10 ---- .../src/components/playlist/playlist.utils.ts | 53 ++++++++++++++++++- 10 files changed, 91 insertions(+), 83 deletions(-) create mode 100644 src/renderer/src/components/playlist/context-menu-items/RemoveFromPlaylist.tsx delete mode 100644 src/renderer/src/components/playlist/playlist-view/playlist-view.utils.ts diff --git a/src/main/router/playlist-router.ts b/src/main/router/playlist-router.ts index fd72a25b..b763ce7d 100644 --- a/src/main/router/playlist-router.ts +++ b/src/main/router/playlist-router.ts @@ -27,7 +27,6 @@ Router.respond("playlist::add", async (_evt, playlistName, song) => { }); Router.respond("playlist::create", (_evt, name) => { - // console.log("create playlist " + name); const playlists = Storage.getTable("playlists"); const playlistNames = Object.keys(playlists.getStruct()); @@ -42,13 +41,11 @@ Router.respond("playlist::create", (_evt, name) => { }); Router.respond("playlist::delete", (_evt, name) => { - console.log("delete playlist " + name); const playlists = Storage.getTable("playlists"); playlists.delete(name); }); Router.respond("playlist::remove", async (_evt, playlistName, song) => { - console.log("delete " + song.title + " from " + playlistName); const playlists = Storage.getTable("playlists"); const playlist = playlists.get(playlistName); @@ -71,7 +68,6 @@ Router.respond("playlist::remove", async (_evt, playlistName, song) => { }); Router.respond("playlist::rename", (_evt, oldName, newName) => { - console.log("rename from " + oldName + " to " + newName); const playlists = Storage.getTable("playlists"); const oldPlaylist = playlists.get(oldName); diff --git a/src/renderer/src/components/playlist/context-menu-items/DeletePlaylist.tsx b/src/renderer/src/components/playlist/context-menu-items/DeletePlaylist.tsx index 427e8774..7f545fac 100644 --- a/src/renderer/src/components/playlist/context-menu-items/DeletePlaylist.tsx +++ b/src/renderer/src/components/playlist/context-menu-items/DeletePlaylist.tsx @@ -1,8 +1,8 @@ import SongContextMenuItem from "@renderer/components/song/context-menu/SongContextMenuItem"; -import { DeleteIcon } from "lucide-solid"; +import { ListXIcon } from "lucide-solid"; import { Component } from "solid-js"; -import { deletePlaylist } from "../playlist-item/playlist-item.utils"; import Impulse from "@renderer/lib/Impulse"; +import { deletePlaylist } from "../playlist.utils"; type DeletePlaylistProps = { name: string; @@ -18,7 +18,7 @@ const DeletePlaylist: Component = (props) => { class="hover:bg-red/20" >

Delete playlist

- + ); }; diff --git a/src/renderer/src/components/playlist/context-menu-items/RemoveFromPlaylist.tsx b/src/renderer/src/components/playlist/context-menu-items/RemoveFromPlaylist.tsx new file mode 100644 index 00000000..459ef9c4 --- /dev/null +++ b/src/renderer/src/components/playlist/context-menu-items/RemoveFromPlaylist.tsx @@ -0,0 +1,26 @@ +import SongContextMenuItem from "@renderer/components/song/context-menu/SongContextMenuItem"; +import { DeleteIcon } from "lucide-solid"; +import { Component } from "solid-js"; +import { Song } from "src/@types"; +import { deleteSong } from "../playlist.utils"; + +type RemoveFromPlaylistProps = { + playlistName: string; + song: Song; +}; + +const RemoveFromPlaylist: Component = (props) => { + return ( + { + await deleteSong(props.playlistName, props.song); + }} + class="hover:bg-red/20" + > +

Remove song

+ +
+ ); +}; + +export default RemoveFromPlaylist; diff --git a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx index cc38bf19..1d58a84e 100644 --- a/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx +++ b/src/renderer/src/components/playlist/playlist-item/PlaylistItem.tsx @@ -3,8 +3,8 @@ import { PLAYLIST_SCENE_SONGS, setActivePlaylistName, setPlaylistActiveScene, -} from "../playlist-view/playlist-view.utils"; -import { getSongImage, renamePlaylist } from "./playlist-item.utils"; +} from "../playlist.utils"; +import { getSongImage } from "./playlist-item.utils"; import Popover from "@renderer/components/popover/Popover"; import SongContextMenu, { ignoreClickInContextMenu, @@ -18,6 +18,7 @@ import { twMerge } from "tailwind-merge"; import DeletePlaylist from "../context-menu-items/DeletePlaylist"; import RenamePlaylist from "../context-menu-items/RenamePlaylist"; import draggable from "@renderer/lib/draggable/draggable"; +import { renamePlaylist } from "../playlist.utils"; export type PlaylistItemProps = { playlist: Playlist; diff --git a/src/renderer/src/components/playlist/playlist-item/playlist-item.utils.ts b/src/renderer/src/components/playlist/playlist-item/playlist-item.utils.ts index 60ba687f..9094339f 100644 --- a/src/renderer/src/components/playlist/playlist-item/playlist-item.utils.ts +++ b/src/renderer/src/components/playlist/playlist-item/playlist-item.utils.ts @@ -1,8 +1,4 @@ -import { addNotice } from "@renderer/components/notice/NoticeContainer"; import { Playlist } from "src/@types"; -import { BadgeCheckIcon } from "lucide-solid"; -import { noticeError } from "../playlist.utils"; -import Impulse from "@renderer/lib/Impulse"; export function getSongImage(playlist: Playlist) { const songs = playlist.songs; @@ -12,34 +8,3 @@ export function getSongImage(playlist: Playlist) { return songs[0].bg; } } - -export function deletePlaylist(name: string, reset: Impulse) { - window.api.request("playlist::delete", name); - reset.pulse(); - addNotice({ - variant: "success", - title: "Playlist deleted", - description: "Playlist " + name + " successfully deleted!", - icon: BadgeCheckIcon({ size: 20 }), - }); -} - -export const renamePlaylist = async (oldName: string, newName: string) => { - newName = newName.trim(); - if (newName === undefined || newName === "" || newName === oldName) { - return; - } - - const result = await window.api.request("playlist::rename", oldName, newName); - if (result.isError) { - noticeError(result.error); - return; - } - - addNotice({ - title: "Renamed playlist", - description: "Playlist renamed successfully!", - variant: "success", - icon: BadgeCheckIcon({ size: 20 }), - }); -}; diff --git a/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx b/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx index 6ab95177..cd8ae49b 100644 --- a/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx +++ b/src/renderer/src/components/playlist/playlist-list/PlaylistList.tsx @@ -9,7 +9,6 @@ import { Component, createSignal, onCleanup, onMount, Show } from "solid-js"; import { twMerge } from "tailwind-merge"; const PlaylistList: Component = () => { - // const [playlistSearch, setPlaylistSearch] = createSignal(""); const [, setCount] = createSignal(0); const resetListing = new Impulse(); const [showCreateBox, setShowCreateBox] = createSignal(false); @@ -23,14 +22,6 @@ const PlaylistList: Component = () => { return (
- {/* - */}
@@ -39,9 +30,6 @@ const PlaylistList: Component = () => { type="text" id="search_input" placeholder="Search in your playlists... (WIP)" - // onInput={(e) => { - // setPlaylistSearch(e.target.value); - // }} />