diff --git a/src/renderer/features/player/components/player-config.tsx b/src/renderer/features/player/components/player-config.tsx index 1d1bcc55a..7c289f45e 100644 --- a/src/renderer/features/player/components/player-config.tsx +++ b/src/renderer/features/player/components/player-config.tsx @@ -110,8 +110,9 @@ export const PlayerConfig = () => { label: t('player.playbackSpeed'), }, { - component: !preservePitch ? : <>, + component: , id: 'pitchControls', + isHidden: preservePitch, label: '', }, { @@ -219,7 +220,7 @@ export const PlayerConfig = () => { variant="subtle" /> - e.stopPropagation()} p="sm"> + e.stopPropagation()} p="sm"> @@ -437,12 +438,8 @@ export const PlaybackSpeedSlider = () => { onChange={setSpeed} onDoubleClick={() => setSpeed(1)} step={0.01} - styles={{ - markLabel: {}, - root: {}, - }} value={speed} - w="240px" + w="320px" /> ); }; @@ -467,13 +464,13 @@ export const PitchControls = () => { }; return ( - + @@ -483,7 +480,7 @@ export const PitchControls = () => { fullWidth fw={400} onClick={() => adjustMusicalSpeed(-0.1)} - size="compact-sm" + size="compact-xs" > -10ct @@ -499,7 +496,7 @@ export const PitchControls = () => { fullWidth fw={400} onClick={() => adjustMusicalSpeed(0.1)} - size="compact-sm" + size="compact-xs" > +10ct @@ -509,7 +506,7 @@ export const PitchControls = () => { fullWidth fw={400} onClick={() => adjustMusicalSpeed(1)} - size="compact-sm" + size="compact-xs" > +1st diff --git a/src/renderer/features/player/components/right-controls.tsx b/src/renderer/features/player/components/right-controls.tsx index 68155f8c3..baa285c2d 100644 --- a/src/renderer/features/player/components/right-controls.tsx +++ b/src/renderer/features/player/components/right-controls.tsx @@ -8,6 +8,10 @@ import { CustomPlayerbarSlider } from '/@/renderer/features/player/components/pl import { SleepTimerButton } from '/@/renderer/features/player/components/sleep-timer-button'; import { usePlayer } from '/@/renderer/features/player/context/player-context'; import { useAudioDevices } from '/@/renderer/features/settings/components/playback/audio-settings'; +import { + ListConfigBooleanControl, + ListConfigTable, +} from '/@/renderer/features/shared/components/list-config-menu'; import { useSetRating } from '/@/renderer/features/shared/hooks/use-set-rating'; import { useCreateFavorite } from '/@/renderer/features/shared/mutations/create-favorite-mutation'; import { useDeleteFavorite } from '/@/renderer/features/shared/mutations/delete-favorite-mutation'; @@ -48,8 +52,8 @@ import { Popover } from '/@/shared/components/popover/popover'; import { Rating } from '/@/shared/components/rating/rating'; import { SegmentedControl } from '/@/shared/components/segmented-control/segmented-control'; import { Select } from '/@/shared/components/select/select'; +import { Slider } from '/@/shared/components/slider/slider'; import { Stack } from '/@/shared/components/stack/stack'; -import { Switch } from '/@/shared/components/switch/switch'; import { Text } from '/@/shared/components/text/text'; import { useMediaQuery } from '/@/shared/hooks/use-media-query'; import { useThrottledCallback } from '/@/shared/hooks/use-throttled-callback'; @@ -107,13 +111,6 @@ const AutoDJButton = () => { const settings = useAutoDJSettings(); const { setSettings } = useSettingsStoreActions(); - const itemLabels = useMemo(() => { - return { - description: t('setting.autoDJ_itemCount_description'), - title: t('setting.autoDJ_itemCount'), - }; - }, [t]); - const strategySelectData = useMemo( () => [ { @@ -128,22 +125,200 @@ const AutoDJButton = () => { [t], ); - const strategyLabels = + const strategyTitle = settings.mode === AUTO_DJ_MODE.ALBUMS - ? { - description: '', - title: t('setting.autoDJ_albumStrategy'), - } - : { - description: '', - title: t('setting.autoDJ_songStrategy'), - }; + ? t('setting.autoDJ_albumStrategy') + : t('setting.autoDJ_songStrategy'); const strategyValue = settings.mode === AUTO_DJ_MODE.ALBUMS ? (settings.albumStrategy ?? AUTO_DJ_STRATEGY.SIMILAR) : (settings.songStrategy ?? AUTO_DJ_STRATEGY.SIMILAR); + const enabledOptions = useMemo( + () => [ + { + component: ( + { + setSettings({ + autoDJ: { enabled: value }, + }); + }} + value={settings.enabled} + /> + ), + id: 'enabled', + label: t('setting.autoDJ_enabled'), + }, + ], + [setSettings, settings.enabled, t], + ); + + const configOptions = useMemo( + () => [ + { + component: ( + { - if (!value) return; - setSettings({ - autoDJ: - settings.mode === AUTO_DJ_MODE.ALBUMS - ? { albumStrategy: value as AutoDJStrategy } - : { songStrategy: value as AutoDJStrategy }, - }); - }} - size="sm" - value={strategyValue} - variant="filled" - w="100%" - /> + - - setSettings({ - autoDJ: { - itemCount: Number(e), - }, - }) - } - size="sm" - value={Number(settings.itemCount)} - variant="filled" - /> - - - - setSettings({ - autoDJ: { - timing: Number(e), - }, - }) - } - size="sm" - value={Number(settings.timing)} - variant="filled" - /> - - - - - - {t('setting.autoDJ_allowDuplicates')} - - - {t('setting.autoDJ_allowDuplicates_description')} - - - - setSettings({ - autoDJ: { - allowDuplicates: e.currentTarget.checked, - }, - }) - } - /> - - - - - - - {t('setting.autoDJ_onlySimilar')} - - - {t('setting.autoDJ_onlySimilar_description')} - - - - setSettings({ - autoDJ: { - onlySimilar: e.currentTarget.checked, - }, - }) - } - /> - + diff --git a/src/renderer/features/player/components/sleep-timer-button.module.css b/src/renderer/features/player/components/sleep-timer-button.module.css new file mode 100644 index 000000000..2d4604f67 --- /dev/null +++ b/src/renderer/features/player/components/sleep-timer-button.module.css @@ -0,0 +1,6 @@ +.active-status { + display: flex; + flex-direction: column; + gap: var(--theme-spacing-xs); + align-items: center; +} diff --git a/src/renderer/features/player/components/sleep-timer-button.tsx b/src/renderer/features/player/components/sleep-timer-button.tsx index 10416cbde..a2097bdef 100644 --- a/src/renderer/features/player/components/sleep-timer-button.tsx +++ b/src/renderer/features/player/components/sleep-timer-button.tsx @@ -1,6 +1,8 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; +import styles from './sleep-timer-button.module.css'; + import { usePlayerEvents } from '/@/renderer/features/player/audio-player/hooks/use-player-events'; import { usePlayer } from '/@/renderer/features/player/context/player-context'; import { @@ -17,13 +19,13 @@ import { } from '/@/renderer/store/sleep-timer.store'; import { ActionIcon } from '/@/shared/components/action-icon/action-icon'; import { Button } from '/@/shared/components/button/button'; -import { Divider } from '/@/shared/components/divider/divider'; -import { Flex } from '/@/shared/components/flex/flex'; import { Grid } from '/@/shared/components/grid/grid'; import { Group } from '/@/shared/components/group/group'; import { NumberInput } from '/@/shared/components/number-input/number-input'; +import { Paper } from '/@/shared/components/paper/paper'; import { Popover } from '/@/shared/components/popover/popover'; import { Stack } from '/@/shared/components/stack/stack'; +import { TextTitle } from '/@/shared/components/text-title/text-title'; import { Text } from '/@/shared/components/text/text'; import { PlayerShuffle, PlayerStatus } from '/@/shared/types/types'; @@ -196,7 +198,6 @@ export const SleepTimerButton = () => { const remaining = useSleepTimerRemaining(); const { cancelTimer, startEndOfAlbumTimer, startEndOfSongTimer, startTimedTimer } = useSleepTimerActions(); - const { mediaPause } = usePlayer(); const shuffle = usePlayerShuffle(); // Track level shuffle scatters and album across a play queue making 'end-of-album' // meaningless. Album shuffle keeps each album intact, so keep 'end-of-'album @@ -209,9 +210,6 @@ export const SleepTimerButton = () => { const [customSeconds, setCustomSeconds] = useState(0); const [opened, setOpened] = useState(false); - const mediaPauseRef = useRef(mediaPause); - mediaPauseRef.current = mediaPause; - const handlePreset = useCallback( (option: (typeof PRESET_OPTIONS)[number]) => { if (option.mode === 'endOfSong') { @@ -248,18 +246,12 @@ export const SleepTimerButton = () => { if (option.mode === 'endOfAlbum') { return t('player.sleepTimer_endOfAlbum'); } - if (option.minutes >= 60) { - return t('player.sleepTimer_hours', { - count: option.minutes / 60, - }); - } - return t('player.sleepTimer_minutes', { - count: option.minutes, - }); + + return `${option.minutes}`; }; return ( - + { variant="subtle" /> - - - - {t('player.sleepTimer')} - + e.stopPropagation()} p="sm"> + + + + {t('player.sleepTimer')} + - {active && ( - - {mode === 'endOfSong' ? ( - - {t('player.sleepTimer_endOfSong')} - - ) : mode === 'endOfAlbum' ? ( - - {t('player.sleepTimer_endOfAlbum')} - - ) : ( - - {formatRemaining(remaining)} - - )} - - - )} + {active && ( + <> + {mode === 'endOfSong' ? ( + + {t('player.sleepTimer_endOfSong')} + + ) : mode === 'endOfAlbum' ? ( + + {t('player.sleepTimer_endOfAlbum')} + + ) : ( + + {formatRemaining(remaining)} + + )} + + + )} + - {PRESET_OPTIONS.filter( - (option) => option.mode === 'endOfSong' || option.mode === 'endOfAlbum', - ).map((option) => { - const disabled = option.mode === 'endOfAlbum' && isTrackShuffle; + + + {PRESET_OPTIONS.filter( + (option) => + option.mode === 'endOfSong' || option.mode === 'endOfAlbum', + ).map((option) => { + const disabled = option.mode === 'endOfAlbum' && isTrackShuffle; - return ( - - ); - })} - - - - - {PRESET_OPTIONS.filter((option) => option.mode === 'timed').map( - (option, index) => ( - + return ( - - ), - )} - - - - - {!showCustom ? ( - - ) : ( - - - setCustomHours(Number(val) || 0)} - placeholder="hr" - size="xs" - value={customHours} - /> - : - setCustomMinutes(Number(val) || 0)} - placeholder="min" - size="xs" - value={customMinutes} - /> - : - setCustomSeconds(Number(val) || 0)} - placeholder="sec" - size="xs" - value={customSeconds} - /> - - - - - + ); + })} - )} + + + + + {PRESET_OPTIONS.filter((option) => option.mode === 'timed').map( + (option, index) => ( + + + + ), + )} + + + + + {!showCustom ? ( + + ) : ( + + + setCustomHours(Number(val) || 0)} + rightSection={ + + hr + + } + size="sm" + value={customHours} + variant="filled" + /> + : + setCustomMinutes(Number(val) || 0)} + rightSection={ + + min + + } + size="sm" + value={customMinutes} + variant="filled" + /> + : + setCustomSeconds(Number(val) || 0)} + rightSection={ + + sec + + } + size="sm" + value={customSeconds} + variant="filled" + /> + + + + + + + )} + diff --git a/src/renderer/features/shared/components/list-config-menu.module.css b/src/renderer/features/shared/components/list-config-menu.module.css index 8a180ce6a..5207fadce 100644 --- a/src/renderer/features/shared/components/list-config-menu.module.css +++ b/src/renderer/features/shared/components/list-config-menu.module.css @@ -5,11 +5,21 @@ .th { width: 50%; padding: var(--theme-spacing-md) var(--theme-spacing-md) var(--theme-spacing-md) 0; + font-weight: 500; + vertical-align: middle; background-color: initial; } .td { padding: 0; + vertical-align: middle; +} + +.control { + display: flex; + align-items: center; + justify-content: flex-end; + width: 100%; } .divider-cell { diff --git a/src/renderer/features/shared/components/list-config-menu.tsx b/src/renderer/features/shared/components/list-config-menu.tsx index 099583823..9a8821c72 100644 --- a/src/renderer/features/shared/components/list-config-menu.tsx +++ b/src/renderer/features/shared/components/list-config-menu.tsx @@ -266,10 +266,13 @@ export const ListConfigTable = ({ ); } + return ( {option.label} - {option.component} + +
{option.component}
+
); })}