From 49b5ce3f6ceceeb17df5209491a21e281d2a1b1c Mon Sep 17 00:00:00 2001 From: austinried <4966622+austinried@users.noreply.github.com> Date: Tue, 6 Jul 2021 21:39:00 +0900 Subject: [PATCH] fixed progress hook with my own state wrap/update --- src/components/NowPlayingLayout.tsx | 13 +++-- src/components/TrackPlayerState.tsx | 45 +++++++++++++++- src/state/trackplayer.ts | 82 +++++++++++++++++++++++++++-- 3 files changed, 131 insertions(+), 9 deletions(-) diff --git a/src/components/NowPlayingLayout.tsx b/src/components/NowPlayingLayout.tsx index 173ba71..121a710 100644 --- a/src/components/NowPlayingLayout.tsx +++ b/src/components/NowPlayingLayout.tsx @@ -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) { diff --git a/src/components/TrackPlayerState.tsx b/src/components/TrackPlayerState.tsx index e20f175..630fdfc 100644 --- a/src/components/TrackPlayerState.tsx +++ b/src/components/TrackPlayerState.tsx @@ -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 @@ -94,6 +99,41 @@ const QueueState = () => { return } +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 ( + <> + + + + ) + } + return +} + const Debug = () => { const value = useAtomValue(currentTrackAtom) @@ -109,6 +149,7 @@ const TrackPlayerState = () => ( + ) diff --git a/src/state/trackplayer.ts b/src/state/trackplayer.ts index ee31564..9dcdcaf 100644 --- a/src/state/trackplayer.ts +++ b/src/state/trackplayer.ts @@ -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.None) export const playerStateAtom = atom( get => get(playerState), @@ -33,7 +40,7 @@ export const currentTrackAtom = atom( ) const _queue = atom([]) -export const queueAtom = atom(get => get(_queue)) +export const queueReadAtom = atom(get => get(_queue)) export const queueWriteAtom = atom( get => get(_queue), (get, set, update) => { @@ -51,6 +58,25 @@ export const queueNameAtom = atom(get => { return undefined }) +const _progress = atom({ position: 0, duration: 0, buffered: 0 }) +export const progressAtom = atom( + 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 => { @@ -61,6 +87,23 @@ const getTrack = async (index: number): Promise => { return ((await TrackPlayer.getTrack(index)) as TrackExt) || undefined } +const getPlayerState = async (): Promise => { + return (await TrackPlayer.getState()) || State.None +} + +const getProgress = async (): Promise => { + 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,