impl repeat mode

fix position not being restored on close/open due to some bad progress updates
This commit is contained in:
austinried 2021-08-04 22:15:16 +09:00
parent a0b49ec75f
commit 9dc1ac451c
4 changed files with 75 additions and 18 deletions

View File

@ -1,15 +1,23 @@
import { useStore } from '@app/state/store'
import { selectTrackPlayer } from '@app/state/trackplayer'
import React, { useEffect } from 'react'
import { useProgress } from 'react-native-track-player'
import { State, useProgress } from 'react-native-track-player'
const ProgressHook = () => {
const playerState = useStore(selectTrackPlayer.playerState)
const setProgress = useStore(selectTrackPlayer.setProgress)
const progress = useProgress(250)
useEffect(() => {
if (playerState !== State.Playing) {
return
}
if (progress.buffered === 0 && progress.duration === 0 && progress.position === 0) {
return
}
setProgress(progress)
}, [setProgress, progress])
}, [setProgress, progress, playerState])
return <></>
}

View File

@ -1,9 +1,16 @@
import { useCoverArtUri } from '@app/hooks/music'
import { Song } from '@app/models/music'
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 TrackPlayer from 'react-native-track-player'
import TrackPlayer, { RepeatMode } from 'react-native-track-player'
export const usePlay = () => {
return () => trackPlayerCommands.enqueue(() => TrackPlayer.play())
@ -14,14 +21,11 @@ export const usePause = () => {
}
export const usePrevious = () => {
// const setCurrentTrackIdx = useStore(selectTrackPlayer.setCurrentTrackIdx)
return () =>
trackPlayerCommands.enqueue(async () => {
const [current] = await Promise.all([await TrackPlayer.getCurrentTrack(), await getQueue()])
if (current > 0) {
await TrackPlayer.skipToPrevious()
// setCurrentTrackIdx(current - 1)
} else {
await TrackPlayer.seekTo(0)
}
@ -30,23 +34,44 @@ export const usePrevious = () => {
}
export const useNext = () => {
// const setCurrentTrack = useUpdateAtom(currentTrackAtom)
return () =>
trackPlayerCommands.enqueue(async () => {
const [current, queue] = await Promise.all([await TrackPlayer.getCurrentTrack(), await getQueue()])
if (current >= queue.length - 1) {
await TrackPlayer.skip(0)
await TrackPlayer.pause()
// setCurrentTrack(queue[0])
} else {
await TrackPlayer.skipToNext()
// setCurrentTrack(queue[current + 1])
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) => {
const resetStore = useStore(selectTrackPlayer.reset)

View File

@ -1,6 +1,6 @@
import React, { useCallback, useEffect } from 'react'
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 IconFA5 from 'react-native-vector-icons/FontAwesome5'
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 { useStore } from '@app/state/store'
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<{
backHandler: () => void
@ -201,6 +201,8 @@ const PlayerControls = () => {
const previous = usePrevious()
const shuffled = useStore(selectTrackPlayer.shuffled)
const toggleShuffle = useToggleShuffle()
const repeatMode = useStore(selectTrackPlayer.repeatMode)
const toggleRepeat = useToggleRepeat()
let playPauseIcon: string
let playPauseAction: undefined | (() => void)
@ -225,8 +227,9 @@ const PlayerControls = () => {
<View style={controlsStyles.container}>
<View style={controlsStyles.top}>
<View style={controlsStyles.center}>
<PressableOpacity onPress={undefined} disabled={disabled}>
<Icon name="repeat" size={26} color="white" />
<PressableOpacity onPress={() => toggleRepeat()} disabled={disabled}>
<Icon name="repeat" size={26} color={repeatMode === RepeatMode.Off ? 'white' : colors.accent} />
<Text style={[controlsStyles.repeatExt, repeatMode === RepeatMode.Track ? { opacity: 1 } : {}]}>1</Text>
</PressableOpacity>
</View>
@ -285,6 +288,14 @@ const controlsStyles = StyleSheet.create({
alignItems: 'center',
justifyContent: 'center',
},
repeatExt: {
color: colors.accent,
fontFamily: font.bold,
fontSize: 14,
position: 'absolute',
top: 26,
opacity: 0,
},
})
type RootStackParamList = {

View File

@ -1,6 +1,6 @@
import PromiseQueue from '@app/util/PromiseQueue'
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 { Store } from './store'
@ -22,6 +22,9 @@ export type TrackPlayerSlice = {
shuffleOrder?: number[]
setShuffleOrder: (shuffleOrder?: number[]) => void
repeatMode: RepeatMode
setRepeatMode: (repeatMode: RepeatMode) => void
playerState: State
setPlayerState: (playerState: State) => void
@ -48,6 +51,9 @@ export const selectTrackPlayer = {
setShuffleOrder: (store: TrackPlayerSlice) => store.setShuffleOrder,
shuffled: (store: TrackPlayerSlice) => !!store.shuffleOrder,
repeatMode: (store: TrackPlayerSlice) => store.repeatMode,
setRepeatMode: (store: TrackPlayerSlice) => store.setRepeatMode,
playerState: (store: TrackPlayerSlice) => store.playerState,
setPlayerState: (store: TrackPlayerSlice) => store.setPlayerState,
@ -75,6 +81,9 @@ export const createTrackPlayerSlice = (set: SetState<Store>, get: GetState<Store
shuffleOrder: undefined,
setShuffleOrder: shuffleOrder => set({ shuffleOrder }),
repeatMode: RepeatMode.Off,
setRepeatMode: repeatMode => set({ repeatMode }),
playerState: State.None,
setPlayerState: playerState => set({ playerState }),
@ -114,6 +123,7 @@ export const createTrackPlayerSlice = (set: SetState<Store>, get: GetState<Store
set({
name: undefined,
shuffleOrder: undefined,
repeatMode: RepeatMode.Off,
playerState: State.None,
currentTrack: undefined,
currentTrackIdx: undefined,
@ -133,6 +143,9 @@ export const getCurrentTrack = async (): Promise<number | undefined> => {
}
export const getPlayerState = async (): Promise<State> => {
const state = await TrackPlayer.getState()
return state || State.None
return (await TrackPlayer.getState()) || State.None
}
export const getRepeatMode = async (): Promise<RepeatMode> => {
return (await TrackPlayer.getRepeatMode()) || RepeatMode.Off
}