diff --git a/src/renderer/features/player/components/center-controls.tsx b/src/renderer/features/player/components/center-controls.tsx
index a672daa4e..15316e8f1 100644
--- a/src/renderer/features/player/components/center-controls.tsx
+++ b/src/renderer/features/player/components/center-controls.tsx
@@ -4,7 +4,8 @@ import isElectron from 'is-electron';
import { IoIosPause } from 'react-icons/io';
import {
RiPlayFill,
- RiRepeat2Fill,
+ RiRepeat2Line,
+ RiRepeatOneLine,
RiRewindFill,
RiShuffleFill,
RiSkipBackFill,
@@ -16,7 +17,12 @@ import { Text } from '@/renderer/components';
import { usePlayerStore } from '@/renderer/store';
import { useSettingsStore } from '@/renderer/store/settings.store';
import { Font } from '@/renderer/styles';
-import { PlaybackType, PlayerStatus } from '@/renderer/types';
+import {
+ PlaybackType,
+ PlayerRepeat,
+ PlayerShuffle,
+ PlayerStatus,
+} from '@/renderer/types';
import { useCenterControls } from '../hooks/use-center-controls';
import { PlayerButton } from './player-button';
import { Slider } from './slider';
@@ -58,13 +64,15 @@ const SliderWrapper = styled.div`
export const CenterControls = ({ playersRef }: CenterControlsProps) => {
const [isSeeking, setIsSeeking] = useState(false);
- const playerData = usePlayerStore((state) => state.getPlayerData());
+ const songDuration = usePlayerStore((state) => state.current.song?.duration);
const skip = useSettingsStore((state) => state.player.skipButtons);
const playerType = useSettingsStore((state) => state.player.type);
- const player1 = playersRef?.current?.player1?.player;
- const player2 = playersRef?.current?.player2?.player;
+ 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 {
handleNextTrack,
@@ -73,11 +81,13 @@ export const CenterControls = ({ playersRef }: CenterControlsProps) => {
handleSeekSlider,
handleSkipBackward,
handleSkipForward,
+ handleToggleRepeat,
+ handleToggleShuffle,
} = useCenterControls({ playersRef });
const currentTime = usePlayerStore((state) => state.current.time);
const currentPlayerRef = player === 1 ? player1 : player2;
- const duration = format((playerData.queue.current?.duration || 0) * 1000);
+ const duration = format((songDuration || 0) * 1000);
const formattedTime = format(currentTime * 1000 || 0);
useEffect(() => {
@@ -101,10 +111,19 @@ export const CenterControls = ({ playersRef }: CenterControlsProps) => {
}
- tooltip={{ label: `Shuffle`, openDelay: 500 }}
- variant="secondary"
- onClick={handlePrevTrack}
+ tooltip={{
+ label:
+ shuffle === PlayerShuffle.NONE
+ ? 'Shuffle disabled'
+ : shuffle === PlayerShuffle.TRACK
+ ? 'Shuffle tracks'
+ : 'Shuffle albums',
+ openDelay: 500,
+ }}
+ variant="tertiary"
+ onClick={handleToggleShuffle}
/>
}
@@ -156,10 +175,26 @@ export const CenterControls = ({ playersRef }: CenterControlsProps) => {
onClick={handleNextTrack}
/>
}
- tooltip={{ label: 'Repeat', openDelay: 500 }}
- variant="secondary"
- onClick={handleNextTrack}
+ $isActive={repeat !== PlayerRepeat.NONE}
+ icon={
+ repeat === PlayerRepeat.ONE ? (
+
+ ) : (
+
+ )
+ }
+ tooltip={{
+ label: `${
+ repeat === PlayerRepeat.NONE
+ ? 'Repeat disabled'
+ : repeat === PlayerRepeat.ALL
+ ? 'Repeat all'
+ : 'Repeat one'
+ }`,
+ openDelay: 500,
+ }}
+ variant="tertiary"
+ onClick={handleToggleRepeat}
/>
@@ -172,7 +207,7 @@ export const CenterControls = ({ playersRef }: CenterControlsProps) => {
`
display: inline-block;
width: 95%;
- max-width: 30vw;
+ max-width: 20vw;
overflow: hidden;
color: ${(props) => props.$secondary && 'var(--main-fg-secondary)'};
white-space: nowrap;
@@ -142,7 +142,6 @@ export const LeftControls = () => {
component={Link}
overflow="hidden"
size="sm"
- sx={{ '&:hover': { textDecoration: 'underline' } }}
to={AppRoute.NOW_PLAYING}
weight={500}
>
diff --git a/src/renderer/features/player/components/player-button.tsx b/src/renderer/features/player/components/player-button.tsx
index 103d42e74..e4700ed19 100644
--- a/src/renderer/features/player/components/player-button.tsx
+++ b/src/renderer/features/player/components/player-button.tsx
@@ -12,9 +12,10 @@ import { Tooltip } from '@/renderer/components';
type MantineButtonProps = UnstyledButtonProps &
ComponentPropsWithoutRef<'button'>;
interface PlayerButtonProps extends MantineButtonProps {
+ $isActive?: boolean;
icon: ReactNode;
tooltip?: Omit;
- variant: 'main' | 'secondary';
+ variant: 'main' | 'secondary' | 'tertiary';
}
const WrapperMainVariant = css`
@@ -63,12 +64,20 @@ const ButtonSecondaryVariant = css`
stroke: var(--playerbar-btn-bg);
}
- &:hover {
+ &:focus-visible {
svg {
fill: var(--playerbar-btn-bg-hover);
stroke: var(--playerbar-btn-bg-hover);
}
}
+`;
+
+const ButtonTertiaryVariant = css`
+ padding: 0.5rem;
+
+ svg {
+ display: flex;
+ }
&:focus-visible {
svg {
@@ -101,8 +110,22 @@ const StyledPlayerButton = styled(UnstyledButton)`
opacity: 0.5;
}
+ svg {
+ fill: ${({ $isActive }) => $isActive && 'var(--primary-color)'};
+ }
+
+ &:hover {
+ svg {
+ fill: ${({ $isActive }) => !$isActive && 'var(--playerbar-btn-bg-hover)'};
+ }
+ }
+
${({ variant }) =>
- variant === 'main' ? ButtonMainVariant : ButtonSecondaryVariant}
+ variant === 'main'
+ ? ButtonMainVariant
+ : variant === 'secondary'
+ ? ButtonSecondaryVariant
+ : ButtonTertiaryVariant};
`;
export const PlayerButton = ({
@@ -116,8 +139,8 @@ export const PlayerButton = ({
{icon}
@@ -137,5 +160,6 @@ export const PlayerButton = ({
};
PlayerButton.defaultProps = {
+ $isActive: false,
tooltip: undefined,
};