mirror of
https://github.com/austinried/subtracks.git
synced 2025-12-29 17:39:27 +01:00
impl repeat mode
fix position not being restored on close/open due to some bad progress updates
This commit is contained in:
parent
a0b49ec75f
commit
9dc1ac451c
@ -1,15 +1,23 @@
|
|||||||
import { useStore } from '@app/state/store'
|
import { useStore } from '@app/state/store'
|
||||||
import { selectTrackPlayer } from '@app/state/trackplayer'
|
import { selectTrackPlayer } from '@app/state/trackplayer'
|
||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import { useProgress } from 'react-native-track-player'
|
import { State, useProgress } from 'react-native-track-player'
|
||||||
|
|
||||||
const ProgressHook = () => {
|
const ProgressHook = () => {
|
||||||
|
const playerState = useStore(selectTrackPlayer.playerState)
|
||||||
const setProgress = useStore(selectTrackPlayer.setProgress)
|
const setProgress = useStore(selectTrackPlayer.setProgress)
|
||||||
const progress = useProgress(250)
|
const progress = useProgress(250)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (playerState !== State.Playing) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (progress.buffered === 0 && progress.duration === 0 && progress.position === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
setProgress(progress)
|
setProgress(progress)
|
||||||
}, [setProgress, progress])
|
}, [setProgress, progress, playerState])
|
||||||
|
|
||||||
return <></>
|
return <></>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,16 @@
|
|||||||
import { useCoverArtUri } from '@app/hooks/music'
|
import { useCoverArtUri } from '@app/hooks/music'
|
||||||
import { Song } from '@app/models/music'
|
import { Song } from '@app/models/music'
|
||||||
import { useStore } from '@app/state/store'
|
import { useStore } from '@app/state/store'
|
||||||
import { getCurrentTrack, getQueue, selectTrackPlayer, TrackExt, trackPlayerCommands } from '@app/state/trackplayer'
|
import {
|
||||||
|
getCurrentTrack,
|
||||||
|
getQueue,
|
||||||
|
getRepeatMode,
|
||||||
|
selectTrackPlayer,
|
||||||
|
TrackExt,
|
||||||
|
trackPlayerCommands,
|
||||||
|
} from '@app/state/trackplayer'
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
import TrackPlayer from 'react-native-track-player'
|
import TrackPlayer, { RepeatMode } from 'react-native-track-player'
|
||||||
|
|
||||||
export const usePlay = () => {
|
export const usePlay = () => {
|
||||||
return () => trackPlayerCommands.enqueue(() => TrackPlayer.play())
|
return () => trackPlayerCommands.enqueue(() => TrackPlayer.play())
|
||||||
@ -14,14 +21,11 @@ export const usePause = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const usePrevious = () => {
|
export const usePrevious = () => {
|
||||||
// const setCurrentTrackIdx = useStore(selectTrackPlayer.setCurrentTrackIdx)
|
|
||||||
|
|
||||||
return () =>
|
return () =>
|
||||||
trackPlayerCommands.enqueue(async () => {
|
trackPlayerCommands.enqueue(async () => {
|
||||||
const [current] = await Promise.all([await TrackPlayer.getCurrentTrack(), await getQueue()])
|
const [current] = await Promise.all([await TrackPlayer.getCurrentTrack(), await getQueue()])
|
||||||
if (current > 0) {
|
if (current > 0) {
|
||||||
await TrackPlayer.skipToPrevious()
|
await TrackPlayer.skipToPrevious()
|
||||||
// setCurrentTrackIdx(current - 1)
|
|
||||||
} else {
|
} else {
|
||||||
await TrackPlayer.seekTo(0)
|
await TrackPlayer.seekTo(0)
|
||||||
}
|
}
|
||||||
@ -30,23 +34,44 @@ export const usePrevious = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const useNext = () => {
|
export const useNext = () => {
|
||||||
// const setCurrentTrack = useUpdateAtom(currentTrackAtom)
|
|
||||||
|
|
||||||
return () =>
|
return () =>
|
||||||
trackPlayerCommands.enqueue(async () => {
|
trackPlayerCommands.enqueue(async () => {
|
||||||
const [current, queue] = await Promise.all([await TrackPlayer.getCurrentTrack(), await getQueue()])
|
const [current, queue] = await Promise.all([await TrackPlayer.getCurrentTrack(), await getQueue()])
|
||||||
if (current >= queue.length - 1) {
|
if (current >= queue.length - 1) {
|
||||||
await TrackPlayer.skip(0)
|
await TrackPlayer.skip(0)
|
||||||
await TrackPlayer.pause()
|
await TrackPlayer.pause()
|
||||||
// setCurrentTrack(queue[0])
|
|
||||||
} else {
|
} else {
|
||||||
await TrackPlayer.skipToNext()
|
await TrackPlayer.skipToNext()
|
||||||
// setCurrentTrack(queue[current + 1])
|
|
||||||
await TrackPlayer.play()
|
await TrackPlayer.play()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const useToggleRepeat = () => {
|
||||||
|
const setRepeatMode = useStore(selectTrackPlayer.setRepeatMode)
|
||||||
|
|
||||||
|
return () =>
|
||||||
|
trackPlayerCommands.enqueue(async () => {
|
||||||
|
const repeatMode = await getRepeatMode()
|
||||||
|
let nextMode = RepeatMode.Off
|
||||||
|
|
||||||
|
switch (repeatMode) {
|
||||||
|
case RepeatMode.Off:
|
||||||
|
nextMode = RepeatMode.Queue
|
||||||
|
break
|
||||||
|
case RepeatMode.Queue:
|
||||||
|
nextMode = RepeatMode.Track
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
nextMode = RepeatMode.Off
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
await TrackPlayer.setRepeatMode(nextMode)
|
||||||
|
setRepeatMode(nextMode)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export const useReset = (enqueue = true) => {
|
export const useReset = (enqueue = true) => {
|
||||||
const resetStore = useStore(selectTrackPlayer.reset)
|
const resetStore = useStore(selectTrackPlayer.reset)
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { useCallback, useEffect } from 'react'
|
import React, { useCallback, useEffect } from 'react'
|
||||||
import { BackHandler, StatusBar, StyleSheet, Text, View } from 'react-native'
|
import { BackHandler, StatusBar, StyleSheet, Text, View } from 'react-native'
|
||||||
import { State } from 'react-native-track-player'
|
import { RepeatMode, State } from 'react-native-track-player'
|
||||||
import IconFA from 'react-native-vector-icons/FontAwesome'
|
import IconFA from 'react-native-vector-icons/FontAwesome'
|
||||||
import IconFA5 from 'react-native-vector-icons/FontAwesome5'
|
import IconFA5 from 'react-native-vector-icons/FontAwesome5'
|
||||||
import Icon from 'react-native-vector-icons/Ionicons'
|
import Icon from 'react-native-vector-icons/Ionicons'
|
||||||
@ -17,7 +17,7 @@ import { NativeStackScreenProps } from 'react-native-screens/native-stack'
|
|||||||
import { useFocusEffect } from '@react-navigation/native'
|
import { useFocusEffect } from '@react-navigation/native'
|
||||||
import { useStore } from '@app/state/store'
|
import { useStore } from '@app/state/store'
|
||||||
import { selectTrackPlayer } from '@app/state/trackplayer'
|
import { selectTrackPlayer } from '@app/state/trackplayer'
|
||||||
import { useNext, usePause, usePlay, usePrevious, useToggleShuffle } from '@app/hooks/trackplayer'
|
import { useNext, usePause, usePlay, usePrevious, useToggleRepeat, useToggleShuffle } from '@app/hooks/trackplayer'
|
||||||
|
|
||||||
const NowPlayingHeader = React.memo<{
|
const NowPlayingHeader = React.memo<{
|
||||||
backHandler: () => void
|
backHandler: () => void
|
||||||
@ -201,6 +201,8 @@ const PlayerControls = () => {
|
|||||||
const previous = usePrevious()
|
const previous = usePrevious()
|
||||||
const shuffled = useStore(selectTrackPlayer.shuffled)
|
const shuffled = useStore(selectTrackPlayer.shuffled)
|
||||||
const toggleShuffle = useToggleShuffle()
|
const toggleShuffle = useToggleShuffle()
|
||||||
|
const repeatMode = useStore(selectTrackPlayer.repeatMode)
|
||||||
|
const toggleRepeat = useToggleRepeat()
|
||||||
|
|
||||||
let playPauseIcon: string
|
let playPauseIcon: string
|
||||||
let playPauseAction: undefined | (() => void)
|
let playPauseAction: undefined | (() => void)
|
||||||
@ -225,8 +227,9 @@ const PlayerControls = () => {
|
|||||||
<View style={controlsStyles.container}>
|
<View style={controlsStyles.container}>
|
||||||
<View style={controlsStyles.top}>
|
<View style={controlsStyles.top}>
|
||||||
<View style={controlsStyles.center}>
|
<View style={controlsStyles.center}>
|
||||||
<PressableOpacity onPress={undefined} disabled={disabled}>
|
<PressableOpacity onPress={() => toggleRepeat()} disabled={disabled}>
|
||||||
<Icon name="repeat" size={26} color="white" />
|
<Icon name="repeat" size={26} color={repeatMode === RepeatMode.Off ? 'white' : colors.accent} />
|
||||||
|
<Text style={[controlsStyles.repeatExt, repeatMode === RepeatMode.Track ? { opacity: 1 } : {}]}>1</Text>
|
||||||
</PressableOpacity>
|
</PressableOpacity>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
@ -285,6 +288,14 @@ const controlsStyles = StyleSheet.create({
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
},
|
},
|
||||||
|
repeatExt: {
|
||||||
|
color: colors.accent,
|
||||||
|
fontFamily: font.bold,
|
||||||
|
fontSize: 14,
|
||||||
|
position: 'absolute',
|
||||||
|
top: 26,
|
||||||
|
opacity: 0,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
type RootStackParamList = {
|
type RootStackParamList = {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import PromiseQueue from '@app/util/PromiseQueue'
|
import PromiseQueue from '@app/util/PromiseQueue'
|
||||||
import produce from 'immer'
|
import produce from 'immer'
|
||||||
import TrackPlayer, { State, Track } from 'react-native-track-player'
|
import TrackPlayer, { RepeatMode, State, Track } from 'react-native-track-player'
|
||||||
import { GetState, SetState } from 'zustand'
|
import { GetState, SetState } from 'zustand'
|
||||||
import { Store } from './store'
|
import { Store } from './store'
|
||||||
|
|
||||||
@ -22,6 +22,9 @@ export type TrackPlayerSlice = {
|
|||||||
shuffleOrder?: number[]
|
shuffleOrder?: number[]
|
||||||
setShuffleOrder: (shuffleOrder?: number[]) => void
|
setShuffleOrder: (shuffleOrder?: number[]) => void
|
||||||
|
|
||||||
|
repeatMode: RepeatMode
|
||||||
|
setRepeatMode: (repeatMode: RepeatMode) => void
|
||||||
|
|
||||||
playerState: State
|
playerState: State
|
||||||
setPlayerState: (playerState: State) => void
|
setPlayerState: (playerState: State) => void
|
||||||
|
|
||||||
@ -48,6 +51,9 @@ export const selectTrackPlayer = {
|
|||||||
setShuffleOrder: (store: TrackPlayerSlice) => store.setShuffleOrder,
|
setShuffleOrder: (store: TrackPlayerSlice) => store.setShuffleOrder,
|
||||||
shuffled: (store: TrackPlayerSlice) => !!store.shuffleOrder,
|
shuffled: (store: TrackPlayerSlice) => !!store.shuffleOrder,
|
||||||
|
|
||||||
|
repeatMode: (store: TrackPlayerSlice) => store.repeatMode,
|
||||||
|
setRepeatMode: (store: TrackPlayerSlice) => store.setRepeatMode,
|
||||||
|
|
||||||
playerState: (store: TrackPlayerSlice) => store.playerState,
|
playerState: (store: TrackPlayerSlice) => store.playerState,
|
||||||
setPlayerState: (store: TrackPlayerSlice) => store.setPlayerState,
|
setPlayerState: (store: TrackPlayerSlice) => store.setPlayerState,
|
||||||
|
|
||||||
@ -75,6 +81,9 @@ export const createTrackPlayerSlice = (set: SetState<Store>, get: GetState<Store
|
|||||||
shuffleOrder: undefined,
|
shuffleOrder: undefined,
|
||||||
setShuffleOrder: shuffleOrder => set({ shuffleOrder }),
|
setShuffleOrder: shuffleOrder => set({ shuffleOrder }),
|
||||||
|
|
||||||
|
repeatMode: RepeatMode.Off,
|
||||||
|
setRepeatMode: repeatMode => set({ repeatMode }),
|
||||||
|
|
||||||
playerState: State.None,
|
playerState: State.None,
|
||||||
setPlayerState: playerState => set({ playerState }),
|
setPlayerState: playerState => set({ playerState }),
|
||||||
|
|
||||||
@ -114,6 +123,7 @@ export const createTrackPlayerSlice = (set: SetState<Store>, get: GetState<Store
|
|||||||
set({
|
set({
|
||||||
name: undefined,
|
name: undefined,
|
||||||
shuffleOrder: undefined,
|
shuffleOrder: undefined,
|
||||||
|
repeatMode: RepeatMode.Off,
|
||||||
playerState: State.None,
|
playerState: State.None,
|
||||||
currentTrack: undefined,
|
currentTrack: undefined,
|
||||||
currentTrackIdx: undefined,
|
currentTrackIdx: undefined,
|
||||||
@ -133,6 +143,9 @@ export const getCurrentTrack = async (): Promise<number | undefined> => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const getPlayerState = async (): Promise<State> => {
|
export const getPlayerState = async (): Promise<State> => {
|
||||||
const state = await TrackPlayer.getState()
|
return (await TrackPlayer.getState()) || State.None
|
||||||
return state || State.None
|
}
|
||||||
|
|
||||||
|
export const getRepeatMode = async (): Promise<RepeatMode> => {
|
||||||
|
return (await TrackPlayer.getRepeatMode()) || RepeatMode.Off
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user