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 (