central management of track player state

currentTrack implemented and working well now (only updates on change)
This commit is contained in:
austinried
2021-07-02 12:48:43 +09:00
parent c676944b9a
commit 28ab092402
7 changed files with 112 additions and 37 deletions

View File

@@ -0,0 +1,72 @@
import React, { useCallback, useEffect } from 'react';
import TrackPlayer, { Event, State, Track, useTrackPlayerEvents } from 'react-native-track-player';
import { useAppState } from '@react-native-community/hooks';
import { useUpdateAtom, useAtomValue } from 'jotai/utils';
import { currentTrackAtom } from '../state/trackplayer';
import { View } from 'react-native';
const TrackPlayerState = () => {
const setCurrentTrack = useUpdateAtom(currentTrackAtom);
const appState = useAppState();
const updateCurrentTrack = useCallback(async () => {
const index = await TrackPlayer.getCurrentTrack();
if (index !== null && index >= 0) {
const track = await TrackPlayer.getTrack(index);
if (track !== null) {
setCurrentTrack(track);
return;
}
}
setCurrentTrack(undefined);
}, [setCurrentTrack]);
useTrackPlayerEvents(
[
// Event.PlaybackState,
// Event.PlaybackTrackChanged,
Event.PlaybackQueueEnded,
Event.PlaybackMetadataReceived,
Event.RemoteDuck,
Event.RemoteNext,
Event.RemotePrevious,
Event.RemoteStop,
],
event => {
if (event.type === Event.PlaybackQueueEnded && 'track' in event) {
setCurrentTrack(undefined);
return;
}
updateCurrentTrack();
},
);
useEffect(() => {
if (appState === 'active') {
updateCurrentTrack();
}
}, [appState, updateCurrentTrack]);
return <></>;
};
const CurrentTrack = () => {
const currentTrack = useAtomValue(currentTrackAtom);
useEffect(() => {
console.log(currentTrack?.title);
}, [currentTrack]);
return <></>;
};
const ASDFSADFSAF = () => (
<View>
<TrackPlayerState />
<CurrentTrack />
</View>
);
export default ASDFSADFSAF;

View File

@@ -10,8 +10,9 @@ import {
useWindowDimensions,
View,
} from 'react-native';
import { useCurrentTrackId, useSetQueue } from '../../hooks/player';
import { useSetQueue } from '../../hooks/player';
import { albumAtomFamily } from '../../state/music';
import { currentTrackAtom } from '../../state/trackplayer';
import colors from '../../styles/colors';
import text from '../../styles/text';
import AlbumArt from './AlbumArt';
@@ -27,7 +28,7 @@ const SongItem: React.FC<{
onPress: (event: GestureResponderEvent) => void;
}> = ({ id, title, artist, onPress }) => {
const [opacity, setOpacity] = useState(1);
const currentTrackId = useCurrentTrackId();
const currentTrack = useAtomValue(currentTrackAtom);
return (
<View
@@ -50,7 +51,7 @@ const SongItem: React.FC<{
<Text
style={{
...text.songListTitle,
color: currentTrackId === id ? colors.accent : colors.text.primary,
color: currentTrack?.id === id ? colors.accent : colors.text.primary,
}}>
{title}
</Text>

View File

@@ -1,6 +1,7 @@
import { useState } from 'react';
import TrackPlayer, { Track, useTrackPlayerEvents, Event, State } from 'react-native-track-player';
import { useUpdateAtom } from 'jotai/utils';
import TrackPlayer, { Track } from 'react-native-track-player';
import { Song } from '../models/music';
import { currentTrackAtom } from '../state/trackplayer';
function mapSongToTrack(song: Song): Track {
return {
@@ -13,41 +14,17 @@ function mapSongToTrack(song: Song): Track {
};
}
const currentTrackEvents = [Event.PlaybackState, Event.PlaybackTrackChanged, Event.RemoteStop];
export const useCurrentTrackId = () => {
const [currentTrackId, setCurrentTrackId] = useState<string | null>(null);
useTrackPlayerEvents(currentTrackEvents, async event => {
switch (event.type) {
case Event.PlaybackState:
switch (event.state) {
case State.None:
case State.Stopped:
setCurrentTrackId(null);
break;
}
break;
case Event.PlaybackTrackChanged:
const trackIndex = await TrackPlayer.getCurrentTrack();
setCurrentTrackId((await TrackPlayer.getTrack(trackIndex)).id);
break;
case Event.RemoteStop:
setCurrentTrackId(null);
break;
default:
break;
}
});
return currentTrackId;
};
export const useSetQueue = () => {
const setCurrentTrack = useUpdateAtom(currentTrackAtom);
return async (songs: Song[], playId?: string) => {
await TrackPlayer.reset();
const tracks = songs.map(mapSongToTrack);
if (playId) {
setCurrentTrack(tracks.find(t => t.id === playId));
}
if (!playId) {
await TrackPlayer.add(tracks);
} else if (playId === tracks[0].id) {
@@ -63,8 +40,8 @@ export const useSetQueue = () => {
await TrackPlayer.add(tracks1, 0);
const queue = await TrackPlayer.getQueue();
console.log(`queue: ${JSON.stringify(queue.map(x => x.title))}`);
// const queue = await TrackPlayer.getQueue();
// console.log(`queue: ${JSON.stringify(queue.map(x => x.title))}`);
}
};
};

16
src/state/trackplayer.ts Normal file
View File

@@ -0,0 +1,16 @@
import { atom } from 'jotai';
import { Track } from 'react-native-track-player';
import equal from 'fast-deep-equal';
type OptionalTrack = Track | undefined;
const currentTrack = atom<OptionalTrack>(undefined);
export const currentTrackAtom = atom<OptionalTrack, OptionalTrack>(
get => get(currentTrack),
(get, set, value) => {
if (equal(get(currentTrack), value)) {
return;
}
set(currentTrack, value);
},
);