Add repeat mode
This commit is contained in:
1
src/assets/repeat.svg
Normal file
1
src/assets/repeat.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 106.69 89.45"><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><g id="Regular-M"><path d="M0,41.16a5.37,5.37,0,0,0,10.74,0V37.94c0-7.76,5.37-12.89,13.38-12.89H60.94v10.2a4.05,4.05,0,0,0,4.39,4.3,5.27,5.27,0,0,0,3.32-1.22L87.11,23.1a4.1,4.1,0,0,0,0-6.55L68.65,1.22A5.57,5.57,0,0,0,65.33,0a4.09,4.09,0,0,0-4.39,4.35v10.1H25.15C9.77,14.45,0,23.29,0,37.16ZM45.75,54.25A4,4,0,0,0,41.36,50a5.25,5.25,0,0,0-3.27,1.17L19.63,66.36a4,4,0,0,0,0,6.54L38.09,88.23a5,5,0,0,0,3.27,1.22,4,4,0,0,0,4.39-4.29V75H81.54c15.38,0,25.15-8.89,25.15-22.7v-4a5.37,5.37,0,1,0-10.74,0v3.22c0,7.72-5.37,12.9-13.38,12.9H45.75Z"/></g></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 695 B |
1
src/assets/shuffle.svg
Normal file
1
src/assets/shuffle.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 114.69 90.97"><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><g id="Symbols"><g id="Regular-M"><path d="M0,70.51c0,3.12,2.29,5.27,5.76,5.27H16.85c8.44,0,13.47-2.44,19.58-9.52L47.36,53.47l11,12.79c6,7.08,11.08,9.57,19.58,9.57h9V86.67A4,4,0,0,0,91.26,91a5.27,5.27,0,0,0,3.32-1.22L113,74.51A4.08,4.08,0,0,0,113,68L94.58,52.64a5.27,5.27,0,0,0-3.32-1.22,4,4,0,0,0-4.35,4.29v9.48H78.22c-5.08,0-8.2-1.62-12.16-6.25L54.39,45.31,66.06,31.74c4-4.69,7.08-6.3,12.16-6.3h8.69v9.81a4,4,0,0,0,4.35,4.3,5.27,5.27,0,0,0,3.32-1.22L113,23.1a4.09,4.09,0,0,0,0-6.55L94.58,1.22A5.27,5.27,0,0,0,91.26,0a4,4,0,0,0-4.35,4.3V14.84h-9c-8.5,0-13.57,2.49-19.58,9.57l-11,12.8L36.43,24.41c-6.11-7.08-11.14-9.57-19.58-9.57H5.76C2.29,14.84,0,17,0,20.17s2.34,5.32,5.76,5.32H17.09c4.69,0,7.67,1.61,11.67,6.25L40.43,45.31,28.76,58.94c-4.05,4.63-7,6.25-11.67,6.25H5.76C2.34,65.19,0,67.38,0,70.51Z"/></g></g></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 964 B |
@@ -4,4 +4,9 @@ export const Header = styled.Text`
|
|||||||
margin: 24px 0 12px 0;
|
margin: 24px 0 12px 0;
|
||||||
font-size: 36px;
|
font-size: 36px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const SubHeader = styled.Text`
|
||||||
|
font-size: 24px;
|
||||||
|
margin: 12px 0;
|
||||||
`;
|
`;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import React, { useState, useCallback, useEffect, useRef } from 'react';
|
||||||
import TrackPlayer, { usePlaybackState, STATE_PLAYING, STATE_PAUSED } from 'react-native-track-player';
|
import TrackPlayer, { usePlaybackState, STATE_PLAYING, STATE_PAUSED } from 'react-native-track-player';
|
||||||
import { TouchableOpacity } from 'react-native';
|
import { TouchableOpacity } from 'react-native';
|
||||||
import styled from 'styled-components/native';
|
import styled from 'styled-components/native';
|
||||||
@@ -7,9 +7,13 @@ import ForwardIcon from 'assets/forwards.svg';
|
|||||||
import BackwardIcon from 'assets/backwards.svg';
|
import BackwardIcon from 'assets/backwards.svg';
|
||||||
import PlayIcon from 'assets/play.svg';
|
import PlayIcon from 'assets/play.svg';
|
||||||
import PauseIcon from 'assets/pause.svg';
|
import PauseIcon from 'assets/pause.svg';
|
||||||
|
import RepeatIcon from 'assets/repeat.svg';
|
||||||
|
// import ShuffleIcon from 'assets/shuffle.svg';
|
||||||
import { useColorScheme } from 'react-native-appearance';
|
import { useColorScheme } from 'react-native-appearance';
|
||||||
|
import { THEME_COLOR } from 'CONSTANTS';
|
||||||
|
|
||||||
const BUTTON_SIZE = 40;
|
const BUTTON_SIZE = 40;
|
||||||
|
const BUTTON_SIZE_SMALL = 25;
|
||||||
|
|
||||||
const pause = () => TrackPlayer.pause();
|
const pause = () => TrackPlayer.pause();
|
||||||
const play = () => TrackPlayer.play();
|
const play = () => TrackPlayer.play();
|
||||||
@@ -47,6 +51,14 @@ export default function MediaControls() {
|
|||||||
<NextButton fill={fill} />
|
<NextButton fill={fill} />
|
||||||
</Button>
|
</Button>
|
||||||
</Buttons>
|
</Buttons>
|
||||||
|
<Buttons>
|
||||||
|
<Button>
|
||||||
|
<RepeatButton fill={fill} />
|
||||||
|
</Button>
|
||||||
|
<Button>
|
||||||
|
{/* <ShuffleButton fill={fill} /> */}
|
||||||
|
</Button>
|
||||||
|
</Buttons>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -71,6 +83,67 @@ export function NextButton({ fill }: { fill: string }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function RepeatButton({ fill }: { fill: string}) {
|
||||||
|
const [isRepeating, setRepeating] = useState(false);
|
||||||
|
const handlePress = useCallback(() => setRepeating(!isRepeating), [isRepeating, setRepeating]);
|
||||||
|
const listener = useRef<TrackPlayer.EmitterSubscription | null>(null);
|
||||||
|
|
||||||
|
// The callback that should determine whether we need to repeeat or not
|
||||||
|
const handleEndEvent = useCallback(async () => {
|
||||||
|
if (isRepeating) {
|
||||||
|
// Retrieve all current tracks
|
||||||
|
const tracks = await TrackPlayer.getQueue();
|
||||||
|
|
||||||
|
// Then skip to the first track
|
||||||
|
await TrackPlayer.skip(tracks[0].id);
|
||||||
|
|
||||||
|
// Cautiously reset the seek time, as there might only be a single
|
||||||
|
// item in queue.
|
||||||
|
await TrackPlayer.seekTo(0);
|
||||||
|
|
||||||
|
// Then play the item
|
||||||
|
await TrackPlayer.play();
|
||||||
|
}
|
||||||
|
}, [isRepeating]);
|
||||||
|
|
||||||
|
// Subscribe to ended event handler so that we can restart the queue from
|
||||||
|
// the start if looping is enabled
|
||||||
|
useEffect(() => {
|
||||||
|
// Set the event listener
|
||||||
|
listener.current = TrackPlayer.addEventListener('playback-queue-ended', handleEndEvent);
|
||||||
|
|
||||||
|
// Then clean up after
|
||||||
|
return function cleanup() {
|
||||||
|
listener?.current?.remove();
|
||||||
|
};
|
||||||
|
}, [handleEndEvent]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TouchableOpacity onPress={handlePress} style={{ opacity: isRepeating ? 1 : 0.5 }}>
|
||||||
|
<RepeatIcon
|
||||||
|
width={BUTTON_SIZE_SMALL}
|
||||||
|
height={BUTTON_SIZE_SMALL}
|
||||||
|
fill={isRepeating ? THEME_COLOR : fill}
|
||||||
|
/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// export function ShuffleButton({ fill }: { fill: string}) {
|
||||||
|
// const [isShuffling, setShuffling] = useState(false);
|
||||||
|
// const handlePress = useCallback(() => setShuffling(!isShuffling), [isShuffling, setShuffling]);
|
||||||
|
|
||||||
|
// return (
|
||||||
|
// <TouchableOpacity onPress={handlePress} style={{ opacity: isShuffling ? 1 : 0.5 }}>
|
||||||
|
// <ShuffleIcon
|
||||||
|
// width={BUTTON_SIZE_SMALL}
|
||||||
|
// height={BUTTON_SIZE_SMALL}
|
||||||
|
// fill={isShuffling ? THEME_COLOR : fill}
|
||||||
|
// />
|
||||||
|
// </TouchableOpacity>
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
export function MainButton({ fill }: { fill: string }) {
|
export function MainButton({ fill }: { fill: string }) {
|
||||||
const state = usePlaybackState();
|
const state = usePlaybackState();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user