diff --git a/res/next-fill.png b/res/next-fill.png
new file mode 100644
index 0000000..46bc713
Binary files /dev/null and b/res/next-fill.png differ
diff --git a/res/pause_circle-fill.png b/res/pause_circle-fill.png
new file mode 100644
index 0000000..e31b55b
Binary files /dev/null and b/res/pause_circle-fill.png differ
diff --git a/res/play_circle-fill.png b/res/play_circle-fill.png
new file mode 100644
index 0000000..db9d664
Binary files /dev/null and b/res/play_circle-fill.png differ
diff --git a/res/previous-fill.png b/res/previous-fill.png
new file mode 100644
index 0000000..328112b
Binary files /dev/null and b/res/previous-fill.png differ
diff --git a/src/components/NowPlayingLayout.tsx b/src/components/NowPlayingLayout.tsx
index 8987dc8..0e907ac 100644
--- a/src/components/NowPlayingLayout.tsx
+++ b/src/components/NowPlayingLayout.tsx
@@ -1,8 +1,9 @@
import { useAtomValue } from 'jotai/utils';
import React from 'react';
-import { StatusBar, StyleSheet, Text, useWindowDimensions, View } from 'react-native';
+import { Pressable, StatusBar, StyleSheet, Text, useWindowDimensions, View } from 'react-native';
import FastImage from 'react-native-fast-image';
-import { currentQueueNameAtom, currentTrackAtom } from '../state/trackplayer';
+import TrackPlayer, { State } from 'react-native-track-player';
+import { currentQueueNameAtom, currentTrackAtom, playerStateAtom } from '../state/trackplayer';
import text from '../styles/text';
import CoverArt from './common/CoverArt';
import ImageGradientBackground from './common/ImageGradientBackground';
@@ -14,7 +15,7 @@ const NowPlayingHeader = () => {
- {queueName}
+ {queueName || 'Nothing playing...'}
@@ -48,16 +49,12 @@ const SongCoverArt = () => {
const track = useAtomValue(currentTrackAtom);
const layout = useWindowDimensions();
- const size = layout.width - layout.width / 6;
+ const size = layout.width - layout.width / 7;
return (
(
-
- Failed
-
- )}
+ PlaceholderComponent={() => }
height={size}
width={size}
coverArtUri={track?.artwork as string}
@@ -70,7 +67,7 @@ const coverArtStyles = StyleSheet.create({
container: {
width: '100%',
alignItems: 'center',
- marginTop: 20,
+ marginTop: 10,
},
});
@@ -104,6 +101,81 @@ const infoStyles = StyleSheet.create({
},
});
+const PlayerControls = () => {
+ const state = useAtomValue(playerStateAtom);
+
+ let playPauseIcon: number;
+ let playPauseStyle: any;
+ let playPauseAction: () => void;
+
+ switch (state) {
+ case State.Playing:
+ playPauseIcon = require('../../res/pause_circle-fill.png');
+ playPauseStyle = controlsStyles.enabled;
+ playPauseAction = () => TrackPlayer.pause();
+ break;
+ case State.Paused:
+ playPauseIcon = require('../../res/play_circle-fill.png');
+ playPauseStyle = controlsStyles.enabled;
+ playPauseAction = () => TrackPlayer.play();
+ break;
+ case State.Buffering:
+ case State.Connecting:
+ playPauseIcon = require('../../res/pause_circle-fill.png');
+ playPauseStyle = controlsStyles.disabled;
+ playPauseAction = () => {};
+ break;
+ default:
+ playPauseIcon = require('../../res/play_circle-fill.png');
+ playPauseStyle = controlsStyles.disabled;
+ playPauseAction = () => {};
+ break;
+ }
+
+ return (
+
+
+
+
+
+
+
+ );
+};
+
+const controlsStyles = StyleSheet.create({
+ container: {
+ width: '100%',
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'center',
+ marginTop: 40,
+ },
+ skip: {
+ height: 40,
+ width: 40,
+ marginHorizontal: 18,
+ },
+ play: {
+ height: 90,
+ width: 90,
+ },
+ enabled: {
+ opacity: 1,
+ },
+ disabled: {
+ opacity: 0.35,
+ },
+});
+
const NowPlayingLayout = () => {
const track = useAtomValue(currentTrackAtom);
@@ -117,6 +189,7 @@ const NowPlayingLayout = () => {
+
);
};
diff --git a/src/components/TrackPlayerState.tsx b/src/components/TrackPlayerState.tsx
index cce06af..cfc0999 100644
--- a/src/components/TrackPlayerState.tsx
+++ b/src/components/TrackPlayerState.tsx
@@ -1,8 +1,8 @@
import React, { useCallback, useEffect } from 'react';
-import TrackPlayer, { Event, useTrackPlayerEvents } from 'react-native-track-player';
+import TrackPlayer, { Event, State, useTrackPlayerEvents } from 'react-native-track-player';
import { useAppState } from '@react-native-community/hooks';
import { useUpdateAtom, useAtomValue } from 'jotai/utils';
-import { currentQueueNameAtom, currentTrackAtom } from '../state/trackplayer';
+import { currentQueueNameAtom, currentTrackAtom, playerStateAtom } from '../state/trackplayer';
import { View } from 'react-native';
const CurrentTrackState = () => {
@@ -67,6 +67,42 @@ const CurrentQueueName = () => {
setCurrentQueueName(undefined);
}, [setCurrentQueueName]);
+ useTrackPlayerEvents(
+ [Event.PlaybackState, Event.PlaybackQueueEnded, Event.PlaybackMetadataReceived, Event.RemoteDuck, Event.RemoteStop],
+ event => {
+ if (event.type === Event.PlaybackState) {
+ if (event.state === State.Stopped || event.state === State.None) {
+ return;
+ }
+ }
+ update();
+ },
+ );
+
+ useEffect(() => {
+ if (appState === 'active') {
+ update();
+ }
+ }, [appState, update]);
+
+ return <>>;
+};
+
+const PlayerState = () => {
+ const setPlayerState = useUpdateAtom(playerStateAtom);
+ const appState = useAppState();
+
+ const update = useCallback(
+ async (state?: State) => {
+ setPlayerState(state || (await TrackPlayer.getState()));
+ },
+ [setPlayerState],
+ );
+
+ useTrackPlayerEvents([Event.PlaybackState], event => {
+ update(event.state);
+ });
+
useEffect(() => {
if (appState === 'active') {
update();
@@ -90,6 +126,7 @@ const TrackPlayerState = () => (
+
);
diff --git a/src/state/trackplayer.ts b/src/state/trackplayer.ts
index 46256d8..236c4cd 100644
--- a/src/state/trackplayer.ts
+++ b/src/state/trackplayer.ts
@@ -1,5 +1,5 @@
import { atom } from 'jotai';
-import { Track } from 'react-native-track-player';
+import { State, Track } from 'react-native-track-player';
import equal from 'fast-deep-equal';
type OptionalTrack = Track | undefined;
@@ -25,3 +25,13 @@ export const currentQueueNameAtom = atom(
}
},
);
+
+const playerState = atom(State.None);
+export const playerStateAtom = atom(
+ get => get(playerState),
+ (get, set, value) => {
+ if (get(playerState) !== value) {
+ set(playerState, value);
+ }
+ },
+);