mirror of
https://github.com/austinried/subtracks.git
synced 2025-12-29 17:39:27 +01:00
impl shuffle, controls are temp
This commit is contained in:
parent
df783a074b
commit
f859be51a5
@ -8,7 +8,7 @@ import {
|
|||||||
playerStateAtom,
|
playerStateAtom,
|
||||||
progressAtom,
|
progressAtom,
|
||||||
progressSubsAtom,
|
progressSubsAtom,
|
||||||
queueWriteAtom,
|
queueAtom,
|
||||||
useRefreshCurrentTrack,
|
useRefreshCurrentTrack,
|
||||||
useRefreshPlayerState,
|
useRefreshPlayerState,
|
||||||
useRefreshProgress,
|
useRefreshProgress,
|
||||||
@ -85,7 +85,7 @@ const PlayerState = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const QueueState = () => {
|
const QueueState = () => {
|
||||||
const setQueue = useUpdateAtom(queueWriteAtom)
|
const setQueue = useUpdateAtom(queueAtom)
|
||||||
const refreshQueue = useRefreshQueue()
|
const refreshQueue = useRefreshQueue()
|
||||||
|
|
||||||
const update = async (payload?: Payload) => {
|
const update = async (payload?: Payload) => {
|
||||||
|
|||||||
@ -26,7 +26,8 @@ const AlbumDetails: React.FC<{
|
|||||||
const Songs = () => (
|
const Songs = () => (
|
||||||
<>
|
<>
|
||||||
<View style={styles.controls}>
|
<View style={styles.controls}>
|
||||||
<Button title="Play Album" onPress={() => setQueue(album.songs, album.name, album.songs[0].id)} />
|
<Button title="Play Album" onPress={() => setQueue(album.songs, album.name, undefined, false)} />
|
||||||
|
<Button title="Shuffle" onPress={() => setQueue(album.songs, album.name, undefined, true)} />
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.songs}>
|
<View style={styles.songs}>
|
||||||
{album.songs
|
{album.songs
|
||||||
@ -37,8 +38,8 @@ const AlbumDetails: React.FC<{
|
|||||||
return a.title.localeCompare(b.title)
|
return a.title.localeCompare(b.title)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.map(s => (
|
.map((s, i) => (
|
||||||
<SongItem key={s.id} song={s} onPress={() => setQueue(album.songs, album.name, s.id)} />
|
<SongItem key={i} song={s} onPress={() => setQueue(album.songs, album.name, i)} />
|
||||||
))}
|
))}
|
||||||
</View>
|
</View>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -48,13 +48,13 @@ const ArtistDetails: React.FC<{ id: string }> = ({ id }) => {
|
|||||||
const TopSongs = () => (
|
const TopSongs = () => (
|
||||||
<>
|
<>
|
||||||
<Text style={styles.header}>Top Songs</Text>
|
<Text style={styles.header}>Top Songs</Text>
|
||||||
{artist.topSongs.map(s => (
|
{artist.topSongs.map((s, i) => (
|
||||||
<SongItem
|
<SongItem
|
||||||
key={s.id}
|
key={i}
|
||||||
song={s}
|
song={s}
|
||||||
showArt={true}
|
showArt={true}
|
||||||
subtitle="album"
|
subtitle="album"
|
||||||
onPress={() => setQueue(artist.topSongs, `Top Songs: ${artist.name}`, s.id)}
|
onPress={() => setQueue(artist.topSongs, `Top Songs: ${artist.name}`, i)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -26,11 +26,11 @@ const PlaylistDetails: React.FC<{
|
|||||||
const Songs = () => (
|
const Songs = () => (
|
||||||
<>
|
<>
|
||||||
<View style={styles.controls}>
|
<View style={styles.controls}>
|
||||||
<Button title="Play Playlist" onPress={() => setQueue(playlist.songs, playlist.name, playlist.songs[0].id)} />
|
<Button title="Play Playlist" onPress={() => setQueue(playlist.songs, playlist.name)} />
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.songs}>
|
<View style={styles.songs}>
|
||||||
{playlist.songs.map((s, index) => (
|
{playlist.songs.map((s, i) => (
|
||||||
<SongItem key={index} song={s} showArt={true} onPress={() => setQueue(playlist.songs, playlist.name, s.id)} />
|
<SongItem key={i} song={s} showArt={true} onPress={() => setQueue(playlist.songs, playlist.name, i)} />
|
||||||
))}
|
))}
|
||||||
</View>
|
</View>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import equal from 'fast-deep-equal'
|
import equal from 'fast-deep-equal'
|
||||||
import { atom } from 'jotai'
|
import { atom } from 'jotai'
|
||||||
import { useAtomValue, useUpdateAtom } from 'jotai/utils'
|
import { useAtomCallback, useAtomValue, useUpdateAtom } from 'jotai/utils'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import TrackPlayer, { State, Track } from 'react-native-track-player'
|
import TrackPlayer, { State, Track } from 'react-native-track-player'
|
||||||
import { Song } from '@app/models/music'
|
import { Song } from '@app/models/music'
|
||||||
@ -9,6 +9,7 @@ import PromiseQueue from '@app/util/PromiseQueue'
|
|||||||
type TrackExt = Track & {
|
type TrackExt = Track & {
|
||||||
id: string
|
id: string
|
||||||
queueName: string
|
queueName: string
|
||||||
|
queueIndex?: number
|
||||||
artworkThumb?: string
|
artworkThumb?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,8 +42,7 @@ export const currentTrackAtom = atom<OptionalTrackExt, OptionalTrackExt>(
|
|||||||
)
|
)
|
||||||
|
|
||||||
const _queue = atom<TrackExt[]>([])
|
const _queue = atom<TrackExt[]>([])
|
||||||
export const queueReadAtom = atom<TrackExt[]>(get => get(_queue))
|
export const queueAtom = atom<TrackExt[], TrackExt[]>(
|
||||||
export const queueWriteAtom = atom<TrackExt[], TrackExt[]>(
|
|
||||||
get => get(_queue),
|
get => get(_queue),
|
||||||
(get, set, update) => {
|
(get, set, update) => {
|
||||||
if (!equal(get(_queue), update)) {
|
if (!equal(get(_queue), update)) {
|
||||||
@ -53,10 +53,22 @@ export const queueWriteAtom = atom<TrackExt[], TrackExt[]>(
|
|||||||
|
|
||||||
export const queueNameAtom = atom<string | undefined>(get => {
|
export const queueNameAtom = atom<string | undefined>(get => {
|
||||||
const queue = get(_queue)
|
const queue = get(_queue)
|
||||||
if (queue.length > 0) {
|
return queue.length > 0 ? queue[0].queueName : undefined
|
||||||
return queue[0].queueName
|
})
|
||||||
|
|
||||||
|
export const queueShuffledAtom = atom<boolean>(get => {
|
||||||
|
const queue = get(_queue)
|
||||||
|
return queue.length > 0 ? queue[0].queueIndex !== undefined : false
|
||||||
|
})
|
||||||
|
|
||||||
|
export const orderedQueueAtom = atom<TrackExt[]>(get => {
|
||||||
|
const queue = get(_queue)
|
||||||
|
|
||||||
|
if (queue.length === 0 || queue[0].queueIndex === undefined) {
|
||||||
|
return queue
|
||||||
}
|
}
|
||||||
return undefined
|
|
||||||
|
return queue.map(t => t.queueIndex as number).map(i => queue[i])
|
||||||
})
|
})
|
||||||
|
|
||||||
const _progress = atom<Progress>({ position: 0, duration: 0, buffered: 0 })
|
const _progress = atom<Progress>({ position: 0, duration: 0, buffered: 0 })
|
||||||
@ -106,7 +118,7 @@ const getProgress = async (): Promise<Progress> => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const useRefreshQueue = () => {
|
export const useRefreshQueue = () => {
|
||||||
const setQueue = useUpdateAtom(queueWriteAtom)
|
const setQueue = useUpdateAtom(queueAtom)
|
||||||
|
|
||||||
return () =>
|
return () =>
|
||||||
trackPlayerCommands.enqueue(async () => {
|
trackPlayerCommands.enqueue(async () => {
|
||||||
@ -188,22 +200,22 @@ export const useNext = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useAdd = () => {
|
// export const useAdd = () => {
|
||||||
const setQueue = useUpdateAtom(queueWriteAtom)
|
// const setQueue = useUpdateAtom(queueAtom)
|
||||||
const setCurrentTrack = useUpdateAtom(currentTrackAtom)
|
// const setCurrentTrack = useUpdateAtom(currentTrackAtom)
|
||||||
|
|
||||||
return (tracks: TrackExt | TrackExt[], insertBeforeindex?: number) =>
|
// return (tracks: TrackExt | TrackExt[], insertBeforeindex?: number) =>
|
||||||
trackPlayerCommands.enqueue(async () => {
|
// trackPlayerCommands.enqueue(async () => {
|
||||||
await TrackPlayer.add(tracks, insertBeforeindex)
|
// await TrackPlayer.add(tracks, insertBeforeindex)
|
||||||
|
|
||||||
const queue = await getQueue()
|
// const queue = await getQueue()
|
||||||
setQueue(queue)
|
// setQueue(queue)
|
||||||
setCurrentTrack(queue.length > 0 ? queue[await TrackPlayer.getCurrentTrack()] : undefined)
|
// setCurrentTrack(queue.length > 0 ? queue[await TrackPlayer.getCurrentTrack()] : undefined)
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
export const useReset = (enqueue = true) => {
|
export const useReset = (enqueue = true) => {
|
||||||
const setQueue = useUpdateAtom(queueWriteAtom)
|
const setQueue = useUpdateAtom(queueAtom)
|
||||||
const setCurrentTrack = useUpdateAtom(currentTrackAtom)
|
const setCurrentTrack = useUpdateAtom(currentTrackAtom)
|
||||||
|
|
||||||
const reset = async () => {
|
const reset = async () => {
|
||||||
@ -217,28 +229,63 @@ export const useReset = (enqueue = true) => {
|
|||||||
|
|
||||||
export const useSetQueue = () => {
|
export const useSetQueue = () => {
|
||||||
const setCurrentTrack = useUpdateAtom(currentTrackAtom)
|
const setCurrentTrack = useUpdateAtom(currentTrackAtom)
|
||||||
const setQueue = useUpdateAtom(queueWriteAtom)
|
const setQueue = useUpdateAtom(queueAtom)
|
||||||
const reset = useReset(false)
|
const reset = useReset(false)
|
||||||
|
const getShuffled = useAtomCallback(get => get(queueShuffledAtom))
|
||||||
|
|
||||||
return async (songs: Song[], name: string, playId?: string) =>
|
return async (songs: Song[], name: string, playTrack?: number, shuffle?: boolean) =>
|
||||||
trackPlayerCommands.enqueue(async () => {
|
trackPlayerCommands.enqueue(async () => {
|
||||||
|
const shuffleTracks = shuffle !== undefined ? shuffle : await getShuffled()
|
||||||
|
|
||||||
await TrackPlayer.setupPlayer()
|
await TrackPlayer.setupPlayer()
|
||||||
await reset()
|
await reset()
|
||||||
const tracks = songs.map(s => mapSongToTrack(s, name))
|
|
||||||
|
|
||||||
if (playId) {
|
if (songs.length === 0) {
|
||||||
setCurrentTrack(tracks.find(t => t.id === playId))
|
setCurrentTrack(undefined)
|
||||||
|
setQueue([])
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!playId) {
|
let tracks = songs.map(s => mapSongToTrack(s, name))
|
||||||
await TrackPlayer.add(tracks)
|
console.log(tracks.map(t => t.title))
|
||||||
} else if (playId === tracks[0].id) {
|
|
||||||
|
if (shuffleTracks) {
|
||||||
|
let trackIndexes = tracks.map((_t, i) => i)
|
||||||
|
const shuffleOrder: number[] = []
|
||||||
|
|
||||||
|
for (let i = trackIndexes.length; i--; i > 0) {
|
||||||
|
tracks[i].queueIndex = i
|
||||||
|
|
||||||
|
const randi = Math.floor(Math.random() * (i + 1))
|
||||||
|
shuffleOrder.push(trackIndexes[randi])
|
||||||
|
trackIndexes.splice(randi, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
tracks = shuffleOrder.map(i => tracks[i])
|
||||||
|
|
||||||
|
if (playTrack !== undefined) {
|
||||||
|
tracks = [
|
||||||
|
tracks.splice(
|
||||||
|
tracks.findIndex(t => t.queueIndex === playTrack),
|
||||||
|
1,
|
||||||
|
)[0],
|
||||||
|
...tracks,
|
||||||
|
]
|
||||||
|
playTrack = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(tracks.map(t => t.title))
|
||||||
|
|
||||||
|
playTrack = playTrack || 0
|
||||||
|
setCurrentTrack(tracks[playTrack])
|
||||||
|
|
||||||
|
if (playTrack === 0) {
|
||||||
await TrackPlayer.add(tracks)
|
await TrackPlayer.add(tracks)
|
||||||
await TrackPlayer.play()
|
await TrackPlayer.play()
|
||||||
} else {
|
} else {
|
||||||
const playIndex = tracks.findIndex(t => t.id === playId)
|
const tracks1 = tracks.slice(0, playTrack)
|
||||||
const tracks1 = tracks.slice(0, playIndex)
|
const tracks2 = tracks.slice(playTrack)
|
||||||
const tracks2 = tracks.slice(playIndex)
|
|
||||||
|
|
||||||
await TrackPlayer.add(tracks2)
|
await TrackPlayer.add(tracks2)
|
||||||
await TrackPlayer.play()
|
await TrackPlayer.play()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user