diff --git a/front/components/Play/PartitionMagic.tsx b/front/components/Play/PartitionMagic.tsx index c1e3d44..899b1b8 100644 --- a/front/components/Play/PartitionMagic.tsx +++ b/front/components/Play/PartitionMagic.tsx @@ -9,6 +9,7 @@ import { SvgContainer } from './SvgContainer'; import LoadingComponent from '../Loading'; import { SplendidGrandPiano } from 'smplr'; import { atom, useAtom } from 'jotai'; +import { useStopwatch } from 'react-use-precision-timer'; export const timestampAtom = atom(0); export const shouldPlayAtom = atom(false); @@ -37,20 +38,21 @@ const getCursorToPlay = ( } }; -const transitionDuration = 50; +const transitionDuration = 200; const PartitionMagic = ({ songID }: ParitionMagicProps) => { const { data, isLoading, isError } = useQuery(API.getSongCursorInfos(songID)); const currentCurIdx = React.useRef(-1); + const stopwatch = useStopwatch(); const [endPartitionReached, setEndPartitionReached] = React.useState(false); const [isPartitionSvgLoaded, setIsPartitionSvgLoaded] = React.useState(false); const partitionOffset = useSharedValue(0); const melodySound = React.useRef(null); const piano = React.useRef(null); const [isPianoLoaded, setIsPianoLoaded] = React.useState(false); - const timestamp = useAtom(timestampAtom)[0]; + const [timestamp, setTimestamp] = useAtom(timestampAtom); const shouldPlay = useAtom(shouldPlayAtom)[0]; - const [, setPartitionState] = useAtom(partitionStateAtom); + const [partitionState, setPartitionState] = useAtom(partitionStateAtom); const cursorPaddingVertical = 10; const cursorPaddingHorizontal = 3; @@ -62,13 +64,28 @@ const PartitionMagic = ({ songID }: ParitionMagicProps) => { const cursorTop = (data?.cursors[cursorDisplayIdx]?.y ?? 0) - cursorPaddingVertical; const cursorLeft = (data?.cursors[0]?.x ?? 0) - cursorPaddingHorizontal; + console.log('state', partitionState); + if (!endPartitionReached && currentCurIdx.current + 1 === data?.cursors.length) { // weird contraption but the mobile don't want classic functions to be called // with the withTiming function :( melodySound.current?.pauseAsync(); + piano.current?.stop(); setPartitionState('ended'); } + React.useEffect(() => { + if (isError) { + setPartitionState('error'); + } + }, [isError]); + + React.useEffect(() => { + if (isPartitionSvgLoaded && !isLoading && (melodySound.current?._loaded || isPianoLoaded)) { + setPartitionState('ready'); + } + }, [isPartitionSvgLoaded, isLoading, melodySound.current?._loaded, isPianoLoaded]); + React.useEffect(() => { if (Platform.OS === 'web' && !piano.current) { const audio = new AudioContext(); @@ -106,28 +123,23 @@ const PartitionMagic = ({ songID }: ParitionMagicProps) => { }, [data]); React.useEffect(() => { - if (isError) { - setPartitionState('error'); - } - }, [isError]); - - React.useEffect(() => { - if (isPartitionSvgLoaded && !isLoading && (melodySound.current?._loaded || isPianoLoaded)) { - setPartitionState('ready'); - } - }, [isPartitionSvgLoaded, isLoading, melodySound.current?._loaded, isPianoLoaded]); + const interval = setInterval(() => { + setTimestamp(stopwatch.getElapsedRunningTime()); + }, 200); + return () => { + clearInterval(interval); + }; + }, []); React.useEffect(() => { if (Platform.OS === 'web') { - if (!piano.current || !isPianoLoaded) { - return; - } + if (!piano.current || !isPianoLoaded) return; + shouldPlay ? stopwatch.start() : stopwatch.pause(); setPartitionState(shouldPlay ? 'playing' : 'paused'); return; } - if (!melodySound.current || !melodySound.current._loaded) { - return; - } + if (!melodySound.current || !melodySound.current._loaded) return; + shouldPlay ? stopwatch.start() : stopwatch.pause(); if (shouldPlay) { melodySound.current .playAsync() diff --git a/front/components/Play/PlayEndModal.tsx b/front/components/Play/PlayEndModal.tsx new file mode 100644 index 0000000..fd785cf --- /dev/null +++ b/front/components/Play/PlayEndModal.tsx @@ -0,0 +1,31 @@ +import PopupCC from '../UI/PopupCC'; +import { shouldEndAtom } from './PlayViewControlBar'; +import { partitionStateAtom } from './PartitionMagic'; +import ScoreModal from '../ScoreModal'; +import { useAtom } from 'jotai'; + +export const PlayEndModal = () => { + const [shouldEnd] = useAtom(shouldEndAtom); + const [partitionState] = useAtom(partitionStateAtom); + + const isEnd = shouldEnd || partitionState === 'ended'; + return ( + + + + ); +}; diff --git a/front/components/Play/PlayViewControlBar.tsx b/front/components/Play/PlayViewControlBar.tsx index f3c2be5..179ff14 100644 --- a/front/components/Play/PlayViewControlBar.tsx +++ b/front/components/Play/PlayViewControlBar.tsx @@ -25,7 +25,7 @@ const PlayViewControlBar = ({ song }: PlayViewControlBarProps) => { const bpm = React.useRef(60); const { colors } = useTheme(); const textColor = colors.text; - const paused = partitionState === 'paused'; + const isPlaying = partitionState === 'playing'; const disabled = partitionState === 'loading' || partitionState === 'error'; return ( { _icon={{ as: Ionicons, color: colors.coolGray[900], - name: paused ? 'play' : 'pause', + name: isPlaying ? 'pause' : 'play', }} - onPress={() => setShouldPlay(paused)} + onPress={() => setShouldPlay(!isPlaying)} /> { minWidth: 120, }} > - + ); diff --git a/front/views/PlayView.tsx b/front/views/PlayView.tsx index 743caa3..bf411d5 100644 --- a/front/views/PlayView.tsx +++ b/front/views/PlayView.tsx @@ -25,6 +25,7 @@ import { Clock, Cup } from 'iconsax-react-native'; import PlayViewControlBar from '../components/Play/PlayViewControlBar'; import ScoreModal from '../components/ScoreModal'; import { PlayScore, ScoreMessage } from '../components/Play/PlayScore'; +import { PlayEndModal } from '../components/Play/PlayEndModal'; type PlayViewProps = { songId: number; @@ -63,22 +64,22 @@ const PlayView = ({ songId }: PlayViewProps) => { const isPhone = screenSize === 'small'; const song = useQuery(API.getSong(songId, ['artist']), { staleTime: Infinity }); const toast = useToast(); - const [lastScoreMessage, setLastScoreMessage] = useState(); + // const [lastScoreMessage, setLastScoreMessage] = useState(); const webSocket = useRef(); - const [paused, setPause] = useState(true); - const stopwatch = useStopwatch(); - const [time, setTime] = useState(0); + // const [paused, setPause] = useState(true); + // const stopwatch = useStopwatch(); + // const [time, setTime] = useState(0); const [endResult, setEndResult] = useState(); - const [shouldPlay, setShouldPlay] = useState(false); + // const [shouldPlay, setShouldPlay] = useState(false); const songHistory = useQuery(API.getSongHistory(songId)); - const [score, setScore] = useState(0); // Between 0 and 100 - const getElapsedTime = () => stopwatch.getElapsedRunningTime(); - const [readyToPlay, setReadyToPlay] = useState(false); + // const [score, setScore] = useState(0); // Between 0 and 100 + // const getElapsedTime = () => stopwatch.getElapsedRunningTime(); + // const [readyToPlay, setReadyToPlay] = useState(false); // eslint-disable-next-line @typescript-eslint/no-unused-vars const [midiKeyboardFound, setMidiKeyboardFound] = useState(); // first number is the note, the other is the time when pressed on release the key is removed // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [streak, setStreak] = useState(0); + // const [streak, setStreak] = useState(0); const colorScheme = useColorScheme(); const { colors } = useTheme(); const statColor = colors.lightText; @@ -131,7 +132,7 @@ const PlayView = ({ songId }: PlayViewProps) => { console.log('MIDI inputs', inputs); let endMsgReceived = false; // Used to know if to go to error screen when websocket closes - if (inputs.size <= 0) { + if (inputs.size <= 10) { toast.show({ description: 'No MIDI Keyboard found' }); return; } @@ -238,14 +239,14 @@ const PlayView = ({ songId }: PlayViewProps) => { useEffect(() => { ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.LANDSCAPE).catch(() => {}); - const interval = setInterval(() => { - setTime(() => getElapsedTime()); // Countdown - }, 200); + // const interval = setInterval(() => { + // setTime(() => getElapsedTime()); // Countdown + // }, 200); return () => { ScreenOrientation.unlockAsync().catch(() => {}); - stopwatch.stop(); - clearInterval(interval); + // stopwatch.stop(); + // clearInterval(interval); }; }, []); @@ -290,12 +291,13 @@ const PlayView = ({ songId }: PlayViewProps) => { zIndex: 100, }} > - + + {/* { // eslint-disable-next-line @typescript-eslint/no-explicit-any - (() => (endResult ? : <>))() + endResult ? : <> } - + */} { /> { - setShouldPlay(false); - }} - onResume={() => { - setShouldPlay(true); - }} + // onEnd={onEnd} + // onPause={() => { + // setShouldPlay(false); + // }} + // onResume={() => { + // setShouldPlay(true); + // }} /> {colorScheme === 'dark' && (