mirror of
https://github.com/austinried/subtracks.git
synced 2025-12-27 00:59:28 +01:00
central management of track player state
currentTrack implemented and working well now (only updates on change)
This commit is contained in:
parent
c676944b9a
commit
28ab092402
2
App.tsx
2
App.tsx
@ -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 />
|
||||
|
||||
@ -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",
|
||||
|
||||
72
src/components/TrackPlayerState.tsx
Normal file
72
src/components/TrackPlayerState.tsx
Normal 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;
|
||||
@ -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>
|
||||
|
||||
@ -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
16
src/state/trackplayer.ts
Normal 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);
|
||||
},
|
||||
);
|
||||
@ -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"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user