From df3e913125a02a21e18f6e43de08133969726d8a Mon Sep 17 00:00:00 2001 From: austinried <4966622+austinried@users.noreply.github.com> Date: Tue, 10 Aug 2021 11:15:57 +0900 Subject: [PATCH] basic queue with skipTo support --- app/hooks/trackplayer.ts | 29 ++++++++++++++--- app/navigation/RootNavigator.tsx | 43 +++++++++++++++++-------- app/screens/NowPlayingQueue.tsx | 48 ++++++++++++++++++++++++++++ app/screens/NowPlayingView.tsx | 54 +++++++++++++------------------- 4 files changed, 124 insertions(+), 50 deletions(-) create mode 100644 app/screens/NowPlayingQueue.tsx diff --git a/app/hooks/trackplayer.ts b/app/hooks/trackplayer.ts index 17dde8b..f4c2f50 100644 --- a/app/hooks/trackplayer.ts +++ b/app/hooks/trackplayer.ts @@ -47,6 +47,18 @@ export const useNext = () => { }) } +export const useSkipTo = () => { + return (track: number) => + trackPlayerCommands.enqueue(async () => { + const queue = await getQueue() + if (track < 0 || track >= queue.length) { + return + } + await TrackPlayer.skip(track) + await TrackPlayer.play() + }) +} + export const useToggleRepeat = () => { const setRepeatMode = useStore(selectTrackPlayer.setRepeatMode) @@ -209,10 +221,6 @@ export const useSetQueue = () => { await TrackPlayer.add(tracks1, 0) } - - // setQueue(await getQueue()) - // setCurrentTrackIdx(playTrack) - // setQueueName(name) }) } @@ -228,3 +236,16 @@ function mapSongToTrack(song: Song, coverArtUri: (coverArt?: string) => string | duration: song.duration, } } + +export function mapTrackExtToSong(track: TrackExt): Song { + return { + itemType: 'song', + id: track.id, + title: track.title as string, + artist: track.artist, + album: track.album, + streamUri: track.url as string, + coverArt: track.coverArt, + duration: track.duration, + } +} diff --git a/app/navigation/RootNavigator.tsx b/app/navigation/RootNavigator.tsx index 4e56b28..274254d 100644 --- a/app/navigation/RootNavigator.tsx +++ b/app/navigation/RootNavigator.tsx @@ -1,10 +1,37 @@ import BottomTabNavigator from '@app/navigation/BottomTabNavigator' +import NowPlayingQueue from '@app/screens/NowPlayingQueue' import NowPlayingView from '@app/screens/NowPlayingView' import colors from '@app/styles/colors' +import font from '@app/styles/font' import { DarkTheme, NavigationContainer } from '@react-navigation/native' import React from 'react' import { createNativeStackNavigator } from 'react-native-screens/native-stack' +const NowPlayingStack = createNativeStackNavigator() + +const NowPlayingNavigator = () => ( + + + + +) + const RootStack = createNativeStackNavigator() const theme = { ...DarkTheme } @@ -15,24 +42,14 @@ const RootNavigator = () => ( theme={theme} linking={{ prefixes: ['trackplayer'], - config: { - screens: { - main: { - path: ':/main', - }, - 'now-playing': { - path: ':/notification.click', - }, - }, - }, }}> - - + initialRouteName="top"> + + ) diff --git a/app/screens/NowPlayingQueue.tsx b/app/screens/NowPlayingQueue.tsx new file mode 100644 index 0000000..d89e01e --- /dev/null +++ b/app/screens/NowPlayingQueue.tsx @@ -0,0 +1,48 @@ +import GradientScrollView from '@app/components/GradientScrollView' +import ListItem from '@app/components/ListItem' +import NowPlayingBar from '@app/components/NowPlayingBar' +import { mapTrackExtToSong, useSkipTo } from '@app/hooks/trackplayer' +import { useStore } from '@app/state/store' +import { selectTrackPlayer } from '@app/state/trackplayer' +import React from 'react' +import { StyleSheet, View } from 'react-native' + +const NowPlayingQueue = React.memo<{}>(() => { + const queue = useStore(selectTrackPlayer.queue) + const skipTo = useSkipTo() + + return ( + + + + {queue.map(mapTrackExtToSong).map((song, i) => ( + skipTo(i)} + showArt={true} + subtitle={`${song.artist} • ${song.album}`} + /> + ))} + + + + + ) +}) + +const styles = StyleSheet.create({ + outerContainer: { + flex: 1, + }, + container: { + flex: 1, + }, + content: { + alignItems: 'center', + paddingTop: 10, + paddingHorizontal: 20, + }, +}) + +export default NowPlayingQueue diff --git a/app/screens/NowPlayingView.tsx b/app/screens/NowPlayingView.tsx index 9a94a09..8161c29 100644 --- a/app/screens/NowPlayingView.tsx +++ b/app/screens/NowPlayingView.tsx @@ -1,26 +1,26 @@ +import CoverArt from '@app/components/CoverArt' +import ImageGradientBackground from '@app/components/ImageGradientBackground' +import PressableOpacity from '@app/components/PressableOpacity' +import Star from '@app/components/Star' +import { useStarred } from '@app/hooks/music' +import { useNext, usePause, usePlay, usePrevious, useToggleRepeat, useToggleShuffle } from '@app/hooks/trackplayer' +import { selectMusic } from '@app/state/music' +import { useStore } from '@app/state/store' +import { selectTrackPlayer } from '@app/state/trackplayer' +import colors from '@app/styles/colors' +import dimensions from '@app/styles/dimensions' +import font from '@app/styles/font' +import formatDuration from '@app/util/formatDuration' +import { useNavigation } from '@react-navigation/native' import React, { useCallback, useEffect } from 'react' -import { BackHandler, StatusBar, StyleSheet, Text, View } from 'react-native' +import { StatusBar, StyleSheet, Text, View } from 'react-native' +import { NativeStackScreenProps } from 'react-native-screens/native-stack' import { RepeatMode, State } from 'react-native-track-player' import IconFA from 'react-native-vector-icons/FontAwesome' import IconFA5 from 'react-native-vector-icons/FontAwesome5' import Icon from 'react-native-vector-icons/Ionicons' import IconMatCom from 'react-native-vector-icons/MaterialCommunityIcons' import IconMat from 'react-native-vector-icons/MaterialIcons' -import colors from '@app/styles/colors' -import font from '@app/styles/font' -import formatDuration from '@app/util/formatDuration' -import CoverArt from '@app/components/CoverArt' -import ImageGradientBackground from '@app/components/ImageGradientBackground' -import PressableOpacity from '@app/components/PressableOpacity' -import dimensions from '@app/styles/dimensions' -import { NativeStackScreenProps } from 'react-native-screens/native-stack' -import { useFocusEffect } from '@react-navigation/native' -import { useStore } from '@app/state/store' -import { selectTrackPlayer } from '@app/state/trackplayer' -import { useNext, usePause, usePlay, usePrevious, useToggleRepeat, useToggleShuffle } from '@app/hooks/trackplayer' -import Star from '@app/components/Star' -import { useStarred } from '@app/hooks/music' -import { selectMusic } from '@app/state/music' const NowPlayingHeader = React.memo<{ backHandler: () => void @@ -210,6 +210,7 @@ const PlayerControls = () => { const toggleShuffle = useToggleShuffle() const repeatMode = useStore(selectTrackPlayer.repeatMode) const toggleRepeat = useToggleRepeat() + const navigation = useNavigation() let playPauseIcon: string let playPauseAction: undefined | (() => void) @@ -262,7 +263,7 @@ const PlayerControls = () => { - + navigation.navigate('queue')} disabled={disabled}> @@ -306,21 +307,16 @@ const controlsStyles = StyleSheet.create({ }) type RootStackParamList = { + top: undefined main: undefined - 'now-playing': undefined } -type NowPlayingProps = NativeStackScreenProps +type NowPlayingProps = NativeStackScreenProps const NowPlayingView: React.FC = ({ navigation }) => { const track = useStore(selectTrackPlayer.currentTrack) const back = useCallback(() => { - if (navigation.canGoBack()) { - navigation.popToTop() - } else { - navigation.navigate('main') - } - return true + navigation.navigate('top') }, [navigation]) useEffect(() => { @@ -329,14 +325,6 @@ const NowPlayingView: React.FC = ({ navigation }) => { } }) - useFocusEffect( - useCallback(() => { - BackHandler.addEventListener('hardwareBackPress', back) - - return () => BackHandler.removeEventListener('hardwareBackPress', back) - }, [back]), - ) - return (