fixed progress hook with my own state wrap/update

This commit is contained in:
austinried 2021-07-06 21:39:00 +09:00
parent b5473ee568
commit 49b5ce3f6c
3 changed files with 131 additions and 9 deletions

View File

@ -2,8 +2,15 @@ import { useAtomValue } from 'jotai/utils'
import React from 'react'
import { StatusBar, StyleSheet, Text, useWindowDimensions, View } from 'react-native'
import FastImage from 'react-native-fast-image'
import TrackPlayer, { State, useProgress } from 'react-native-track-player'
import { queueNameAtom, currentTrackAtom, playerStateAtom, useNext, usePrevious } from '../state/trackplayer'
import TrackPlayer, { State } from 'react-native-track-player'
import {
queueNameAtom,
currentTrackAtom,
playerStateAtom,
useNext,
usePrevious,
useProgress,
} from '../state/trackplayer'
import colors from '../styles/colors'
import text, { Font } from '../styles/text'
import { formatDuration } from '../util'
@ -100,7 +107,7 @@ const infoStyles = StyleSheet.create({
})
const SeekBar = () => {
const { position, duration } = useProgress(250)
const { position, duration } = useProgress()
let progress = 0
if (duration > 0) {

View File

@ -2,12 +2,16 @@ import { useAppState } from '@react-native-community/hooks'
import { useAtomValue, useUpdateAtom } from 'jotai/utils'
import React, { useEffect } from 'react'
import { View } from 'react-native'
import TrackPlayer, { Event, State, useTrackPlayerEvents } from 'react-native-track-player'
import { Event, State, useProgress, useTrackPlayerEvents } from 'react-native-track-player'
import {
currentTrackAtom,
playerStateAtom,
progressAtom,
progressSubsAtom,
queueWriteAtom,
useRefreshCurrentTrack,
useRefreshPlayerState,
useRefreshProgress,
useRefreshQueue,
} from '../state/trackplayer'
@ -67,13 +71,14 @@ const CurrentTrackState = () => {
const PlayerState = () => {
const setPlayerState = useUpdateAtom(playerStateAtom)
const refreshPlayerState = useRefreshPlayerState()
const update = async (payload?: Payload) => {
if (payload?.type === Event.RemoteStop) {
setPlayerState(State.None)
return
}
setPlayerState(payload?.state || (await TrackPlayer.getState()))
await refreshPlayerState()
}
return <TrackPlayerEventResponder events={[Event.PlaybackState, Event.RemoteStop]} update={update} />
@ -94,6 +99,41 @@ const QueueState = () => {
return <TrackPlayerEventResponder events={[Event.RemoteStop]} update={update} />
}
const ProgressHook = () => {
const setProgress = useUpdateAtom(progressAtom)
const progress = useProgress(250)
useEffect(() => {
setProgress(progress)
}, [setProgress, progress])
return <></>
}
const ProgressState = () => {
const setProgress = useUpdateAtom(progressAtom)
const refreshProgress = useRefreshProgress()
const progressSubs = useAtomValue(progressSubsAtom)
const update = async (payload?: Payload) => {
if (payload) {
setProgress({ position: 0, duration: 0, buffered: 0 })
return
}
await refreshProgress()
}
if (progressSubs > 0) {
return (
<>
<ProgressHook />
<TrackPlayerEventResponder events={[Event.RemoteStop]} update={update} />
</>
)
}
return <TrackPlayerEventResponder events={[Event.RemoteStop]} update={update} />
}
const Debug = () => {
const value = useAtomValue(currentTrackAtom)
@ -109,6 +149,7 @@ const TrackPlayerState = () => (
<CurrentTrackState />
<PlayerState />
<QueueState />
<ProgressState />
<Debug />
</View>
)

View File

@ -1,7 +1,8 @@
import { atom } from 'jotai'
import TrackPlayer, { State, Track } from 'react-native-track-player'
import equal from 'fast-deep-equal'
import { useUpdateAtom } from 'jotai/utils'
import { atom } from 'jotai'
import { useAtomValue, useUpdateAtom } from 'jotai/utils'
import { useEffect } from 'react'
import TrackPlayer, { State, Track } from 'react-native-track-player'
import { Song } from '../models/music'
import { PromiseQueue } from '../util'
@ -12,6 +13,12 @@ type TrackExt = Track & {
type OptionalTrackExt = TrackExt | undefined
type Progress = {
position: number
duration: number
buffered: number
}
const playerState = atom<State>(State.None)
export const playerStateAtom = atom<State, State>(
get => get(playerState),
@ -33,7 +40,7 @@ export const currentTrackAtom = atom<OptionalTrackExt, OptionalTrackExt>(
)
const _queue = atom<TrackExt[]>([])
export const queueAtom = atom<TrackExt[]>(get => get(_queue))
export const queueReadAtom = atom<TrackExt[]>(get => get(_queue))
export const queueWriteAtom = atom<TrackExt[], TrackExt[]>(
get => get(_queue),
(get, set, update) => {
@ -51,6 +58,25 @@ export const queueNameAtom = atom<string | undefined>(get => {
return undefined
})
const _progress = atom<Progress>({ position: 0, duration: 0, buffered: 0 })
export const progressAtom = atom<Progress, Progress>(
get => get(_progress),
(get, set, update) => {
if (!equal(get(_progress), update)) {
set(_progress, update)
}
},
)
const progressSubs = atom(0)
export const progressSubsAtom = atom(get => get(progressSubs))
const addProgressSub = atom(null, (get, set) => {
set(progressSubs, get(progressSubs) + 1)
})
const removeProgressSub = atom(null, (get, set) => {
set(progressSubs, get(progressSubs) - 1)
})
const trackPlayerCommands = new PromiseQueue(1)
const getQueue = async (): Promise<TrackExt[]> => {
@ -61,6 +87,23 @@ const getTrack = async (index: number): Promise<TrackExt> => {
return ((await TrackPlayer.getTrack(index)) as TrackExt) || undefined
}
const getPlayerState = async (): Promise<State> => {
return (await TrackPlayer.getState()) || State.None
}
const getProgress = async (): Promise<Progress> => {
const [position, duration, buffered] = await Promise.all([
TrackPlayer.getPosition(),
TrackPlayer.getDuration(),
TrackPlayer.getBufferedPosition(),
])
return {
position: position || 0,
duration: duration || 0,
buffered: buffered || 0,
}
}
export const useRefreshQueue = () => {
const setQueue = useUpdateAtom(queueWriteAtom)
@ -84,6 +127,24 @@ export const useRefreshCurrentTrack = () => {
})
}
export const useRefreshPlayerState = () => {
const setPlayerState = useUpdateAtom(playerStateAtom)
return () =>
trackPlayerCommands.enqueue(async () => {
setPlayerState(await getPlayerState())
})
}
export const useRefreshProgress = () => {
const setProgress = useUpdateAtom(progressAtom)
return () =>
trackPlayerCommands.enqueue(async () => {
setProgress(await getProgress())
})
}
export const usePrevious = () => {
const setCurrentTrack = useUpdateAtom(currentTrackAtom)
@ -179,6 +240,19 @@ export const useSetQueue = () => {
})
}
export const useProgress = () => {
const progress = useAtomValue(progressAtom)
const addSub = useUpdateAtom(addProgressSub)
const removeSub = useUpdateAtom(removeProgressSub)
useEffect(() => {
addSub()
return removeSub
}, [addSub, removeSub])
return progress
}
function mapSongToTrack(song: Song, queueName: string): TrackExt {
return {
id: song.id,