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

@ -5,6 +5,7 @@ import RootNavigator from './src/components/navigation/RootNavigator';
import { Provider } from 'jotai';
import { StatusBar } from 'react-native';
import colors from './src/styles/colors';
import TrackPlayerState from './src/components/TrackPlayerState';
const theme = { ...DarkTheme };
theme.colors.background = colors.gradient.high;
@ -12,6 +13,7 @@ theme.colors.background = colors.gradient.high;
const App = () => (
<Provider>
<StatusBar animated={true} backgroundColor={'rgba(0, 0, 0, 0.4)'} barStyle={'light-content'} translucent={true} />
<TrackPlayerState />
<SplashPage>
<NavigationContainer theme={theme}>
<RootNavigator />

View File

@ -11,10 +11,12 @@
},
"dependencies": {
"@react-native-async-storage/async-storage": "^1.15.5",
"@react-native-community/hooks": "^2.6.0",
"@react-native-community/masked-view": "^0.1.11",
"@react-navigation/bottom-tabs": "^5.11.11",
"@react-navigation/material-top-tabs": "^5.3.15",
"@react-navigation/native": "^5.9.4",
"fast-deep-equal": "^3.1.3",
"jotai": "^1.1.0",
"md5": "^2.3.0",
"react": "17.0.1",

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);
},
);

View File

@ -1108,6 +1108,11 @@
resolved "https://registry.yarnpkg.com/@react-native-community/eslint-plugin/-/eslint-plugin-1.1.0.tgz#e42b1bef12d2415411519fd528e64b593b1363dc"
integrity sha512-W/J0fNYVO01tioHjvYWQ9m6RgndVtbElzYozBq1ZPrHO/iCzlqoySHl4gO/fpCl9QEFjvJfjPgtPMTMlsoq5DQ==
"@react-native-community/hooks@^2.6.0":
version "2.6.0"
resolved "https://registry.yarnpkg.com/@react-native-community/hooks/-/hooks-2.6.0.tgz#dd5f19601eb3684c6bcdd3df3d0c04cf44c24cff"
integrity sha512-emBGKvhJ0h++lLJQ5ejsj+od9G67nEaihjvfSx7/JWvNrQGAhP9U0OZqgb9dkKzor9Ufaj9SGt8RNY97cGzttw==
"@react-native-community/masked-view@^0.1.11":
version "0.1.11"
resolved "https://registry.yarnpkg.com/@react-native-community/masked-view/-/masked-view-0.1.11.tgz#2f4c6e10bee0786abff4604e39a37ded6f3980ce"