-
+
+
- handleSearchTerm(e.target.value)}
- value={searchTerm}
- />
-
-
-
-
-
-
-
-
+
);
diff --git a/src/renderer/features/now-playing/components/play-queue.tsx b/src/renderer/features/now-playing/components/play-queue.tsx
index 880100031..b8bcf9ca6 100644
--- a/src/renderer/features/now-playing/components/play-queue.tsx
+++ b/src/renderer/features/now-playing/components/play-queue.tsx
@@ -1,51 +1,25 @@
-import type { RowClassRules, RowDragEvent, RowNode } from '@ag-grid-community/core';
-import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
import type { Ref } from 'react';
-import '@ag-grid-community/styles/ag-theme-alpine.css';
-import { useMergedRef } from '@mantine/hooks';
-import debounce from 'lodash/debounce';
-import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
-import { ErrorBoundary } from 'react-error-boundary';
+import { forwardRef, useMemo } from 'react';
-import { getColumnDefs, VirtualTable } from '/@/renderer/components/virtual-table';
-import { ErrorFallback } from '/@/renderer/features/action-required/components/error-fallback';
-import { QUEUE_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/context-menu-items';
-import { useHandleTableContextMenu } from '/@/renderer/features/context-menu/hooks/use-handle-context-menu';
-import { useAppFocus } from '/@/renderer/hooks';
-import {
- useAppStoreActions,
- usePlayerQueue,
- usePlayerSong,
- usePlayerStatus,
-} from '/@/renderer/store';
-import {
- useSettingsStore,
- useSettingsStoreActions,
- useTableSettings,
-} from '/@/renderer/store/settings.store';
+import { ItemTableList } from '/@/renderer/components/item-list/item-table-list/item-table-list';
+import { ItemTableListColumn } from '/@/renderer/components/item-list/item-table-list/item-table-list-column';
+import { useListSettings, usePlayerQueue } from '/@/renderer/store';
import { searchSongs } from '/@/renderer/utils/search-songs';
import { LibraryItem, QueueSong } from '/@/shared/types/domain-types';
import { ItemListKey } from '/@/shared/types/types';
type QueueProps = {
- type: ItemListKey;
+ listKey: ItemListKey;
+ searchTerm: string | undefined;
};
-export const PlayQueue = forwardRef(({ searchTerm, type }: QueueProps, ref: Ref) => {
- const tableRef = useRef(null);
- const mergedRef = useMergedRef(ref, tableRef);
- const queue = usePlayerQueue();
- const currentSong = usePlayerSong();
- const status = usePlayerStatus();
- const { setSettings } = useSettingsStoreActions();
- const { setAppStore } = useAppStoreActions();
- const tableConfig = useTableSettings(type);
- const [gridApi, setGridApi] = useState();
- const isFocused = useAppFocus();
- const isFocusedRef = useRef(isFocused);
+export const PlayQueue = forwardRef(({ listKey, searchTerm }: QueueProps, ref: Ref) => {
+ const { table } = useListSettings(listKey);
- const songs = useMemo(() => {
+ const queue = usePlayerQueue();
+
+ const data: QueueSong[] = useMemo(() => {
if (searchTerm) {
return searchSongs(queue, searchTerm);
}
@@ -53,230 +27,21 @@ export const PlayQueue = forwardRef(({ searchTerm, type }: QueueProps, ref: Ref<
return queue;
}, [queue, searchTerm]);
- useEffect(() => {
- if (tableRef.current) {
- setGridApi(tableRef.current);
- }
- }, []);
-
- useImperativeHandle(ref, () => ({
- get grid() {
- return gridApi;
- },
- }));
-
- const columnDefs = useMemo(
- () => getColumnDefs(tableConfig.columns, false, 'generic'),
- [tableConfig.columns],
- );
-
- // const handleDoubleClick = (e: CellDoubleClickedEvent) => {
- // const playerData = setCurrentTrack(e.data.uniqueId);
- // updateSong(playerData.current.song);
-
- // if (playbackType === PlaybackType.LOCAL) {
- // mpvPlayer!.volume(volume);
- // setQueue(playerData, false);
- // } else {
- // const player =
- // playerData.current.player === 1
- // ? PlayersRef.current?.player1
- // : PlayersRef.current?.player2;
- // const underlying = player?.getInternalPlayer();
- // if (underlying) {
- // underlying.currentTime = 0;
- // }
- // }
-
- // play();
- // };
-
- const handleDragStart = () => {
- if (type === 'sideDrawerQueue') {
- setAppStore({ isReorderingQueue: true });
- }
- };
-
- let timeout: any;
- const handleDragEnd = (e: RowDragEvent) => {
- if (!e.nodes.length) return;
- const selectedUniqueIds = e.nodes
- .map((node) => node.data?._uniqueId)
- .filter((e) => e !== undefined);
-
- // const playerData = reorderQueue(selectedUniqueIds as string[], e.overNode?.data?.uniqueId);
-
- // if (playbackType === PlaybackType.LOCAL) {
- // setQueueNext(playerData);
- // }
-
- if (type === 'sideDrawerQueue') {
- setAppStore({ isReorderingQueue: false });
- }
-
- const { api } = tableRef?.current || {};
- clearTimeout(timeout);
- timeout = setTimeout(() => api?.redrawRows(), 250);
- };
-
- const handleGridReady = () => {
- const { api } = tableRef?.current || {};
-
- if (currentSong?._uniqueId) {
- const currentNode = api?.getRowNode(currentSong?._uniqueId);
-
- if (!currentNode) return;
- api?.ensureNodeVisible(currentNode, 'middle');
- }
- };
-
- const handleColumnChange = () => {
- const { columnApi } = tableRef?.current || {};
- const columnsOrder = columnApi?.getAllGridColumns();
- if (!columnsOrder) return;
-
- const columnsInSettings = useSettingsStore.getState().lists[type].columns;
-
- const updatedColumns: PersistedTableColumn[] = [];
- for (const column of columnsOrder) {
- const columnInSettings = columnsInSettings.find(
- (c) => c.column === column.getColDef().colId,
- );
-
- if (columnInSettings) {
- updatedColumns.push({
- ...columnInSettings,
- ...(!useSettingsStore.getState().lists[type].autoFit && {
- width: column.getActualWidth(),
- }),
- });
- }
- }
-
- setSettings({
- lists: {
- ...useSettingsStore.getState().lists,
- [type]: {
- ...useSettingsStore.getState().lists[type],
- columns: updatedColumns,
- },
- },
- });
- };
-
- const debouncedColumnChange = debounce(handleColumnChange, 250);
-
- const handleGridSizeChange = () => {
- if (tableConfig.autoFit) {
- tableRef?.current?.api?.sizeColumnsToFit();
- }
- };
-
- const rowClassRules = useMemo(() => {
- return {
- 'current-song': (params) => {
- return params.data.uniqueId === currentSong?._uniqueId;
- },
- };
- }, [currentSong?._uniqueId]);
-
- const previousSongRef = useRef(undefined);
-
- useEffect(() => {
- if (currentSong) {
- previousSongRef.current = currentSong;
- }
- }, [currentSong]);
-
- // Redraw the current song row when the previous song changes
- useEffect(() => {
- if (tableRef?.current) {
- const { api, columnApi } = tableRef?.current || {};
- if (api == null || columnApi == null) {
- return;
- }
-
- const currentNode = currentSong?._uniqueId
- ? api.getRowNode(currentSong._uniqueId)
- : undefined;
- const previousNode = previousSongRef.current?._uniqueId
- ? api.getRowNode(previousSongRef.current?._uniqueId)
- : undefined;
-
- const rowNodes = [currentNode, previousNode].filter(
- (e) => e !== undefined,
- ) as RowNode[];
-
- if (rowNodes) {
- api.redrawRows({ rowNodes });
- if (tableConfig.followCurrentSong) {
- if (!currentNode) return;
- api.ensureNodeVisible(currentNode, 'middle');
- }
- }
- }
- }, [currentSong, previousSongRef, tableConfig.followCurrentSong, status]);
-
- // As a separate rule, update the current row when focus changes. This is
- // to prevent queue scrolling when the application loses and then gains focus.
- // The body should only fire when focus changes, even though it depends on current song
- useEffect(() => {
- if (isFocused !== isFocusedRef.current && tableRef?.current) {
- const { api, columnApi } = tableRef.current;
- if (api == null || columnApi == null) {
- return;
- }
-
- const currentNode = currentSong?._uniqueId
- ? api.getRowNode(currentSong._uniqueId)
- : undefined;
-
- if (currentNode) {
- api.redrawRows({ rowNodes: [currentNode] });
- }
-
- isFocusedRef.current = isFocused;
- }
- }, [currentSong, isFocused]);
-
- const onCellContextMenu = useHandleTableContextMenu(LibraryItem.SONG, QUEUE_CONTEXT_MENU_ITEMS);
-
return (
-
-
- data.data.uniqueId}
- onCellContextMenu={onCellContextMenu}
- // onCellDoubleClicked={handleDoubleClick}
- onColumnMoved={handleColumnChange}
- onColumnResized={debouncedColumnChange}
- onDragStarted={handleDragStart}
- onGridReady={handleGridReady}
- onGridSizeChanged={handleGridSizeChange}
- onRowDragEnd={handleDragEnd}
- ref={mergedRef}
- rowBuffer={50}
- rowClassRules={rowClassRules}
- rowData={songs}
- rowDragEntireRow
- rowDragMultiRow
- rowHeight={tableConfig.rowHeight || 40}
- suppressCellFocus={type === 'fullScreen'}
- />
-
-
+
);
});
diff --git a/src/renderer/features/now-playing/components/sidebar-play-queue.tsx b/src/renderer/features/now-playing/components/sidebar-play-queue.tsx
index ef7b03a24..8e6cd4144 100644
--- a/src/renderer/features/now-playing/components/sidebar-play-queue.tsx
+++ b/src/renderer/features/now-playing/components/sidebar-play-queue.tsx
@@ -1,17 +1,24 @@
-import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
-
import { useRef, useState } from 'react';
-import { useWindowSettings } from '/@/renderer/store/settings.store';
-import { Song } from '/@/shared/types/domain-types';
-import { Platform } from '/@/shared/types/types';
+import { PlayQueue } from '/@/renderer/features/now-playing/components/play-queue';
+import { PlayQueueListControls } from '/@/renderer/features/now-playing/components/play-queue-list-controls';
+import { Flex } from '/@/shared/components/flex/flex';
+import { ItemListKey } from '/@/shared/types/types';
export const SidebarPlayQueue = () => {
- const queueRef = useRef }>(null);
+ const tableRef = useRef(null);
+ // const queueRef = useRef }>(null);
const [search, setSearch] = useState(undefined);
- const { windowBarStyle } = useWindowSettings();
- const isWeb = windowBarStyle === Platform.WEB;
-
- return null;
+ return (
+
+
+
+
+ );
};
diff --git a/src/renderer/features/player/components/full-screen-player-queue.tsx b/src/renderer/features/player/components/full-screen-player-queue.tsx
index f06e24340..82f84f7d6 100644
--- a/src/renderer/features/player/components/full-screen-player-queue.tsx
+++ b/src/renderer/features/player/components/full-screen-player-queue.tsx
@@ -15,7 +15,7 @@ import {
} from '/@/renderer/store/full-screen-player.store';
import { Button } from '/@/shared/components/button/button';
import { Group } from '/@/shared/components/group/group';
-import { PlayerType } from '/@/shared/types/types';
+import { ItemListKey, PlayerType } from '/@/shared/types/types';
const Visualizer = lazy(() =>
import('/@/renderer/features/player/components/visualizer').then((module) => ({
@@ -99,7 +99,7 @@ export const FullScreenPlayerQueue = () => {
{activeTab === 'queue' ? (
) : activeTab === 'related' ? (
diff --git a/src/renderer/layouts/default-layout/right-sidebar.module.css b/src/renderer/layouts/default-layout/right-sidebar.module.css
index 153ef8f6e..9258643ef 100644
--- a/src/renderer/layouts/default-layout/right-sidebar.module.css
+++ b/src/renderer/layouts/default-layout/right-sidebar.module.css
@@ -1,7 +1,8 @@
.right-sidebar-container {
position: relative;
grid-area: right-sidebar;
- height: 100%;
+ min-height: 0;
+ overflow: hidden;
border-left: 1px solid alpha(var(--theme-colors-border), 0.3);
.current-song-cell:not(.current-playlist-song-cell) svg {
diff --git a/src/renderer/utils/search-songs.ts b/src/renderer/utils/search-songs.ts
index 0ab83a7c8..e0c6a4692 100644
--- a/src/renderer/utils/search-songs.ts
+++ b/src/renderer/utils/search-songs.ts
@@ -1,8 +1,8 @@
import Fuse from 'fuse.js';
-import { Song } from '/@/shared/types/domain-types';
+import { QueueSong } from '/@/shared/types/domain-types';
-export const searchSongs = (songs: Song[], searchTerm: string) => {
+export const searchSongs = (songs: QueueSong[], searchTerm: string) => {
const fuse = new Fuse(songs, {
fieldNormWeight: 1,
ignoreLocation: true,