mirror of
https://github.com/Jellify-Music/App.git
synced 2026-03-17 18:51:24 -05:00
play next fixes, queue state fixes, styling fixes
This commit is contained in:
@@ -89,7 +89,7 @@ export default function AlbumTrackListHeader({ album }: { album: BaseItemDto }):
|
||||
) : null}
|
||||
</YStack>
|
||||
|
||||
<Separator vertical />
|
||||
<Separator vertical borderColor={'$borderColor'} />
|
||||
|
||||
<RunTimeTicks props={{ flex: 1, textAlign: 'left' }}>
|
||||
{album.RunTimeTicks}
|
||||
|
||||
@@ -12,8 +12,8 @@ interface SwitchWithLabelProps {
|
||||
|
||||
// Use theme tokens so thumb colors follow the active color preset
|
||||
const JellifySliderThumb = styled(Switch.Thumb, {
|
||||
borderColor: '$primary',
|
||||
backgroundColor: '$background',
|
||||
borderColor: '$color',
|
||||
backgroundColor: '$color',
|
||||
})
|
||||
|
||||
export function SwitchWithLabel(props: SwitchWithLabelProps) {
|
||||
@@ -36,7 +36,7 @@ export function SwitchWithLabel(props: SwitchWithLabelProps) {
|
||||
>
|
||||
<JellifySliderThumb transition='bouncy' />
|
||||
</Switch>
|
||||
<Separator minHeight={20} vertical />
|
||||
<Separator minHeight={20} vertical borderColor={'$borderColor'} />
|
||||
<Label size={props.size} htmlFor={id}>
|
||||
{props.label}
|
||||
</Label>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { usePlayerQueueStore } from '../../../stores/player/queue'
|
||||
import { SKIP_TO_PREVIOUS_THRESHOLD } from '../../../configs/player.config'
|
||||
import { isUndefined } from 'lodash'
|
||||
import { TrackPlayer } from 'react-native-nitro-player'
|
||||
import { usePlayerPlaybackStore } from '../../../stores/player/playback'
|
||||
|
||||
/**
|
||||
* A function that will skip to the previous track if
|
||||
@@ -15,9 +17,15 @@ import { TrackPlayer } from 'react-native-nitro-player'
|
||||
* Does not resume playback if the player was paused
|
||||
*/
|
||||
export async function previous(): Promise<void> {
|
||||
const { currentPosition, currentState } = await TrackPlayer.getState()
|
||||
const { currentState } = await TrackPlayer.getState()
|
||||
|
||||
if (Math.floor(currentPosition) < SKIP_TO_PREVIOUS_THRESHOLD) {
|
||||
const { position } = usePlayerPlaybackStore.getState()
|
||||
|
||||
const { currentIndex } = usePlayerQueueStore.getState()
|
||||
|
||||
if (isUndefined(currentIndex)) return
|
||||
|
||||
if (Math.floor(position) < SKIP_TO_PREVIOUS_THRESHOLD) {
|
||||
TrackPlayer.skipToPrevious()
|
||||
} else {
|
||||
TrackPlayer.seek(0)
|
||||
@@ -37,13 +45,11 @@ export async function previous(): Promise<void> {
|
||||
* @param index The track index to skip to, to skip multiple tracks
|
||||
*/
|
||||
export async function skip(index: number | undefined): Promise<void> {
|
||||
if (!isUndefined(index)) {
|
||||
const { currentIndex } = await TrackPlayer.getState()
|
||||
const { currentIndex } = usePlayerQueueStore.getState()
|
||||
|
||||
if (!isUndefined(index)) {
|
||||
if (index === currentIndex) return
|
||||
else {
|
||||
TrackPlayer.skipToIndex(index)
|
||||
}
|
||||
TrackPlayer.skipToIndex(index)
|
||||
} else {
|
||||
TrackPlayer.skipToNext()
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { isNull } from 'lodash'
|
||||
import { useNetworkStore } from '../../../stores/network'
|
||||
import { DownloadManager, PlayerQueue, TrackItem, TrackPlayer } from 'react-native-nitro-player'
|
||||
import uuid from 'react-native-uuid'
|
||||
import resolveTrackUrls from '../../../utils/fetching/track-media-info'
|
||||
|
||||
type LoadQueueResult = {
|
||||
finalStartIndex: number
|
||||
@@ -20,7 +21,6 @@ export async function loadQueue({
|
||||
tracklist,
|
||||
queue,
|
||||
shuffled = false,
|
||||
startPlayback,
|
||||
}: QueueMutation): Promise<LoadQueueResult> {
|
||||
TrackPlayer.pause()
|
||||
|
||||
@@ -76,56 +76,31 @@ export async function loadQueue({
|
||||
* @param item The track to play next
|
||||
*/
|
||||
export const playNextInQueue = async ({ tracks }: AddToQueueMutation) => {
|
||||
// Add the resolved tracks to the CURRENT playlist (not an orphan one). The
|
||||
// native updatePlaylist callback will do a soft rebuild that dedups them from
|
||||
// the remaining queue, so they only appear in the playNext stack.
|
||||
const currentPlaylistId = PlayerQueue.getCurrentPlaylistId()
|
||||
if (!currentPlaylistId) return
|
||||
|
||||
const tracksToPlayNext = tracks.map((item) => mapDtoToTrack(item))
|
||||
|
||||
const { currentIndex, currentPlaylistId } = await TrackPlayer.getState()
|
||||
// Resolve URLs before adding to the native queue. If we add unresolved tracks
|
||||
// (empty URL) and then call playNext, ExoPlayer/AVPlayer immediately errors on
|
||||
// the empty URI and skips the track. We must have the real URL in the playlist
|
||||
// before playNext references it by ID.
|
||||
const resolvedTracks = await resolveTrackUrls(tracksToPlayNext, 'stream')
|
||||
|
||||
if (currentPlaylistId) {
|
||||
const currentQueue = PlayerQueue.getPlaylist(currentPlaylistId!)!.tracks
|
||||
PlayerQueue.addTracksToPlaylist(currentPlaylistId, resolvedTracks)
|
||||
|
||||
PlayerQueue.addTracksToPlaylist(currentPlaylistId, tracksToPlayNext)
|
||||
await Promise.all(resolvedTracks.map(({ id }) => TrackPlayer.playNext(id)))
|
||||
|
||||
await Promise.all(tracksToPlayNext.map(({ id }) => TrackPlayer.playNext(id)))
|
||||
// Get the active queue, put it in Zustand
|
||||
const updatedQueue = await TrackPlayer.getActualQueue()
|
||||
usePlayerQueueStore.getState().setQueue([...updatedQueue])
|
||||
|
||||
// Get the active queue, put it in Zustand
|
||||
const updatedQueue = await TrackPlayer.getActualQueue()
|
||||
usePlayerQueueStore.getState().setQueue([...updatedQueue])
|
||||
|
||||
// Add to the state unshuffled queue, using the currently playing track as the index
|
||||
// TODO: Check this
|
||||
usePlayerQueueStore
|
||||
.getState()
|
||||
.setUnshuffledQueue([
|
||||
...usePlayerQueueStore
|
||||
.getState()
|
||||
.unShuffledQueue.slice(
|
||||
0,
|
||||
usePlayerQueueStore
|
||||
.getState()
|
||||
.unShuffledQueue.indexOf(currentQueue[currentIndex!]) + 1,
|
||||
),
|
||||
...tracksToPlayNext,
|
||||
...usePlayerQueueStore
|
||||
.getState()
|
||||
.unShuffledQueue.slice(
|
||||
usePlayerQueueStore
|
||||
.getState()
|
||||
.unShuffledQueue.indexOf(currentQueue[currentIndex!]) + 1,
|
||||
),
|
||||
])
|
||||
}
|
||||
// If there isn't a current playlist, create one with the track to play next and load it
|
||||
else {
|
||||
const currentPlaylistId = PlayerQueue.createPlaylist('Playlist')
|
||||
|
||||
PlayerQueue.addTracksToPlaylist(currentPlaylistId, tracksToPlayNext)
|
||||
PlayerQueue.loadPlaylist(currentPlaylistId)
|
||||
await TrackPlayer.playNext(tracksToPlayNext[0].id)
|
||||
|
||||
const updatedQueue = await TrackPlayer.getActualQueue()
|
||||
usePlayerQueueStore.getState().setQueue([...updatedQueue])
|
||||
usePlayerQueueStore.getState().setUnshuffledQueue([...tracksToPlayNext])
|
||||
}
|
||||
usePlayerQueueStore
|
||||
.getState()
|
||||
.setUnshuffledQueue([...usePlayerQueueStore.getState().unShuffledQueue, ...resolvedTracks])
|
||||
}
|
||||
|
||||
export const playLaterInQueue = async ({ tracks }: AddToQueueMutation) => {
|
||||
|
||||
@@ -4,11 +4,7 @@ import reportPlaybackProgress from '../../../api/mutations/playback/functions/pl
|
||||
import reportPlaybackStarted from '../../../api/mutations/playback/functions/playback-started'
|
||||
import reportPlaybackStopped from '../../../api/mutations/playback/functions/playback-stopped'
|
||||
import isPlaybackFinished from '../../../api/mutations/playback/utils'
|
||||
import {
|
||||
usePlayerPlaybackStore,
|
||||
setPlaybackPosition,
|
||||
setTotalDuration,
|
||||
} from '../../../stores/player/playback'
|
||||
import { usePlayerPlaybackStore } from '../../../stores/player/playback'
|
||||
import { usePlayerQueueStore } from '../../../stores/player/queue'
|
||||
import { usePlayerSettingsStore } from '../../../stores/settings/player'
|
||||
import { useUsageSettingsStore } from '../../../stores/settings/usage'
|
||||
@@ -19,6 +15,7 @@ import {
|
||||
Reason,
|
||||
TrackPlayerState,
|
||||
TrackItem,
|
||||
PlayerQueue,
|
||||
} from 'react-native-nitro-player'
|
||||
|
||||
/**
|
||||
@@ -65,6 +62,7 @@ export async function onChangeTrack() {
|
||||
}
|
||||
|
||||
const { currentIndex, currentTrack } = await TrackPlayer.getState()
|
||||
const actualQueue = await TrackPlayer.getActualQueue()
|
||||
|
||||
// Get the last track and the last known position...
|
||||
const previousTrack = usePlayerQueueStore.getState().currentTrack
|
||||
@@ -78,12 +76,17 @@ export async function onChangeTrack() {
|
||||
}
|
||||
|
||||
// Then we can update the store...
|
||||
usePlayerQueueStore.getState().setCurrentIndex(currentIndex)
|
||||
usePlayerQueueStore.getState().setCurrentTrack(currentTrack!)
|
||||
usePlayerQueueStore.setState((state) => ({
|
||||
...state,
|
||||
currentIndex,
|
||||
currentTrack: currentTrack ?? undefined,
|
||||
queue: actualQueue,
|
||||
}))
|
||||
|
||||
// ...report that playback has started for the new track...
|
||||
await reportPlaybackStarted(currentTrack!, 0)
|
||||
|
||||
// TODO: Fix audio normalization logic against nitro player
|
||||
const { enableAudioNormalization } = usePlayerSettingsStore.getState()
|
||||
|
||||
// ...and apply audio normalization if enabled in settings
|
||||
@@ -94,8 +97,10 @@ export async function onChangeTrack() {
|
||||
}
|
||||
|
||||
export async function onPlaybackProgress(position: number, totalDuration: number) {
|
||||
setPlaybackPosition(position)
|
||||
setTotalDuration(totalDuration)
|
||||
usePlayerPlaybackStore.setState({
|
||||
position,
|
||||
totalDuration,
|
||||
})
|
||||
|
||||
const { currentTrack } = usePlayerQueueStore.getState()
|
||||
|
||||
@@ -105,16 +110,12 @@ export async function onPlaybackProgress(position: number, totalDuration: number
|
||||
|
||||
const { autoDownload } = useUsageSettingsStore.getState()
|
||||
|
||||
const isDownloadedOrDownloadPending =
|
||||
(await DownloadManager.isTrackDownloaded(currentTrack?.id ?? '')) ||
|
||||
(await DownloadManager.isDownloading(currentTrack?.id ?? ''))
|
||||
if (position / totalDuration > 0.3 && currentTrack && autoDownload) {
|
||||
const isDownloadedOrDownloadPending =
|
||||
(await DownloadManager.isTrackDownloaded(currentTrack?.id ?? '')) ||
|
||||
(await DownloadManager.isDownloading(currentTrack?.id ?? ''))
|
||||
|
||||
if (
|
||||
position / totalDuration > 0.3 &&
|
||||
currentTrack &&
|
||||
autoDownload &&
|
||||
!isDownloadedOrDownloadPending
|
||||
) {
|
||||
if (isDownloadedOrDownloadPending) return
|
||||
try {
|
||||
await DownloadManager.downloadTrack(currentTrack)
|
||||
} catch (error) {
|
||||
|
||||
@@ -169,11 +169,13 @@ export const setNewQueue = (
|
||||
index: number,
|
||||
shuffled: boolean,
|
||||
) => {
|
||||
usePlayerQueueStore.getState().setCurrentIndex(index)
|
||||
usePlayerQueueStore.getState().setQueueRef(queueRef)
|
||||
usePlayerQueueStore.getState().setQueue(queue)
|
||||
usePlayerQueueStore.getState().setCurrentTrack(queue[index])
|
||||
usePlayerQueueStore.getState().setShuffled(shuffled)
|
||||
usePlayerQueueStore.setState({
|
||||
queue,
|
||||
queueRef,
|
||||
currentIndex: index,
|
||||
currentTrack: queue[index],
|
||||
shuffled,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user