From 51f07f4457ed5ba201fd887ead3c85280fbeb09d Mon Sep 17 00:00:00 2001 From: Victor Alves Date: Tue, 29 Oct 2024 17:58:05 -0300 Subject: [PATCH 01/24] feat: add repeat all songs --- src/app/components/fullscreen/controls.tsx | 27 ++++++++---- src/app/components/icons/repeat-one.tsx | 34 +++++++++++++++ src/app/components/player/controls.tsx | 30 +++++++++---- src/app/components/player/player.tsx | 19 ++------- src/i18n/languages/en.ts | 1 + src/i18n/languages/pt-BR.ts | 1 + src/store/player.store.ts | 49 ++++++++++++++++++---- src/types/playerContext.ts | 10 ++++- 8 files changed, 130 insertions(+), 41 deletions(-) create mode 100644 src/app/components/icons/repeat-one.tsx diff --git a/src/app/components/fullscreen/controls.tsx b/src/app/components/fullscreen/controls.tsx index 43bd3912..8f186b2f 100644 --- a/src/app/components/fullscreen/controls.tsx +++ b/src/app/components/fullscreen/controls.tsx @@ -8,6 +8,7 @@ import { SkipForward, } from 'lucide-react' import { Fragment } from 'react/jsx-runtime' +import RepeatOne from '@/app/components/icons/repeat-one' import { Button } from '@/app/components/ui/button' import { usePlayerActions, @@ -15,11 +16,12 @@ import { usePlayerLoop, usePlayerShuffle, } from '@/store/player.store' +import { LoopState } from '@/types/playerContext' export function FullscreenControls() { const isPlaying = usePlayerIsPlaying() const isShuffleActive = usePlayerShuffle() - const isLoopActive = usePlayerLoop() + const loopState = usePlayerLoop() const { isPlayingOneSong, toggleShuffle, @@ -76,7 +78,7 @@ export function FullscreenControls() { variant="ghost" className={buttonsStyle.secondary} onClick={() => playNextSong()} - disabled={!hasNextSong()} + disabled={!hasNextSong() && loopState !== LoopState.All} > @@ -85,16 +87,23 @@ export function FullscreenControls() { variant="ghost" className={clsx( buttonsStyle.secondary, - isLoopActive && buttonsStyle.activeDot, + loopState !== LoopState.Off && buttonsStyle.activeDot, )} onClick={() => toggleLoop()} > - + {loopState === LoopState.Off && ( + + )} + {loopState === LoopState.All && ( + + )} + {loopState === LoopState.One && ( + + )} ) diff --git a/src/app/components/icons/repeat-one.tsx b/src/app/components/icons/repeat-one.tsx new file mode 100644 index 00000000..6cc9f778 --- /dev/null +++ b/src/app/components/icons/repeat-one.tsx @@ -0,0 +1,34 @@ +import { SVGProps } from 'react' + +export default function RepeatOne(props: SVGProps) { + return ( + + + + + + ) +} diff --git a/src/app/components/player/controls.tsx b/src/app/components/player/controls.tsx index 1e2b7814..772e5018 100644 --- a/src/app/components/player/controls.tsx +++ b/src/app/components/player/controls.tsx @@ -10,6 +10,7 @@ import { import { useEffect } from 'react' import { type HotkeyCallback, type Keys, useHotkeys } from 'react-hotkeys-hook' import { useTranslation } from 'react-i18next' +import RepeatOne from '@/app/components/icons/repeat-one' import { Button } from '@/app/components/ui/button' import { SimpleTooltip } from '@/app/components/ui/simple-tooltip' import { @@ -20,6 +21,7 @@ import { usePlayerMediaType, usePlayerShuffle, } from '@/store/player.store' +import { LoopState } from '@/types/playerContext' import { Radio } from '@/types/responses/radios' import { ISong } from '@/types/responses/song' import { manageMediaSession } from '@/utils/setMediaSession' @@ -33,7 +35,7 @@ export function PlayerControls({ song, radio }: PlayerControlsProps) { const { t } = useTranslation() const mediaType = usePlayerMediaType() const isShuffleActive = usePlayerShuffle() - const isLoopActive = usePlayerLoop() + const loopState = usePlayerLoop() const isPlaying = usePlayerIsPlaying() const { isPlayingOneSong, @@ -74,9 +76,15 @@ export function PlayerControls({ song, radio }: PlayerControlsProps) { const playTooltip = isPlaying ? t('player.tooltips.pause') : t('player.tooltips.play') - const repeatTooltip = isLoopActive - ? t('player.tooltips.repeat.disable') - : t('player.tooltips.repeat.enable') + + const repeatTooltips = { + 0: t('player.tooltips.repeat.enable'), + 1: t('player.tooltips.repeat.enableOne'), + 2: t('player.tooltips.repeat.disable'), + } + const repeatTooltip = repeatTooltips[loopState] + + const cannotGotoNextSong = !hasNextSong() && loopState !== LoopState.All return (
@@ -130,7 +138,7 @@ export function PlayerControls({ song, radio }: PlayerControlsProps) { )} diff --git a/src/app/components/player/player.tsx b/src/app/components/player/player.tsx index 74948c70..c30a933e 100644 --- a/src/app/components/player/player.tsx +++ b/src/app/components/player/player.tsx @@ -15,6 +15,7 @@ import { usePlayerSonglist, getVolume, } from '@/store/player.store' +import { LoopState } from '@/types/playerContext' import { PlayerControls } from './controls' import { PlayerLikeButton } from './like-button' import { PlayerProgress } from './progress' @@ -34,15 +35,13 @@ export function Player() { setAudioPlayerRef, setCurrentDuration, setProgress, - hasNextSong, - playNextSong, - clearPlayerState, setPlayingState, + handleSongEnded, } = usePlayerActions() const { currentList, currentSongIndex, radioList } = usePlayerSonglist() const isPlaying = usePlayerIsPlaying() const mediaType = usePlayerMediaType() - const isLoopActive = usePlayerLoop() + const loopState = usePlayerLoop() const currentDuration = usePlayerDuration() const audioPlayerRef = usePlayerRef() const progress = usePlayerProgress() @@ -120,16 +119,6 @@ export function Player() { } }, [currentDuration, progress, setCurrentDuration, setProgress]) - const handleSongEnded = useCallback(() => { - if (hasNextSong()) { - playNextSong() - setPlayingState(true) - } else { - clearPlayerState() - setPlayingState(false) - } - }, [clearPlayerState, hasNextSong, playNextSong, setPlayingState]) - return (