support sidebar player in now playing route (#2134)

- add toggle to show/hide the queue in the sidebarplayer
This commit is contained in:
jeffvli
2026-07-23 22:16:01 -07:00
parent 04b1f6595a
commit 207df236a3
12 changed files with 273 additions and 151 deletions
@@ -6,7 +6,10 @@ import {
getDefaultAudioDevice,
useAudioDevices,
} from '/@/renderer/features/settings/components/playback/audio-settings';
import { ListConfigTable } from '/@/renderer/features/shared/components/list-config-menu';
import {
ListConfigBooleanControl,
ListConfigTable,
} from '/@/renderer/features/shared/components/list-config-menu';
import {
usePlaybackType,
usePlayerActions,
@@ -22,16 +25,18 @@ import {
useSettingsStore,
useSettingsStoreActions,
useShowLyricsInSidebar,
useShowQueueInSidebar,
useShowVisualizerInSidebar,
} from '/@/renderer/store/settings.store';
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
import { Button } from '/@/shared/components/button/button';
import { Group } from '/@/shared/components/group/group';
import { Paper } from '/@/shared/components/paper/paper';
import { Popover } from '/@/shared/components/popover/popover';
import { SegmentedControl } from '/@/shared/components/segmented-control/segmented-control';
import { Select } from '/@/shared/components/select/select';
import { Slider } from '/@/shared/components/slider/slider';
import { Switch } from '/@/shared/components/switch/switch';
import { Stack } from '/@/shared/components/stack/stack';
import { Text } from '/@/shared/components/text/text';
import { CrossfadeStyle, PlayerStatus, PlayerStyle, PlayerType } from '/@/shared/types/types';
@@ -41,8 +46,10 @@ export const PlayerConfig = () => {
const { t } = useTranslation();
const preservePitch = useSettingsStore((state) => state.playback.preservePitch);
const showLyricsInSidebar = useShowLyricsInSidebar();
const showQueueInSidebar = useShowQueueInSidebar();
const showVisualizerInSidebar = useShowVisualizerInSidebar();
const combinedLyricsAndVisualizer = useCombinedLyricsAndVisualizer();
const { transitionType } = usePlayerProperties();
const playbackSettings = usePlaybackSettings();
const { setSettings } = useSettingsStoreActions();
@@ -56,8 +63,8 @@ export const PlayerConfig = () => {
[playbackSettings, setSettings],
);
const options = useMemo(() => {
const allOptions = [
const audioOptions = useMemo(
() => [
{
component: <AudioPlayerTypeConfig />,
id: 'audioPlayerType',
@@ -68,12 +75,12 @@ export const PlayerConfig = () => {
id: 'audioDevice',
label: t('setting.audioDevice'),
},
{
component: null,
id: 'divider-1',
isDivider: true,
label: '',
},
],
[t],
);
const transitionOptions = useMemo(
() => [
{
component: <TransitionTypeConfig />,
id: 'transitionType',
@@ -82,19 +89,21 @@ export const PlayerConfig = () => {
{
component: <CrossfadeStyleConfig />,
id: 'crossfadeStyle',
isHidden: transitionType !== PlayerStyle.CROSSFADE,
label: t('setting.crossfadeStyle'),
},
{
component: <CrossfadeDurationConfig />,
id: 'crossfadeDuration',
isHidden: transitionType !== PlayerStyle.CROSSFADE,
label: t('setting.crossfadeDuration'),
},
{
component: null,
id: 'divider-2',
isDivider: true,
label: '',
},
],
[t, transitionType],
);
const playbackOptions = useMemo(
() => [
{
component: <PlaybackSpeedSlider />,
id: 'playbackSpeed',
@@ -107,31 +116,44 @@ export const PlayerConfig = () => {
},
{
component: (
<Switch
defaultChecked={preservePitch}
onChange={(e) => setPreservePitch(e.currentTarget.checked)}
/>
<ListConfigBooleanControl onChange={setPreservePitch} value={preservePitch} />
),
id: 'preservePitch',
label: t('setting.preservePitch'),
},
{
component: null,
id: 'divider-3',
isDivider: true,
label: '',
},
],
[preservePitch, setPreservePitch, t],
);
const sidebarOptions = useMemo(
() => [
{
component: (
<Switch
defaultChecked={showLyricsInSidebar}
onChange={(e) => {
<ListConfigBooleanControl
onChange={(value) => {
setSettings({
general: {
showLyricsInSidebar: e.currentTarget.checked,
showQueueInSidebar: value,
},
});
}}
value={showQueueInSidebar}
/>
),
id: 'showQueueInSidebar',
label: t('setting.showQueueInSidebar'),
},
{
component: (
<ListConfigBooleanControl
onChange={(value) => {
setSettings({
general: {
showLyricsInSidebar: value,
},
});
}}
value={showLyricsInSidebar}
/>
),
id: 'showLyricsInSidebar',
@@ -139,15 +161,15 @@ export const PlayerConfig = () => {
},
{
component: (
<Switch
defaultChecked={showVisualizerInSidebar}
onChange={(e) => {
<ListConfigBooleanControl
onChange={(value) => {
setSettings({
general: {
showVisualizerInSidebar: e.currentTarget.checked,
showVisualizerInSidebar: value,
},
});
}}
value={showVisualizerInSidebar}
/>
),
id: 'showVisualizerInSidebar',
@@ -155,35 +177,33 @@ export const PlayerConfig = () => {
},
{
component: (
<Switch
defaultChecked={combinedLyricsAndVisualizer}
onChange={(e) => {
<ListConfigBooleanControl
onChange={(value) => {
setSettings({
general: {
combinedLyricsAndVisualizer: e.currentTarget.checked,
combinedLyricsAndVisualizer: value,
},
});
}}
value={combinedLyricsAndVisualizer}
/>
),
id: 'combinedLyricsAndVisualizer',
label: t('setting.combinedLyricsAndVisualizer'),
},
];
return allOptions;
}, [
t,
preservePitch,
setSettings,
setPreservePitch,
showLyricsInSidebar,
showVisualizerInSidebar,
combinedLyricsAndVisualizer,
]);
],
[
combinedLyricsAndVisualizer,
setSettings,
showLyricsInSidebar,
showQueueInSidebar,
showVisualizerInSidebar,
t,
],
);
return (
<Popover position="top" width={500}>
<Popover position="top" withArrow>
<Popover.Target>
<ActionIcon
icon="mediaSettings"
@@ -199,8 +219,21 @@ export const PlayerConfig = () => {
variant="subtle"
/>
</Popover.Target>
<Popover.Dropdown>
<ListConfigTable options={options} />
<Popover.Dropdown maw={500} miw={320} onClick={(e) => e.stopPropagation()} p="sm">
<Stack gap="sm">
<Paper p="md" radius="md">
<ListConfigTable options={audioOptions} />
</Paper>
<Paper p="md" radius="md">
<ListConfigTable options={transitionOptions} />
</Paper>
<Paper p="md" radius="md">
<ListConfigTable options={playbackOptions} />
</Paper>
<Paper p="md" radius="md">
<ListConfigTable options={sidebarOptions} />
</Paper>
</Stack>
</Popover.Dropdown>
</Popover>
);
@@ -234,6 +267,7 @@ const AudioPlayerTypeConfig = () => {
value: e,
});
}}
variant="filled"
width="100%"
/>
);
@@ -268,6 +302,7 @@ const AudioDeviceConfig = () => {
});
}}
value={audioDeviceId ?? getDefaultAudioDevice(audioDevices, playbackType)}
variant="filled"
width="100%"
/>
);
@@ -331,6 +366,7 @@ const CrossfadeStyleConfig = () => {
setCrossfadeStyle(e as CrossfadeStyle);
}
}}
variant="filled"
width="100%"
/>
);
@@ -406,7 +442,7 @@ export const PlaybackSpeedSlider = () => {
root: {},
}}
value={speed}
w="100%"
w="240px"
/>
);
};
@@ -435,8 +471,9 @@ export const PitchControls = () => {
<Button
aria-label="-1 semitone"
fullWidth
fw={400}
onClick={() => adjustMusicalSpeed(-1)}
size="compact-xs"
size="compact-sm"
>
-1st
</Button>
@@ -444,13 +481,14 @@ export const PitchControls = () => {
<Button
aria-label="-10 cents"
fullWidth
fw={400}
onClick={() => adjustMusicalSpeed(-0.1)}
size="compact-xs"
size="compact-sm"
>
-10ct
</Button>
)}
<Text size="xs" style={{ fontFamily: 'monospace' }} ta="center" w="60px">
<Text size="sm" style={{ fontFamily: 'monospace' }} ta="center">
{speed.toFixed(2)}x {speedToPitch(speed) > 0 && '+'}
{speedToPitch(speed) == 0 && '±'}
{speedToPitch(speed).toFixed(2)}st
@@ -459,8 +497,9 @@ export const PitchControls = () => {
<Button
aria-label="+10 cents"
fullWidth
fw={400}
onClick={() => adjustMusicalSpeed(0.1)}
size="compact-xs"
size="compact-sm"
>
+10ct
</Button>
@@ -468,8 +507,9 @@ export const PitchControls = () => {
<Button
aria-label="+1 semitone"
fullWidth
fw={400}
onClick={() => adjustMusicalSpeed(1)}
size="compact-xs"
size="compact-sm"
>
+1st
</Button>