mirror of
https://github.com/Boof2015/astra-mobile.git
synced 2026-08-19 04:06:43 +02:00
widgets
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import TrackPlayer, { Event } from 'react-native-track-player';
|
||||
import { syncWidgetNowPlayingFromTrackPlayer } from './widgetSync';
|
||||
|
||||
/**
|
||||
* RNTP playback service — registered in `index.js`. Runs in a headless context
|
||||
@@ -6,15 +7,31 @@ import TrackPlayer, { Event } from 'react-native-track-player';
|
||||
* controls to the player. Must not depend on React or the JS UI tree.
|
||||
*/
|
||||
export async function PlaybackService(): Promise<void> {
|
||||
TrackPlayer.addEventListener(Event.RemotePlay, () => TrackPlayer.play());
|
||||
TrackPlayer.addEventListener(Event.RemotePause, () => TrackPlayer.pause());
|
||||
TrackPlayer.addEventListener(Event.RemoteStop, () => TrackPlayer.stop());
|
||||
TrackPlayer.addEventListener(Event.RemoteNext, () =>
|
||||
TrackPlayer.skipToNext().catch(() => {}),
|
||||
);
|
||||
TrackPlayer.addEventListener(Event.RemotePrevious, () =>
|
||||
TrackPlayer.skipToPrevious().catch(() => {}),
|
||||
);
|
||||
TrackPlayer.addEventListener(Event.PlaybackActiveTrackChanged, () => {
|
||||
void syncWidgetNowPlayingFromTrackPlayer();
|
||||
});
|
||||
TrackPlayer.addEventListener(Event.PlaybackState, () => {
|
||||
void syncWidgetNowPlayingFromTrackPlayer();
|
||||
});
|
||||
TrackPlayer.addEventListener(Event.RemotePlay, () => {
|
||||
void TrackPlayer.play().finally(() => syncWidgetNowPlayingFromTrackPlayer());
|
||||
});
|
||||
TrackPlayer.addEventListener(Event.RemotePause, () => {
|
||||
void TrackPlayer.pause().finally(() => syncWidgetNowPlayingFromTrackPlayer());
|
||||
});
|
||||
TrackPlayer.addEventListener(Event.RemoteStop, () => {
|
||||
void TrackPlayer.stop().finally(() => syncWidgetNowPlayingFromTrackPlayer());
|
||||
});
|
||||
TrackPlayer.addEventListener(Event.RemoteNext, () => {
|
||||
void TrackPlayer.skipToNext()
|
||||
.catch(() => {})
|
||||
.finally(() => syncWidgetNowPlayingFromTrackPlayer());
|
||||
});
|
||||
TrackPlayer.addEventListener(Event.RemotePrevious, () => {
|
||||
void TrackPlayer.skipToPrevious()
|
||||
.catch(() => {})
|
||||
.finally(() => syncWidgetNowPlayingFromTrackPlayer());
|
||||
});
|
||||
TrackPlayer.addEventListener(Event.RemoteSeek, ({ position }) =>
|
||||
TrackPlayer.seekTo(position),
|
||||
);
|
||||
|
||||
@@ -9,6 +9,7 @@ import { usePlayerStore } from '@/stores/playerStore';
|
||||
import { useLibraryStore } from '@/stores/libraryStore';
|
||||
import type { PlaybackState } from '@/types/audio';
|
||||
import { rntpToTrack } from './sampleTracks';
|
||||
import { buildWidgetRecentItems, setWidgetNowPlaying } from './widgetSync';
|
||||
|
||||
const RECENT_PLAY_THRESHOLD_MS = 15_000;
|
||||
|
||||
@@ -54,6 +55,7 @@ export function usePlaybackSync(): void {
|
||||
const setProgress = usePlayerStore((s) => s.setProgress);
|
||||
const setPlaybackState = usePlayerStore((s) => s.setPlaybackState);
|
||||
const recordTrackPlayed = useLibraryStore((s) => s.recordTrackPlayed);
|
||||
const recentlyPlayedTracks = useLibraryStore((s) => s.recentlyPlayedTracks);
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentTrack(activeTrack ? rntpToTrack(activeTrack) : null);
|
||||
@@ -67,6 +69,15 @@ export function usePlaybackSync(): void {
|
||||
setPlaybackState(mappedPlaybackState);
|
||||
}, [mappedPlaybackState, setPlaybackState]);
|
||||
|
||||
useEffect(() => {
|
||||
const track = activeTrack ? rntpToTrack(activeTrack) : null;
|
||||
setWidgetNowPlaying(
|
||||
track,
|
||||
mappedPlaybackState,
|
||||
buildWidgetRecentItems(recentlyPlayedTracks, track?.path),
|
||||
);
|
||||
}, [activeTrack, mappedPlaybackState, recentlyPlayedTracks]);
|
||||
|
||||
useEffect(() => {
|
||||
const path = activeTrack?.url ? String(activeTrack.url) : null;
|
||||
const now = Date.now();
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
import TrackPlayer, { State, type Track as RntpTrack } from 'react-native-track-player';
|
||||
|
||||
import type { PlaybackState, Track } from '@/types/audio';
|
||||
import type { DbTrack } from '@/types/library';
|
||||
import { artworkThumbUri } from '@/library/artwork';
|
||||
import { AstraWidget, type AstraWidgetRecentItem } from '../../modules/astra-widget';
|
||||
|
||||
function mapRntpState(state?: State): PlaybackState {
|
||||
switch (state) {
|
||||
case State.Playing:
|
||||
return 'playing';
|
||||
case State.Buffering:
|
||||
case State.Loading:
|
||||
return 'loading';
|
||||
case State.Paused:
|
||||
case State.Ready:
|
||||
return 'paused';
|
||||
default:
|
||||
return 'stopped';
|
||||
}
|
||||
}
|
||||
|
||||
export function setWidgetNowPlaying(
|
||||
track: Pick<Track, 'title' | 'artist' | 'artworkData'> | null,
|
||||
playbackState: PlaybackState,
|
||||
recentlyPlayed?: AstraWidgetRecentItem[],
|
||||
): void {
|
||||
AstraWidget.setNowPlaying({
|
||||
title: track?.title ?? null,
|
||||
artist: track?.artist ?? null,
|
||||
artworkUri: track?.artworkData ?? null,
|
||||
playbackState,
|
||||
hasTrack: Boolean(track),
|
||||
...(recentlyPlayed === undefined
|
||||
? {}
|
||||
: {
|
||||
recentlyPlayed,
|
||||
replaceRecentlyPlayed: true,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
export function setWidgetNowPlayingFromRntpTrack(
|
||||
track: RntpTrack | null | undefined,
|
||||
playbackState: PlaybackState,
|
||||
): void {
|
||||
setWidgetNowPlaying(
|
||||
track
|
||||
? {
|
||||
title: track.title ?? 'Unknown title',
|
||||
artist: track.artist ?? 'Unknown artist',
|
||||
artworkData: typeof track.artwork === 'string' ? track.artwork : undefined,
|
||||
}
|
||||
: null,
|
||||
playbackState,
|
||||
);
|
||||
}
|
||||
|
||||
export function buildWidgetRecentItems(
|
||||
tracks: readonly DbTrack[],
|
||||
currentPath?: string,
|
||||
): AstraWidgetRecentItem[] {
|
||||
return tracks
|
||||
.filter((track) => track.path !== currentPath)
|
||||
.slice(0, 8)
|
||||
.map((track) => ({
|
||||
title: track.title,
|
||||
artist: track.artist,
|
||||
artworkUri: track.artwork_hash ? artworkThumbUri(track.artwork_hash) : null,
|
||||
}));
|
||||
}
|
||||
|
||||
export async function syncWidgetNowPlayingFromTrackPlayer(): Promise<void> {
|
||||
try {
|
||||
const [activeTrack, playbackState] = await Promise.all([
|
||||
TrackPlayer.getActiveTrack(),
|
||||
TrackPlayer.getPlaybackState(),
|
||||
]);
|
||||
setWidgetNowPlayingFromRntpTrack(activeTrack, mapRntpState(playbackState.state));
|
||||
} catch {
|
||||
setWidgetNowPlaying(null, 'stopped');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user