Refactor player store

This commit is contained in:
jeffvli
2022-12-10 02:49:13 -08:00
parent a7ce902a16
commit 6de5d56f29
13 changed files with 747 additions and 644 deletions
@@ -6,19 +6,20 @@ import type {
RowDragEvent,
} from '@ag-grid-community/core';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import { VirtualGridAutoSizerContainer, VirtualGridContainer, getColumnDefs } from '/@/components';
import {
VirtualGridAutoSizerContainer,
VirtualGridContainer,
getColumnDefs,
TableConfigDropdown,
} from '/@/components';
import { useAppStoreActions, usePlayerStore } from '/@/store';
useAppStoreActions,
useCurrentSong,
useDefaultQueue,
usePreviousSong,
useQueueControls,
} from '/@/store';
import { useSettingsStore } from '/@/store/settings.store';
import type { QueueSong, TableType } from '/@/types';
import { ErrorBoundary } from 'react-error-boundary';
import { mpvPlayer } from '#preload';
import { VirtualTable } from '../../../components/virtual-table';
import { ErrorFallback } from '../../action-required';
import { VirtualTable } from '/@/components/virtual-table';
import { ErrorFallback } from '/@/features/action-required';
type QueueProps = {
type: TableType;
@@ -26,11 +27,10 @@ type QueueProps = {
export const PlayQueue = ({ type }: QueueProps) => {
const gridRef = useRef<any>(null);
const queue = usePlayerStore((state) => state.queue.default);
const reorderQueue = usePlayerStore((state) => state.reorderQueue);
const current = usePlayerStore((state) => state.getQueueData().current);
const previous = usePlayerStore((state) => state.queue.previousNode);
const setCurrentTrack = usePlayerStore((state) => state.setCurrentTrack);
const queue = useDefaultQueue();
const { reorderQueue, setCurrentTrack } = useQueueControls();
const currentSong = useCurrentSong();
const previousSong = usePreviousSong();
const setSettings = useSettingsStore((state) => state.setSettings);
const { setAppStore } = useAppStoreActions();
const tableConfig = useSettingsStore((state) => state.tables[type]);
@@ -77,7 +77,7 @@ export const PlayQueue = ({ type }: QueueProps) => {
const handleGridReady = () => {
const { api } = gridRef?.current || {};
const currentNode = api.getRowNode(current?.uniqueId);
const currentNode = api.getRowNode(currentSong?.uniqueId);
api.ensureNodeVisible(currentNode, 'middle');
};
@@ -121,10 +121,10 @@ export const PlayQueue = ({ type }: QueueProps) => {
const rowClassRules = useMemo<RowClassRules>(() => {
return {
'current-song': (params) => {
return params.data.uniqueId === current?.uniqueId;
return params.data.uniqueId === currentSong?.uniqueId;
},
};
}, [current?.uniqueId]);
}, [currentSong?.uniqueId]);
// Redraw the current song row when the previous song changes
useEffect(() => {
@@ -134,8 +134,8 @@ export const PlayQueue = ({ type }: QueueProps) => {
return;
}
const currentNode = api.getRowNode(current?.uniqueId);
const previousNode = api.getRowNode(previous?.uniqueId);
const currentNode = api.getRowNode(currentSong?.uniqueId);
const previousNode = api.getRowNode(previousSong?.uniqueId);
const rowNodes = [currentNode, previousNode];
@@ -146,7 +146,7 @@ export const PlayQueue = ({ type }: QueueProps) => {
}
}
}
}, [current, previous, tableConfig.followCurrentSong]);
}, [currentSong, previousSong, tableConfig.followCurrentSong]);
// Auto resize the columns when the column config changes
useEffect(() => {
@@ -198,7 +198,7 @@ export const PlayQueue = ({ type }: QueueProps) => {
/>
</VirtualGridAutoSizerContainer>
</VirtualGridContainer>
<TableConfigDropdown type={type} />
{/* <TableConfigDropdown type={type} /> */}
</ErrorBoundary>
);
};
@@ -14,7 +14,15 @@ import {
} from 'react-icons/ri';
import styled from 'styled-components';
import { Text } from '/@/components';
import { usePlayerStore } from '/@/store';
import {
useCurrentPlayer,
useCurrentSong,
useCurrentStatus,
useCurrentTime,
useRepeatStatus,
useSetCurrentTime,
useShuffleStatus,
} from '/@/store';
import { useSettingsStore } from '/@/store/settings.store';
import { PlaybackType, PlayerRepeat, PlayerShuffle, PlayerStatus } from '/@/types';
import { useCenterControls } from '../hooks/use-center-controls';
@@ -58,15 +66,17 @@ const SliderWrapper = styled.div`
export const CenterControls = ({ playersRef }: CenterControlsProps) => {
const [isSeeking, setIsSeeking] = useState(false);
const songDuration = usePlayerStore((state) => state.current.song?.duration);
const currentSong = useCurrentSong();
const songDuration = currentSong?.duration;
const skip = useSettingsStore((state) => state.player.skipButtons);
const playerType = useSettingsStore((state) => state.player.type);
const player1 = playersRef?.current?.player1;
const player2 = playersRef?.current?.player2;
const { status, player } = usePlayerStore((state) => state.current);
const setCurrentTime = usePlayerStore((state) => state.setCurrentTime);
const repeat = usePlayerStore((state) => state.repeat);
const shuffle = usePlayerStore((state) => state.shuffle);
const status = useCurrentStatus();
const player = useCurrentPlayer();
const setCurrentTime = useSetCurrentTime();
const repeat = useRepeatStatus();
const shuffle = useShuffleStatus();
const {
handleNextTrack,
@@ -79,7 +89,7 @@ export const CenterControls = ({ playersRef }: CenterControlsProps) => {
handleToggleShuffle,
} = useCenterControls({ playersRef });
const currentTime = usePlayerStore((state) => state.current.time);
const currentTime = useCurrentTime();
const currentPlayerRef = player === 1 ? player1 : player2;
const duration = format((songDuration || 0) * 1000);
const formattedTime = format(currentTime * 1000 || 0);
@@ -6,7 +6,7 @@ import { generatePath, Link } from 'react-router-dom';
import styled from 'styled-components';
import { Button, Text } from '/@/components';
import { AppRoute } from '/@/router/routes';
import { useAppStore, useAppStoreActions, usePlayerStore } from '/@/store';
import { useAppStore, useAppStoreActions, useCurrentSong } from '/@/store';
import { fadeIn } from '/@/styles';
const LeftControlsContainer = styled.div`
@@ -72,9 +72,9 @@ const LineItem = styled.div<{ $secondary?: boolean }>`
export const LeftControls = () => {
const { setSidebar } = useAppStoreActions();
const hideImage = useAppStore((state) => state.sidebar.image);
const song = usePlayerStore((state) => state.current.song);
const title = song?.name;
const artists = song?.artists;
const currentSong = useCurrentSong();
const title = currentSong?.name;
const artists = currentSong?.artists;
return (
<LeftControlsContainer>
@@ -93,10 +93,10 @@ export const LeftControls = () => {
to={AppRoute.NOW_PLAYING}
transition={{ duration: 0.3, ease: 'easeInOut' }}
>
{song?.imageUrl ? (
{currentSong?.imageUrl ? (
<PlayerbarImage
loading="eager"
src={song?.imageUrl}
src={currentSong?.imageUrl}
/>
) : (
<>
@@ -190,15 +190,15 @@ export const LeftControls = () => {
overflow="hidden"
size="xs"
to={
song?.albumId
currentSong?.albumId
? generatePath(AppRoute.LIBRARY_ALBUMS_DETAIL, {
albumId: song.albumId,
albumId: currentSong.albumId,
})
: ''
}
weight={500}
>
{song?.album || '—'}
{currentSong?.album || '—'}
</Text>
</LineItem>
</MetadataStack>
@@ -2,8 +2,15 @@ import { useRef } from 'react';
import styled from 'styled-components';
import { useSettingsStore } from '/@/store/settings.store';
import { PlaybackType } from '/@/types';
import { AudioPlayer } from '../../../components';
import { usePlayerStore } from '../../../store';
import { AudioPlayer } from '/@/components';
import {
useCurrentPlayer,
useCurrentStatus,
usePlayer1Data,
usePlayer2Data,
usePlayerControls,
useVolume,
} from '/@/store';
import { CenterControls } from './center-controls';
import { LeftControls } from './left-controls';
import { RightControls } from './right-controls';
@@ -46,12 +53,12 @@ const CenterGridItem = styled.div`
export const Playerbar = () => {
const playersRef = useRef<any>();
const settings = useSettingsStore((state) => state.player);
const volume = usePlayerStore((state) => state.volume);
const player1 = usePlayerStore((state) => state.player1());
const player2 = usePlayerStore((state) => state.player2());
const status = usePlayerStore((state) => state.current.status);
const player = usePlayerStore((state) => state.current.player);
const autoNext = usePlayerStore((state) => state.autoNext);
const volume = useVolume();
const player1 = usePlayer1Data();
const player2 = usePlayer2Data();
const status = useCurrentStatus();
const player = useCurrentPlayer();
const { autoNext } = usePlayerControls();
return (
<PlayerbarContainer>
@@ -2,7 +2,7 @@ import { Group } from '@mantine/core';
import { HiOutlineQueueList } from 'react-icons/hi2';
import { RiVolumeUpFill, RiVolumeDownFill, RiVolumeMuteFill } from 'react-icons/ri';
import styled from 'styled-components';
import { usePlayerStore, useAppStoreActions, useSidebarStore } from '/@/store';
import { useAppStoreActions, useMuted, useSidebarStore, useVolume } from '/@/store';
import { useRightControls } from '../hooks/use-right-controls';
import { PlayerButton } from './player-button';
import { Slider } from './slider';
@@ -33,8 +33,8 @@ const MetadataStack = styled.div`
`;
export const RightControls = () => {
const volume = usePlayerStore((state) => state.volume);
const muted = usePlayerStore((state) => state.muted);
const volume = useVolume();
const muted = useMuted();
const { setSidebar } = useAppStoreActions();
const { rightExpanded: isQueueExpanded } = useSidebarStore();
const { handleVolumeSlider, handleVolumeSliderState, handleMute } = useRightControls();
@@ -2,30 +2,31 @@ import { useCallback, useEffect } from 'react';
import isElectron from 'is-electron';
import { PlaybackType, PlayerRepeat, PlayerShuffle, PlayerStatus } from '/@/types';
import { mpvPlayer, mpvPlayerListener, ipc } from '#preload';
import { usePlayerStore } from '../../../store';
import { useSettingsStore } from '../../../store/settings.store';
import {
useCurrentPlayer,
useCurrentStatus,
useDefaultQueue,
usePlayerControls,
usePlayerStore,
useRepeatStatus,
useSetCurrentTime,
useShuffleStatus,
} from '/@/store';
import { useSettingsStore } from '/@/store/settings.store';
export const useCenterControls = (args: { playersRef: any }) => {
const { playersRef } = args;
const settings = useSettingsStore((state) => state.player);
const setShuffle = usePlayerStore((state) => state.setShuffle);
const setRepeat = usePlayerStore((state) => state.setRepeat);
const play = usePlayerStore((state) => state.play);
const pause = usePlayerStore((state) => state.pause);
const prev = usePlayerStore((state) => state.prev);
const next = usePlayerStore((state) => state.next);
const setCurrentIndex = usePlayerStore((state) => state.setCurrentIndex);
const autoNext = usePlayerStore((state) => state.autoNext);
const queue = usePlayerStore((state) => state.queue.default);
const playerStatus = usePlayerStore((state) => state.current.status);
const currentPlayer = usePlayerStore((state) => state.current.player);
const repeat = usePlayerStore((state) => state.repeat);
const shuffle = usePlayerStore((state) => state.shuffle);
const currentPlayer = useCurrentPlayer();
const { setShuffle, setRepeat, play, pause, previous, next, setCurrentIndex, autoNext } =
usePlayerControls();
const setCurrentTime = useSetCurrentTime();
const queue = useDefaultQueue();
const playerStatus = useCurrentStatus();
const repeatStatus = useRepeatStatus();
const shuffleStatus = useShuffleStatus();
const playerType = useSettingsStore((state) => state.player.type);
const setCurrentTime = usePlayerStore((state) => state.setCurrentTime);
const player1Ref = playersRef?.current?.player1;
const player2Ref = playersRef?.current?.player2;
const currentPlayerRef = currentPlayer === 1 ? player1Ref : player2Ref;
@@ -87,35 +88,35 @@ export const useCenterControls = (args: { playersRef: any }) => {
}, [isMpvPlayer, pause, setCurrentTime, stopPlayback]);
const handleToggleShuffle = useCallback(() => {
if (shuffle === PlayerShuffle.NONE) {
if (shuffleStatus === PlayerShuffle.NONE) {
const playerData = setShuffle(PlayerShuffle.TRACK);
return mpvPlayer.setQueueNext(playerData);
}
const playerData = setShuffle(PlayerShuffle.NONE);
return mpvPlayer.setQueueNext(playerData);
}, [setShuffle, shuffle]);
}, [setShuffle, shuffleStatus]);
const handleToggleRepeat = useCallback(() => {
if (repeat === PlayerRepeat.NONE) {
if (repeatStatus === PlayerRepeat.NONE) {
const playerData = setRepeat(PlayerRepeat.ALL);
return mpvPlayer.setQueueNext(playerData);
}
if (repeat === PlayerRepeat.ALL) {
if (repeatStatus === PlayerRepeat.ALL) {
const playerData = setRepeat(PlayerRepeat.ONE);
return mpvPlayer.setQueueNext(playerData);
}
return setRepeat(PlayerRepeat.NONE);
}, [repeat, setRepeat]);
}, [repeatStatus, setRepeat]);
const checkIsLastTrack = useCallback(() => {
return usePlayerStore.getState().checkIsLastTrack();
return usePlayerStore.getState().actions.checkIsLastTrack();
}, []);
const checkIsFirstTrack = useCallback(() => {
return usePlayerStore.getState().checkIsFirstTrack();
return usePlayerStore.getState().actions.checkIsFirstTrack();
}, []);
const handleAutoNext = useCallback(() => {
@@ -172,7 +173,7 @@ export const useCenterControls = (args: { playersRef: any }) => {
},
};
switch (repeat) {
switch (repeatStatus) {
case PlayerRepeat.NONE:
handleRepeatNone[playerType]();
break;
@@ -186,7 +187,16 @@ export const useCenterControls = (args: { playersRef: any }) => {
default:
break;
}
}, [autoNext, checkIsLastTrack, pause, play, playerType, repeat, resetPlayers, setCurrentIndex]);
}, [
autoNext,
checkIsLastTrack,
pause,
play,
playerType,
repeatStatus,
resetPlayers,
setCurrentIndex,
]);
const handleNextTrack = useCallback(() => {
const isLastTrack = checkIsLastTrack();
@@ -240,7 +250,7 @@ export const useCenterControls = (args: { playersRef: any }) => {
},
};
switch (repeat) {
switch (repeatStatus) {
case PlayerRepeat.NONE:
handleRepeatNone[playerType]();
break;
@@ -261,7 +271,7 @@ export const useCenterControls = (args: { playersRef: any }) => {
next,
pause,
playerType,
repeat,
repeatStatus,
resetPlayers,
setCurrentIndex,
setCurrentTime,
@@ -285,7 +295,7 @@ export const useCenterControls = (args: { playersRef: any }) => {
const handleRepeatAll = {
local: () => {
if (!isFirstTrack) {
const playerData = prev();
const playerData = previous();
mpvPlayer.setQueue(playerData);
mpvPlayer.previous();
} else {
@@ -299,7 +309,7 @@ export const useCenterControls = (args: { playersRef: any }) => {
setCurrentIndex(queue.length - 1);
resetPlayers();
} else {
prev();
previous();
resetPlayers();
}
},
@@ -307,7 +317,7 @@ export const useCenterControls = (args: { playersRef: any }) => {
const handleRepeatNone = {
local: () => {
const playerData = prev();
const playerData = previous();
mpvPlayer.setQueue(playerData);
mpvPlayer.previous();
},
@@ -316,7 +326,7 @@ export const useCenterControls = (args: { playersRef: any }) => {
resetPlayers();
pause();
} else {
prev();
previous();
resetPlayers();
}
},
@@ -325,7 +335,7 @@ export const useCenterControls = (args: { playersRef: any }) => {
const handleRepeatOne = {
local: () => {
if (!isFirstTrack) {
const playerData = prev();
const playerData = previous();
mpvPlayer.setQueue(playerData);
mpvPlayer.previous();
} else {
@@ -333,12 +343,12 @@ export const useCenterControls = (args: { playersRef: any }) => {
}
},
web: () => {
prev();
previous();
resetPlayers();
},
};
switch (repeat) {
switch (repeatStatus) {
case PlayerRepeat.NONE:
handleRepeatNone[playerType]();
break;
@@ -360,9 +370,9 @@ export const useCenterControls = (args: { playersRef: any }) => {
isMpvPlayer,
pause,
playerType,
prev,
previous,
queue.length,
repeat,
repeatStatus,
resetPlayers,
setCurrentIndex,
setCurrentTime,
@@ -489,7 +499,7 @@ export const useCenterControls = (args: { playersRef: any }) => {
next,
pause,
play,
prev,
previous,
setCurrentTime,
]);
@@ -1,13 +1,12 @@
import { useEffect } from 'react';
import isElectron from 'is-electron';
import { mpvPlayer } from '#preload';
import { usePlayerStore } from '../../../store';
import { useMuted, usePlayerControls, useVolume } from '/@/store';
export const useRightControls = () => {
const setVolume = usePlayerStore((state) => state.setVolume);
const volume = usePlayerStore((state) => state.volume);
const muted = usePlayerStore((state) => state.muted);
const setMuted = usePlayerStore((state) => state.setMuted);
const { setVolume, setMuted } = usePlayerControls();
const volume = useVolume();
const muted = useMuted();
// Ensure that the mpv player volume is set on startup
useEffect(() => {
@@ -46,7 +46,7 @@ export const handlePlayQueueAdd = async (options: PlayQueueAddOptions) => {
if (!songs) return;
const playerData = usePlayerStore.getState().addToQueue(songs, options.play);
const playerData = usePlayerStore.getState().actions.addToQueue(songs, options.play);
if (options.play === Play.NEXT || options.play === Play.LAST) {
if (playerType === PlaybackType.LOCAL) {
@@ -60,7 +60,7 @@ export const handlePlayQueueAdd = async (options: PlayQueueAddOptions) => {
mpvPlayer.play();
}
usePlayerStore.getState().play();
usePlayerStore.getState().actions.play();
}
}
};
@@ -16,7 +16,7 @@ import {
} from '/@/components';
import { mpvPlayer } from '#preload';
import { SettingsOptions } from '/@/features/settings/components/settings-option';
import { usePlayerStore } from '/@/store';
import { useCurrentStatus, usePlayerStore } from '/@/store';
import { useSettingsStore } from '/@/store/settings.store';
import { Play, PlaybackStyle, PlaybackType, PlayerStatus, CrossfadeStyle } from '/@/types';
import { localSettings } from '#preload';
@@ -29,7 +29,7 @@ const getAudioDevice = async () => {
export const PlaybackTab = () => {
const settings = useSettingsStore((state) => state.player);
const update = useSettingsStore((state) => state.setSettings);
const status = usePlayerStore((state) => state.current.status);
const status = useCurrentStatus();
const [audioDevices, setAudioDevices] = useState<SelectItem[]>([]);
const [mpvPath, setMpvPath] = useState('');
const [mpvParameters, setMpvParameters] = useState('');
@@ -83,7 +83,7 @@ export const PlaybackTab = () => {
onChange={(e) => {
update({ player: { ...settings, type: e as PlaybackType } });
if (isElectron() && e === PlaybackType.LOCAL) {
const queueData = usePlayerStore.getState().getPlayerData();
const queueData = usePlayerStore.getState().actions.getPlayerData();
mpvPlayer.setQueue(queueData);
}
}}
@@ -21,7 +21,7 @@ import { useNavigate, Link } from 'react-router-dom';
import styled from 'styled-components';
import { Button, TextInput } from '/@/components';
import { AppRoute } from '/@/router/routes';
import { useAppStoreActions, usePlayerStore, useSidebarStore } from '/@/store';
import { useAppStoreActions, useCurrentSong, useSidebarStore } from '/@/store';
import { fadeIn } from '/@/styles';
import { SidebarItem } from './sidebar-item';
@@ -62,7 +62,7 @@ export const Sidebar = () => {
const navigate = useNavigate();
const sidebar = useSidebarStore();
const { setSidebar } = useAppStoreActions();
const imageUrl = usePlayerStore((state) => state.current?.song?.imageUrl);
const imageUrl = useCurrentSong()?.imageUrl;
const showImage = sidebar.image;
File diff suppressed because it is too large Load Diff
+5 -6
View File
@@ -2,7 +2,7 @@
--root-font-size: 12px;
--icon-color: rgb(255, 255, 255);
--primary-color: rgb(49, 107, 224);
--primary-color: rgb(89, 141, 245);
--secondary-color: rgb(255, 120, 120);
--success-color: green;
--warning-color: orange;
@@ -20,7 +20,7 @@
--sidebar-btn-color: rgb(179, 179, 179);
--sidebar-btn-color-hover: #dddddd;
--sidebar-handle-bg: #4d4d4d;
--sidebar-border: 1px rgba(150, 150, 150, 0.1) solid;
--sidebar-border: none;
--playerbar-bg: linear-gradient(rgb(20, 20, 20) 0%, rgb(30, 30, 30) 50%, rgb(20, 20, 20) 100%);
--playerbar-btn-main-fg: rgb(0, 0, 0);
@@ -38,7 +38,7 @@
--tooltip-bg: #ffffff;
--tooltip-fg: #000000;
--scrollbar-track-bg: #181818;
--scrollbar-track-bg: transparent;
--scrollbar-thumb-bg: rgba(90, 90, 90, 0.5);
--btn-primary-bg: var(--primary-color);
@@ -46,14 +46,14 @@
--btn-primary-fg: #ffffff;
--btn-primary-fg-hover: #ffffff;
--btn-default-bg: rgb(39, 39, 39);
--btn-default-bg: rgb(31, 31, 32);
--btn-default-bg-hover: rgb(63, 63, 63);
--btn-default-fg: rgb(193, 193, 193);
--btn-default-fg-hover: rgb(193, 193, 193);
--btn-subtle-bg: transparent;
--btn-subtle-bg-hover: transparent;
--btn-subtle-fg: rgb(150, 150, 150);
--btn-subtle-fg: rgb(224, 224, 224);
--btn-subtle-fg-hover: rgb(240, 240, 240);
--input-bg: rgb(35, 35, 35);
@@ -107,7 +107,6 @@
--ag-foreground-color: rgb(179, 179, 179);
--ag-background-color: var(--main-bg);
// --ag-odd-row-background-color: rgb(25, 25, 25);
--ag-row-hover-color: rgba(100, 100, 100, 0.2);
--ag-selected-row-background-color: rgba(100, 100, 100, 0.4);
}
+14 -3
View File
@@ -9,7 +9,7 @@ body[data-theme="defaultLight"] {
--titlebar-fg: rgb(25, 25, 25);
--titlebar-bg: rgb(227, 229, 232);
--sidebar-bg: rgb(255, 255, 255);
--sidebar-bg: rgb(240, 241, 242);
--sidebar-btn-color: rgb(0, 0, 0);
--sidebar-btn-color-hover: rgb(0, 0, 0);
--sidebar-handle-bg: #4d4d4d;
@@ -34,8 +34,8 @@ body[data-theme="defaultLight"] {
--tooltip-bg: rgb(255, 255, 255);
--tooltip-fg: rgb(0, 0, 0);
--scrollbar-track-bg: rgba(0, 0, 0, 0.2);
--scrollbar-thumb-bg: rgb(150, 150, 150);
--scrollbar-track-bg: transparent;
--scrollbar-thumb-bg: rgb(140, 140, 140);
--btn-primary-bg: var(--primary-color);
--btn-primary-bg-hover: rgb(47, 122, 237);
@@ -109,6 +109,17 @@ body[data-theme="defaultLight"] {
--ag-selected-row-background-color: rgba(100, 100, 100, 0.4);
}
.ag-root ::-webkit-scrollbar-corner {
background: var(--scrollbar-track-bg);
}
.ag-root ::-webkit-scrollbar-track-piece {
background: var(--scrollbar-track-bg);
}
.ag-root ::-webkit-scrollbar-thumb {
background: var(--scrollbar-thumb-bg);
// background: black;
}
.ag-cell-focus {
border: 1px rgba(60, 60, 60, 0.3) solid !important;
}