mirror of
https://github.com/austinried/subtracks.git
synced 2026-02-10 06:52:43 +01:00
use immer as middleware
This commit is contained in:
@@ -1,10 +1,8 @@
|
|||||||
import { CacheFile, CacheImageSize, CacheItemType, CacheItemTypeKey, CacheRequest } from '@app/models/cache'
|
import { CacheFile, CacheImageSize, CacheItemType, CacheItemTypeKey, CacheRequest } from '@app/models/cache'
|
||||||
import { mkdir, rmdir } from '@app/util/fs'
|
import { mkdir, rmdir } from '@app/util/fs'
|
||||||
import PromiseQueue from '@app/util/PromiseQueue'
|
import PromiseQueue from '@app/util/PromiseQueue'
|
||||||
import produce from 'immer'
|
|
||||||
import RNFS from 'react-native-fs'
|
import RNFS from 'react-native-fs'
|
||||||
import { GetState, SetState } from 'zustand'
|
import { GetStore, SetStore } from './store'
|
||||||
import { Store } from './store'
|
|
||||||
|
|
||||||
const queues: Record<CacheItemTypeKey, PromiseQueue> = {
|
const queues: Record<CacheItemTypeKey, PromiseQueue> = {
|
||||||
coverArt: new PromiseQueue(5),
|
coverArt: new PromiseQueue(5),
|
||||||
@@ -47,7 +45,7 @@ export const selectCache = {
|
|||||||
clearImageCache: (store: CacheSlice) => store.clearImageCache,
|
clearImageCache: (store: CacheSlice) => store.clearImageCache,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createCacheSlice = (set: SetState<Store>, get: GetState<Store>): CacheSlice => ({
|
export const createCacheSlice = (set: SetStore, get: GetStore): CacheSlice => ({
|
||||||
// cache: {},
|
// cache: {},
|
||||||
cacheDirs: {},
|
cacheDirs: {},
|
||||||
cacheFiles: {},
|
cacheFiles: {},
|
||||||
@@ -105,34 +103,28 @@ export const createCacheSlice = (set: SetState<Store>, get: GetState<Store>): Ca
|
|||||||
// },
|
// },
|
||||||
}).promise
|
}).promise
|
||||||
|
|
||||||
set(
|
set(state => {
|
||||||
produce<CacheSlice>(state => {
|
state.cacheRequests[activeServerId][key][itemId].progress = 1
|
||||||
state.cacheRequests[activeServerId][key][itemId].progress = 1
|
delete state.cacheRequests[activeServerId][key][itemId].promise
|
||||||
delete state.cacheRequests[activeServerId][key][itemId].promise
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
} catch {
|
} catch {
|
||||||
set(
|
set(state => {
|
||||||
produce<CacheSlice>(state => {
|
delete state.cacheFiles[activeServerId][key][itemId]
|
||||||
delete state.cacheFiles[activeServerId][key][itemId]
|
delete state.cacheRequests[activeServerId][key][itemId]
|
||||||
delete state.cacheRequests[activeServerId][key][itemId]
|
})
|
||||||
}),
|
}
|
||||||
)
|
})
|
||||||
|
set(state => {
|
||||||
|
state.cacheFiles[activeServerId][key][itemId] = {
|
||||||
|
path,
|
||||||
|
date: Date.now(),
|
||||||
|
permanent: false,
|
||||||
|
}
|
||||||
|
state.cacheRequests[activeServerId][key][itemId] = {
|
||||||
|
progress: 0,
|
||||||
|
promise,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
set(
|
|
||||||
produce<Store>(state => {
|
|
||||||
state.cacheFiles[activeServerId][key][itemId] = {
|
|
||||||
path,
|
|
||||||
date: Date.now(),
|
|
||||||
permanent: false,
|
|
||||||
}
|
|
||||||
state.cacheRequests[activeServerId][key][itemId] = {
|
|
||||||
progress: 0,
|
|
||||||
promise,
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
return await promise
|
return await promise
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -173,54 +165,48 @@ export const createCacheSlice = (set: SetState<Store>, get: GetState<Store>): Ca
|
|||||||
await mkdir(`${RNFS.DocumentDirectoryPath}/servers/${serverId}/${type}`)
|
await mkdir(`${RNFS.DocumentDirectoryPath}/servers/${serverId}/${type}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
set(
|
set(state => {
|
||||||
produce<CacheSlice>(state => {
|
state.cacheFiles[serverId] = {
|
||||||
state.cacheFiles[serverId] = {
|
song: {},
|
||||||
|
coverArt: {},
|
||||||
|
coverArtThumb: {},
|
||||||
|
artistArt: {},
|
||||||
|
artistArtThumb: {},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
get().prepareCache(serverId)
|
||||||
|
},
|
||||||
|
|
||||||
|
prepareCache: serverId => {
|
||||||
|
set(state => {
|
||||||
|
if (!state.cacheDirs[serverId]) {
|
||||||
|
state.cacheDirs[serverId] = {
|
||||||
|
song: `${RNFS.DocumentDirectoryPath}/servers/${serverId}/song`,
|
||||||
|
coverArt: `${RNFS.DocumentDirectoryPath}/servers/${serverId}/coverArt`,
|
||||||
|
coverArtThumb: `${RNFS.DocumentDirectoryPath}/servers/${serverId}/coverArtThumb`,
|
||||||
|
artistArt: `${RNFS.DocumentDirectoryPath}/servers/${serverId}/artistArt`,
|
||||||
|
artistArtThumb: `${RNFS.DocumentDirectoryPath}/servers/${serverId}/artistArtThumb`,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!state.cacheRequests[serverId]) {
|
||||||
|
state.cacheRequests[serverId] = {
|
||||||
song: {},
|
song: {},
|
||||||
coverArt: {},
|
coverArt: {},
|
||||||
coverArtThumb: {},
|
coverArtThumb: {},
|
||||||
artistArt: {},
|
artistArt: {},
|
||||||
artistArtThumb: {},
|
artistArtThumb: {},
|
||||||
}
|
}
|
||||||
}),
|
}
|
||||||
)
|
})
|
||||||
|
|
||||||
get().prepareCache(serverId)
|
|
||||||
},
|
|
||||||
|
|
||||||
prepareCache: serverId => {
|
|
||||||
set(
|
|
||||||
produce<CacheSlice>(state => {
|
|
||||||
if (!state.cacheDirs[serverId]) {
|
|
||||||
state.cacheDirs[serverId] = {
|
|
||||||
song: `${RNFS.DocumentDirectoryPath}/servers/${serverId}/song`,
|
|
||||||
coverArt: `${RNFS.DocumentDirectoryPath}/servers/${serverId}/coverArt`,
|
|
||||||
coverArtThumb: `${RNFS.DocumentDirectoryPath}/servers/${serverId}/coverArtThumb`,
|
|
||||||
artistArt: `${RNFS.DocumentDirectoryPath}/servers/${serverId}/artistArt`,
|
|
||||||
artistArtThumb: `${RNFS.DocumentDirectoryPath}/servers/${serverId}/artistArtThumb`,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!state.cacheRequests[serverId]) {
|
|
||||||
state.cacheRequests[serverId] = {
|
|
||||||
song: {},
|
|
||||||
coverArt: {},
|
|
||||||
coverArtThumb: {},
|
|
||||||
artistArt: {},
|
|
||||||
artistArtThumb: {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
pendingRemoval: {},
|
pendingRemoval: {},
|
||||||
|
|
||||||
removeCache: async serverId => {
|
removeCache: async serverId => {
|
||||||
set(
|
set(state => {
|
||||||
produce<CacheSlice>(state => {
|
state.pendingRemoval[serverId] = true
|
||||||
state.pendingRemoval[serverId] = true
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
const cacheRequests = get().cacheRequests[serverId]
|
const cacheRequests = get().cacheRequests[serverId]
|
||||||
const pendingRequests: Promise<void>[] = []
|
const pendingRequests: Promise<void>[] = []
|
||||||
@@ -235,21 +221,19 @@ export const createCacheSlice = (set: SetState<Store>, get: GetState<Store>): Ca
|
|||||||
await Promise.all(pendingRequests)
|
await Promise.all(pendingRequests)
|
||||||
await rmdir(`${RNFS.DocumentDirectoryPath}/servers/${serverId}`)
|
await rmdir(`${RNFS.DocumentDirectoryPath}/servers/${serverId}`)
|
||||||
|
|
||||||
set(
|
set(state => {
|
||||||
produce<CacheSlice>(state => {
|
delete state.pendingRemoval[serverId]
|
||||||
delete state.pendingRemoval[serverId]
|
|
||||||
|
|
||||||
if (state.cacheDirs[serverId]) {
|
if (state.cacheDirs[serverId]) {
|
||||||
delete state.cacheDirs[serverId]
|
delete state.cacheDirs[serverId]
|
||||||
}
|
}
|
||||||
if (state.cacheFiles[serverId]) {
|
if (state.cacheFiles[serverId]) {
|
||||||
delete state.cacheFiles[serverId]
|
delete state.cacheFiles[serverId]
|
||||||
}
|
}
|
||||||
if (state.cacheRequests[serverId]) {
|
if (state.cacheRequests[serverId]) {
|
||||||
delete state.cacheRequests[serverId]
|
delete state.cacheRequests[serverId]
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
clearImageCache: async () => {
|
clearImageCache: async () => {
|
||||||
@@ -270,14 +254,12 @@ export const createCacheSlice = (set: SetState<Store>, get: GetState<Store>): Ca
|
|||||||
await rmdir(get().cacheDirs[serverId].artistArt)
|
await rmdir(get().cacheDirs[serverId].artistArt)
|
||||||
await mkdir(get().cacheDirs[serverId].artistArt)
|
await mkdir(get().cacheDirs[serverId].artistArt)
|
||||||
|
|
||||||
set(
|
set(state => {
|
||||||
produce<CacheSlice>(state => {
|
state.cacheFiles[serverId].coverArt = {}
|
||||||
state.cacheFiles[serverId].coverArt = {}
|
state.cacheFiles[serverId].coverArtThumb = {}
|
||||||
state.cacheFiles[serverId].coverArtThumb = {}
|
state.cacheFiles[serverId].artistArt = {}
|
||||||
state.cacheFiles[serverId].artistArt = {}
|
state.cacheFiles[serverId].artistArtThumb = {}
|
||||||
state.cacheFiles[serverId].artistArtThumb = {}
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Album, Artist, ArtistInfo, Playlist, SearchResults, Song } from '@app/models/library'
|
import { Album, Artist, ArtistInfo, Playlist, SearchResults, Song } from '@app/models/library'
|
||||||
import { ById, OneToMany } from '@app/models/state'
|
import { ById, OneToMany } from '@app/models/state'
|
||||||
import { Store } from '@app/state/store'
|
import { GetStore, SetStore, Store } from '@app/state/store'
|
||||||
import {
|
import {
|
||||||
AlbumID3Element,
|
AlbumID3Element,
|
||||||
ArtistID3Element,
|
ArtistID3Element,
|
||||||
@@ -24,10 +24,8 @@ import {
|
|||||||
} from '@app/subsonic/responses'
|
} from '@app/subsonic/responses'
|
||||||
import PromiseQueue from '@app/util/PromiseQueue'
|
import PromiseQueue from '@app/util/PromiseQueue'
|
||||||
import { reduceById, mergeById } from '@app/util/state'
|
import { reduceById, mergeById } from '@app/util/state'
|
||||||
import produce from 'immer'
|
|
||||||
import { WritableDraft } from 'immer/dist/types/types-external'
|
import { WritableDraft } from 'immer/dist/types/types-external'
|
||||||
import pick from 'lodash.pick'
|
import pick from 'lodash.pick'
|
||||||
import { GetState, SetState } from 'zustand'
|
|
||||||
|
|
||||||
const songCoverArtQueue = new PromiseQueue(2)
|
const songCoverArtQueue = new PromiseQueue(2)
|
||||||
|
|
||||||
@@ -84,7 +82,7 @@ const defaultEntities = () => ({
|
|||||||
songs: {},
|
songs: {},
|
||||||
})
|
})
|
||||||
|
|
||||||
export const createLibrarySlice = (set: SetState<Store>, get: GetState<Store>): LibrarySlice => ({
|
export const createLibrarySlice = (set: SetStore, get: GetStore): LibrarySlice => ({
|
||||||
entities: defaultEntities(),
|
entities: defaultEntities(),
|
||||||
|
|
||||||
resetLibrary: state => {
|
resetLibrary: state => {
|
||||||
@@ -92,9 +90,7 @@ export const createLibrarySlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
state.entities = defaultEntities()
|
state.entities = defaultEntities()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
set(store => {
|
set(store => (store.entities = defaultEntities()))
|
||||||
store.entities = defaultEntities()
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchArtists: async () => {
|
fetchArtists: async () => {
|
||||||
@@ -113,12 +109,10 @@ export const createLibrarySlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
const artists = response.data.artists.map(mapArtist)
|
const artists = response.data.artists.map(mapArtist)
|
||||||
const artistsById = reduceById(artists)
|
const artistsById = reduceById(artists)
|
||||||
|
|
||||||
set(
|
set(state => {
|
||||||
produce<LibrarySlice>(state => {
|
state.entities.artists = artistsById
|
||||||
state.entities.artists = artistsById
|
state.entities.artistAlbums = pick(state.entities.artistAlbums, mapId(artists))
|
||||||
state.entities.artistAlbums = pick(state.entities.artistAlbums, mapId(artists))
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchArtist: async id => {
|
fetchArtist: async id => {
|
||||||
@@ -138,13 +132,11 @@ export const createLibrarySlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
const albums = response.data.albums.map(mapAlbum)
|
const albums = response.data.albums.map(mapAlbum)
|
||||||
const albumsById = reduceById(albums)
|
const albumsById = reduceById(albums)
|
||||||
|
|
||||||
set(
|
set(state => {
|
||||||
produce<LibrarySlice>(state => {
|
state.entities.artists[id] = artist
|
||||||
state.entities.artists[id] = artist
|
state.entities.artistAlbums[id] = mapId(albums)
|
||||||
state.entities.artistAlbums[id] = mapId(albums)
|
mergeById(state.entities.albums, albumsById)
|
||||||
mergeById(state.entities.albums, albumsById)
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchArtistInfo: async id => {
|
fetchArtistInfo: async id => {
|
||||||
@@ -162,11 +154,9 @@ export const createLibrarySlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
|
|
||||||
const info = mapArtistInfo(id, response.data.artistInfo)
|
const info = mapArtistInfo(id, response.data.artistInfo)
|
||||||
|
|
||||||
set(
|
set(state => {
|
||||||
produce<LibrarySlice>(state => {
|
state.entities.artistInfo[id] = info
|
||||||
state.entities.artistInfo[id] = info
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchArtistTopSongs: async artistName => {
|
fetchArtistTopSongs: async artistName => {
|
||||||
@@ -187,12 +177,10 @@ export const createLibrarySlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
|
|
||||||
get()._fixSongCoverArt(topSongs)
|
get()._fixSongCoverArt(topSongs)
|
||||||
|
|
||||||
set(
|
set(state => {
|
||||||
produce<LibrarySlice>(state => {
|
mergeById(state.entities.songs, topSongsById)
|
||||||
mergeById(state.entities.songs, topSongsById)
|
state.entities.artistNameTopSongs[artistName] = mapId(topSongs)
|
||||||
state.entities.artistNameTopSongs[artistName] = mapId(topSongs)
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchAlbum: async id => {
|
fetchAlbum: async id => {
|
||||||
@@ -214,13 +202,11 @@ export const createLibrarySlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
|
|
||||||
get()._fixSongCoverArt(songs)
|
get()._fixSongCoverArt(songs)
|
||||||
|
|
||||||
set(
|
set(state => {
|
||||||
produce<LibrarySlice>(state => {
|
state.entities.albums[id] = album
|
||||||
state.entities.albums[id] = album
|
state.entities.albumSongs[id] = mapId(songs)
|
||||||
state.entities.albumSongs[id] = mapId(songs)
|
mergeById(state.entities.songs, songsById)
|
||||||
mergeById(state.entities.songs, songsById)
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchPlaylists: async () => {
|
fetchPlaylists: async () => {
|
||||||
@@ -239,12 +225,10 @@ export const createLibrarySlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
const playlists = response.data.playlists.map(mapPlaylist)
|
const playlists = response.data.playlists.map(mapPlaylist)
|
||||||
const playlistsById = reduceById(playlists)
|
const playlistsById = reduceById(playlists)
|
||||||
|
|
||||||
set(
|
set(state => {
|
||||||
produce<LibrarySlice>(state => {
|
state.entities.playlists = playlistsById
|
||||||
state.entities.playlists = playlistsById
|
state.entities.playlistSongs = pick(state.entities.playlistSongs, mapId(playlists))
|
||||||
state.entities.playlistSongs = pick(state.entities.playlistSongs, mapId(playlists))
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchPlaylist: async id => {
|
fetchPlaylist: async id => {
|
||||||
@@ -266,13 +250,11 @@ export const createLibrarySlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
|
|
||||||
get()._fixSongCoverArt(songs)
|
get()._fixSongCoverArt(songs)
|
||||||
|
|
||||||
set(
|
set(state => {
|
||||||
produce<LibrarySlice>(state => {
|
state.entities.playlists[id] = playlist
|
||||||
state.entities.playlists[id] = playlist
|
state.entities.playlistSongs[id] = mapId(songs)
|
||||||
state.entities.playlistSongs[id] = mapId(songs)
|
mergeById(state.entities.songs, songsById)
|
||||||
mergeById(state.entities.songs, songsById)
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchSong: async id => {
|
fetchSong: async id => {
|
||||||
@@ -292,11 +274,9 @@ export const createLibrarySlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
|
|
||||||
get()._fixSongCoverArt([song])
|
get()._fixSongCoverArt([song])
|
||||||
|
|
||||||
set(
|
set(state => {
|
||||||
produce<LibrarySlice>(state => {
|
state.entities.songs[id] = song
|
||||||
state.entities.songs[id] = song
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchAlbumList: async params => {
|
fetchAlbumList: async params => {
|
||||||
@@ -315,11 +295,7 @@ export const createLibrarySlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
const albums = response.data.albums.map(mapAlbum)
|
const albums = response.data.albums.map(mapAlbum)
|
||||||
const albumsById = reduceById(albums)
|
const albumsById = reduceById(albums)
|
||||||
|
|
||||||
set(
|
set(state => mergeById(state.entities.albums, albumsById))
|
||||||
produce<LibrarySlice>(state => {
|
|
||||||
mergeById(state.entities.albums, albumsById)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
return mapId(albums)
|
return mapId(albums)
|
||||||
},
|
},
|
||||||
@@ -348,13 +324,11 @@ export const createLibrarySlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
|
|
||||||
get()._fixSongCoverArt(songs)
|
get()._fixSongCoverArt(songs)
|
||||||
|
|
||||||
set(
|
set(state => {
|
||||||
produce<LibrarySlice>(state => {
|
mergeById(state.entities.artists, artistsById)
|
||||||
mergeById(state.entities.artists, artistsById)
|
mergeById(state.entities.albums, albumsById)
|
||||||
mergeById(state.entities.albums, albumsById)
|
mergeById(state.entities.songs, songsById)
|
||||||
mergeById(state.entities.songs, songsById)
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
artists: mapId(artists),
|
artists: mapId(artists),
|
||||||
@@ -387,22 +361,18 @@ export const createLibrarySlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
const item = get().entities[entity][id]
|
const item = get().entities[entity][id]
|
||||||
const originalValue = item ? item.starred : null
|
const originalValue = item ? item.starred : null
|
||||||
|
|
||||||
set(
|
set(state => {
|
||||||
produce<LibrarySlice>(state => {
|
state.entities[entity][id].starred = new Date()
|
||||||
state.entities[entity][id].starred = new Date()
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await client.star(params)
|
await client.star(params)
|
||||||
} catch {
|
} catch {
|
||||||
set(
|
set(state => {
|
||||||
produce<LibrarySlice>(state => {
|
if (originalValue !== null) {
|
||||||
if (originalValue !== null) {
|
state.entities[entity][id].starred = originalValue
|
||||||
state.entities[entity][id].starred = originalValue
|
}
|
||||||
}
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -430,22 +400,18 @@ export const createLibrarySlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
const item = get().entities[entity][id]
|
const item = get().entities[entity][id]
|
||||||
const originalValue = item ? item.starred : null
|
const originalValue = item ? item.starred : null
|
||||||
|
|
||||||
set(
|
set(state => {
|
||||||
produce<LibrarySlice>(state => {
|
state.entities[entity][id].starred = undefined
|
||||||
state.entities[entity][id].starred = undefined
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await client.unstar(params)
|
await client.unstar(params)
|
||||||
} catch {
|
} catch {
|
||||||
set(
|
set(state => {
|
||||||
produce<LibrarySlice>(state => {
|
if (originalValue !== null) {
|
||||||
if (originalValue !== null) {
|
state.entities[entity][id].starred = originalValue
|
||||||
state.entities[entity][id].starred = originalValue
|
}
|
||||||
}
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -479,14 +445,12 @@ export const createLibrarySlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
.then(res => {
|
.then(res => {
|
||||||
const album = mapAlbum(res.data.album)
|
const album = mapAlbum(res.data.album)
|
||||||
|
|
||||||
set(
|
set(state => {
|
||||||
produce<LibrarySlice>(state => {
|
state.entities.albums[album.id] = album
|
||||||
state.entities.albums[album.id] = album
|
for (const song of albumsToGet[album.id]) {
|
||||||
for (const song of albumsToGet[album.id]) {
|
state.entities.songs[song.id].coverArt = album.coverArt
|
||||||
state.entities.songs[song.id].coverArt = album.coverArt
|
}
|
||||||
}
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import { AppSettings, ArtistFilterSettings, AlbumFilterSettings, Server } from '@app/models/settings'
|
import { AlbumFilterSettings, AppSettings, ArtistFilterSettings, Server } from '@app/models/settings'
|
||||||
import { Store } from '@app/state/store'
|
import { GetStore, SetStore } from '@app/state/store'
|
||||||
import { SubsonicApiClient } from '@app/subsonic/api'
|
import { SubsonicApiClient } from '@app/subsonic/api'
|
||||||
import produce from 'immer'
|
|
||||||
import { GetState, SetState } from 'zustand'
|
|
||||||
|
|
||||||
export type SettingsSlice = {
|
export type SettingsSlice = {
|
||||||
settings: AppSettings
|
settings: AppSettings
|
||||||
@@ -66,7 +64,7 @@ export const selectSettings = {
|
|||||||
libraryArtistFilter: (state: SettingsSlice) => state.settings.screens.library.artists,
|
libraryArtistFilter: (state: SettingsSlice) => state.settings.screens.library.artists,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createSettingsSlice = (set: SetState<Store>, get: GetState<Store>): SettingsSlice => ({
|
export const createSettingsSlice = (set: SetStore, get: GetStore): SettingsSlice => ({
|
||||||
settings: {
|
settings: {
|
||||||
servers: [],
|
servers: [],
|
||||||
screens: {
|
screens: {
|
||||||
@@ -99,8 +97,8 @@ export const createSettingsSlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
const newActiveServer = servers.find(s => s.id === id)
|
const newActiveServer = servers.find(s => s.id === id)
|
||||||
|
|
||||||
if (!newActiveServer) {
|
if (!newActiveServer) {
|
||||||
set({
|
set(state => {
|
||||||
client: undefined,
|
state.client = undefined
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -111,13 +109,11 @@ export const createSettingsSlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
|
|
||||||
get().prepareCache(newActiveServer.id)
|
get().prepareCache(newActiveServer.id)
|
||||||
|
|
||||||
set(
|
set(state => {
|
||||||
produce<Store>(state => {
|
state.settings.activeServer = newActiveServer.id
|
||||||
state.settings.activeServer = newActiveServer.id
|
state.client = new SubsonicApiClient(newActiveServer)
|
||||||
state.client = new SubsonicApiClient(newActiveServer)
|
get().resetLibrary(state)
|
||||||
get().resetLibrary(state)
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getActiveServer: () => get().settings.servers.find(s => s.id === get().settings.activeServer),
|
getActiveServer: () => get().settings.servers.find(s => s.id === get().settings.activeServer),
|
||||||
@@ -125,11 +121,7 @@ export const createSettingsSlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
addServer: async server => {
|
addServer: async server => {
|
||||||
await get().createCache(server.id)
|
await get().createCache(server.id)
|
||||||
|
|
||||||
set(
|
set(state => state.settings.servers.push(server))
|
||||||
produce<SettingsSlice>(state => {
|
|
||||||
state.settings.servers.push(server)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
if (get().settings.servers.length === 1) {
|
if (get().settings.servers.length === 1) {
|
||||||
get().setActiveServer(server.id)
|
get().setActiveServer(server.id)
|
||||||
@@ -139,23 +131,19 @@ export const createSettingsSlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
removeServer: async id => {
|
removeServer: async id => {
|
||||||
await get().removeCache(id)
|
await get().removeCache(id)
|
||||||
|
|
||||||
set(
|
set(state => {
|
||||||
produce<SettingsSlice>(state => {
|
state.settings.servers = state.settings.servers.filter(s => s.id !== id)
|
||||||
state.settings.servers = state.settings.servers.filter(s => s.id !== id)
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
updateServer: server => {
|
updateServer: server => {
|
||||||
set(
|
set(state => {
|
||||||
produce<SettingsSlice>(state => {
|
state.settings.servers = replaceIndex(
|
||||||
state.settings.servers = replaceIndex(
|
state.settings.servers,
|
||||||
state.settings.servers,
|
state.settings.servers.findIndex(s => s.id === server.id),
|
||||||
state.settings.servers.findIndex(s => s.id === server.id),
|
server,
|
||||||
server,
|
)
|
||||||
)
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
if (get().settings.activeServer === server.id) {
|
if (get().settings.activeServer === server.id) {
|
||||||
get().setActiveServer(server.id, true)
|
get().setActiveServer(server.id, true)
|
||||||
@@ -163,29 +151,22 @@ export const createSettingsSlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
},
|
},
|
||||||
|
|
||||||
setScrobble: scrobble => {
|
setScrobble: scrobble => {
|
||||||
set(
|
set(state => {
|
||||||
produce<SettingsSlice>(state => {
|
state.settings.scrobble = scrobble
|
||||||
state.settings.scrobble = scrobble
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setEstimateContentLength: estimateContentLength => {
|
setEstimateContentLength: estimateContentLength => {
|
||||||
set(
|
set(state => {
|
||||||
produce<SettingsSlice>(state => {
|
state.settings.estimateContentLength = estimateContentLength
|
||||||
state.settings.estimateContentLength = estimateContentLength
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
get().rebuildQueue()
|
get().rebuildQueue()
|
||||||
},
|
},
|
||||||
|
|
||||||
setMaxBitrateWifi: maxBitrateWifi => {
|
setMaxBitrateWifi: maxBitrateWifi => {
|
||||||
set(
|
set(state => {
|
||||||
produce<SettingsSlice>(state => {
|
state.settings.maxBitrateWifi = maxBitrateWifi
|
||||||
state.settings.maxBitrateWifi = maxBitrateWifi
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
if (get().netState === 'wifi') {
|
if (get().netState === 'wifi') {
|
||||||
get().rebuildQueue()
|
get().rebuildQueue()
|
||||||
@@ -193,11 +174,9 @@ export const createSettingsSlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
},
|
},
|
||||||
|
|
||||||
setMaxBitrateMobile: maxBitrateMobile => {
|
setMaxBitrateMobile: maxBitrateMobile => {
|
||||||
set(
|
set(state => {
|
||||||
produce<SettingsSlice>(state => {
|
state.settings.maxBitrateMobile = maxBitrateMobile
|
||||||
state.settings.maxBitrateMobile = maxBitrateMobile
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
if (get().netState === 'mobile') {
|
if (get().netState === 'mobile') {
|
||||||
get().rebuildQueue()
|
get().rebuildQueue()
|
||||||
@@ -209,11 +188,9 @@ export const createSettingsSlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
set(
|
set(state => {
|
||||||
produce<SettingsSlice>(state => {
|
state.settings.minBuffer = Math.max(1, Math.min(minBuffer, state.settings.maxBuffer / 2))
|
||||||
state.settings.minBuffer = Math.max(1, Math.min(minBuffer, state.settings.maxBuffer / 2))
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
get().rebuildQueue()
|
get().rebuildQueue()
|
||||||
},
|
},
|
||||||
@@ -223,11 +200,9 @@ export const createSettingsSlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
set(
|
set(state => {
|
||||||
produce<SettingsSlice>(state => {
|
state.settings.maxBuffer = Math.min(5 * 60, Math.max(maxBuffer, state.settings.minBuffer * 2))
|
||||||
state.settings.maxBuffer = Math.min(5 * 60, Math.max(maxBuffer, state.settings.minBuffer * 2))
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
get().rebuildQueue()
|
get().rebuildQueue()
|
||||||
},
|
},
|
||||||
@@ -253,19 +228,15 @@ export const createSettingsSlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
},
|
},
|
||||||
|
|
||||||
setLibraryAlbumFilter: filter => {
|
setLibraryAlbumFilter: filter => {
|
||||||
set(
|
set(state => {
|
||||||
produce<SettingsSlice>(state => {
|
state.settings.screens.library.albums = filter
|
||||||
state.settings.screens.library.albums = filter
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setLibraryArtistFiler: filter => {
|
setLibraryArtistFiler: filter => {
|
||||||
set(
|
set(state => {
|
||||||
produce<SettingsSlice>(state => {
|
state.settings.screens.library.artists = filter
|
||||||
state.settings.screens.library.artists = filter
|
})
|
||||||
}),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import { createSettingsSlice, SettingsSlice } from '@app/state/settings'
|
import { createSettingsSlice, SettingsSlice } from '@app/state/settings'
|
||||||
import AsyncStorage from '@react-native-async-storage/async-storage'
|
import AsyncStorage from '@react-native-async-storage/async-storage'
|
||||||
import equal from 'fast-deep-equal/es6/react'
|
import equal from 'fast-deep-equal/es6/react'
|
||||||
import create, { GetState, Mutate, SetState, StateSelector, StoreApi } from 'zustand'
|
import create, { GetState, Mutate, SetState, State, StateCreator, StateSelector, StoreApi } from 'zustand'
|
||||||
import { persist, subscribeWithSelector } from 'zustand/middleware'
|
import { persist, subscribeWithSelector } from 'zustand/middleware'
|
||||||
import { CacheSlice, createCacheSlice } from './cache'
|
import { CacheSlice, createCacheSlice } from './cache'
|
||||||
import { createLibrarySlice, LibrarySlice } from './library'
|
import { createLibrarySlice, LibrarySlice } from './library'
|
||||||
import migrations from './migrations'
|
import migrations from './migrations'
|
||||||
import { createTrackPlayerSlice, TrackPlayerSlice } from './trackplayer'
|
import { createTrackPlayerSlice, TrackPlayerSlice } from './trackplayer'
|
||||||
import { createTrackPlayerMapSlice, TrackPlayerMapSlice } from './trackplayermap'
|
import { createTrackPlayerMapSlice, TrackPlayerMapSlice } from './trackplayermap'
|
||||||
|
import produce, { Draft } from 'immer'
|
||||||
|
import { WritableDraft } from 'immer/dist/internal'
|
||||||
|
|
||||||
const DB_VERSION = migrations.length
|
const DB_VERSION = migrations.length
|
||||||
|
|
||||||
@@ -20,6 +22,37 @@ export type Store = SettingsSlice &
|
|||||||
setHydrated: (hydrated: boolean) => void
|
setHydrated: (hydrated: boolean) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// taken from zustand test examples:
|
||||||
|
// https://github.com/pmndrs/zustand/blob/v3.7.1/tests/middlewareTypes.test.tsx#L20
|
||||||
|
const immer =
|
||||||
|
<
|
||||||
|
T extends State,
|
||||||
|
CustomSetState extends SetState<T>,
|
||||||
|
CustomGetState extends GetState<T>,
|
||||||
|
CustomStoreApi extends StoreApi<T>,
|
||||||
|
>(
|
||||||
|
config: StateCreator<
|
||||||
|
T,
|
||||||
|
(partial: ((draft: Draft<T>) => void) | T, replace?: boolean) => void,
|
||||||
|
CustomGetState,
|
||||||
|
CustomStoreApi
|
||||||
|
>,
|
||||||
|
): StateCreator<T, CustomSetState, CustomGetState, CustomStoreApi> =>
|
||||||
|
(set, get, api) =>
|
||||||
|
config(
|
||||||
|
(partial, replace) => {
|
||||||
|
const nextState = typeof partial === 'function' ? produce(partial as (state: Draft<T>) => T) : (partial as T)
|
||||||
|
return set(nextState, replace)
|
||||||
|
},
|
||||||
|
get,
|
||||||
|
api,
|
||||||
|
)
|
||||||
|
|
||||||
|
export type SetStore = (partial: Store | ((draft: WritableDraft<Store>) => void), replace?: boolean | undefined) => void
|
||||||
|
export type GetStore = GetState<Store>
|
||||||
|
|
||||||
|
// types taken from zustand test examples:
|
||||||
|
// https://github.com/pmndrs/zustand/blob/v3.7.1/tests/middlewareTypes.test.tsx#L584
|
||||||
export const useStore = create<
|
export const useStore = create<
|
||||||
Store,
|
Store,
|
||||||
SetState<Store>,
|
SetState<Store>,
|
||||||
@@ -28,7 +61,7 @@ export const useStore = create<
|
|||||||
>(
|
>(
|
||||||
subscribeWithSelector(
|
subscribeWithSelector(
|
||||||
persist(
|
persist(
|
||||||
(set, get) => ({
|
immer((set, get) => ({
|
||||||
...createSettingsSlice(set, get),
|
...createSettingsSlice(set, get),
|
||||||
...createLibrarySlice(set, get),
|
...createLibrarySlice(set, get),
|
||||||
...createTrackPlayerSlice(set, get),
|
...createTrackPlayerSlice(set, get),
|
||||||
@@ -36,13 +69,15 @@ export const useStore = create<
|
|||||||
...createCacheSlice(set, get),
|
...createCacheSlice(set, get),
|
||||||
|
|
||||||
hydrated: false,
|
hydrated: false,
|
||||||
setHydrated: hydrated => set({ hydrated }),
|
setHydrated: hydrated =>
|
||||||
}),
|
set(state => {
|
||||||
|
state.hydrated = hydrated
|
||||||
|
}),
|
||||||
|
})),
|
||||||
{
|
{
|
||||||
name: '@appStore',
|
name: '@appStore',
|
||||||
version: DB_VERSION,
|
version: DB_VERSION,
|
||||||
getStorage: () => AsyncStorage,
|
getStorage: () => AsyncStorage,
|
||||||
// whitelist: ['settings', 'cacheFiles'],
|
|
||||||
partialize: state => ({ settings: state.settings, cacheFiles: state.cacheFiles }),
|
partialize: state => ({ settings: state.settings, cacheFiles: state.cacheFiles }),
|
||||||
onRehydrateStorage: _preState => {
|
onRehydrateStorage: _preState => {
|
||||||
return async (postState, _error) => {
|
return async (postState, _error) => {
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ import { Song } from '@app/models/library'
|
|||||||
import PromiseQueue from '@app/util/PromiseQueue'
|
import PromiseQueue from '@app/util/PromiseQueue'
|
||||||
import produce from 'immer'
|
import produce from 'immer'
|
||||||
import TrackPlayer, { PlayerOptions, RepeatMode, State, Track } from 'react-native-track-player'
|
import TrackPlayer, { PlayerOptions, RepeatMode, State, Track } from 'react-native-track-player'
|
||||||
import { GetState, SetState } from 'zustand'
|
import { GetStore, SetStore } from './store'
|
||||||
import { Store } from './store'
|
|
||||||
|
|
||||||
export type TrackExt = Track & {
|
export type TrackExt = Track & {
|
||||||
id: string
|
id: string
|
||||||
@@ -114,15 +113,24 @@ export const selectTrackPlayer = {
|
|||||||
|
|
||||||
export const trackPlayerCommands = new PromiseQueue(1)
|
export const trackPlayerCommands = new PromiseQueue(1)
|
||||||
|
|
||||||
export const createTrackPlayerSlice = (set: SetState<Store>, get: GetState<Store>): TrackPlayerSlice => ({
|
export const createTrackPlayerSlice = (set: SetStore, get: GetStore): TrackPlayerSlice => ({
|
||||||
queueName: undefined,
|
queueName: undefined,
|
||||||
setQueueName: name => set({ queueName: name }),
|
setQueueName: name =>
|
||||||
|
set(state => {
|
||||||
|
state.queueName = name
|
||||||
|
}),
|
||||||
|
|
||||||
queueContextType: undefined,
|
queueContextType: undefined,
|
||||||
setQueueContextType: queueContextType => set({ queueContextType }),
|
setQueueContextType: queueContextType =>
|
||||||
|
set(state => {
|
||||||
|
state.queueContextType = queueContextType
|
||||||
|
}),
|
||||||
|
|
||||||
queueContextId: undefined,
|
queueContextId: undefined,
|
||||||
setQueueContextId: queueContextId => set({ queueContextId }),
|
setQueueContextId: queueContextId =>
|
||||||
|
set(state => {
|
||||||
|
state.queueContextId = queueContextId
|
||||||
|
}),
|
||||||
|
|
||||||
shuffleOrder: undefined,
|
shuffleOrder: undefined,
|
||||||
toggleShuffle: async () => {
|
toggleShuffle: async () => {
|
||||||
@@ -140,7 +148,9 @@ export const createTrackPlayerSlice = (set: SetState<Store>, get: GetState<Store
|
|||||||
}
|
}
|
||||||
|
|
||||||
await TrackPlayer.add(tracks)
|
await TrackPlayer.add(tracks)
|
||||||
set({ shuffleOrder })
|
set(state => {
|
||||||
|
state.shuffleOrder = shuffleOrder
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
const tracks = unshuffleTracks(queue, queueShuffleOrder)
|
const tracks = unshuffleTracks(queue, queueShuffleOrder)
|
||||||
|
|
||||||
@@ -155,10 +165,14 @@ export const createTrackPlayerSlice = (set: SetState<Store>, get: GetState<Store
|
|||||||
await TrackPlayer.add(tracks)
|
await TrackPlayer.add(tracks)
|
||||||
}
|
}
|
||||||
|
|
||||||
set({ shuffleOrder: undefined })
|
set(state => {
|
||||||
|
state.shuffleOrder = undefined
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
set({ queue: await getQueue() })
|
set(async state => {
|
||||||
|
state.queue = await getQueue()
|
||||||
|
})
|
||||||
get().setCurrentTrackIdx(await getCurrentTrack())
|
get().setCurrentTrackIdx(await getCurrentTrack())
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -182,12 +196,17 @@ export const createTrackPlayerSlice = (set: SetState<Store>, get: GetState<Store
|
|||||||
}
|
}
|
||||||
|
|
||||||
await TrackPlayer.setRepeatMode(nextMode)
|
await TrackPlayer.setRepeatMode(nextMode)
|
||||||
set({ repeatMode: nextMode })
|
set(state => {
|
||||||
|
state.repeatMode = nextMode
|
||||||
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
playerState: State.None,
|
playerState: State.None,
|
||||||
setPlayerState: playerState => set({ playerState }),
|
setPlayerState: playerState =>
|
||||||
|
set(state => {
|
||||||
|
state.playerState = playerState
|
||||||
|
}),
|
||||||
|
|
||||||
currentTrack: undefined,
|
currentTrack: undefined,
|
||||||
currentTrackIdx: undefined,
|
currentTrackIdx: undefined,
|
||||||
@@ -201,7 +220,10 @@ export const createTrackPlayerSlice = (set: SetState<Store>, get: GetState<Store
|
|||||||
},
|
},
|
||||||
|
|
||||||
duckPaused: false,
|
duckPaused: false,
|
||||||
setDuckPaused: duckPaused => set({ duckPaused }),
|
setDuckPaused: duckPaused =>
|
||||||
|
set(state => {
|
||||||
|
state.duckPaused = duckPaused
|
||||||
|
}),
|
||||||
|
|
||||||
queue: [],
|
queue: [],
|
||||||
setQueue: async (songs, name, contextType, contextId, playTrack, shuffle) => {
|
setQueue: async (songs, name, contextType, contextId, playTrack, shuffle) => {
|
||||||
@@ -219,21 +241,25 @@ export const createTrackPlayerSlice = (set: SetState<Store>, get: GetState<Store
|
|||||||
|
|
||||||
if (shuffled) {
|
if (shuffled) {
|
||||||
const { tracks, shuffleOrder } = shuffleTracks(queue, playTrack)
|
const { tracks, shuffleOrder } = shuffleTracks(queue, playTrack)
|
||||||
set({ shuffleOrder })
|
set(state => {
|
||||||
|
state.shuffleOrder = shuffleOrder
|
||||||
|
})
|
||||||
queue = tracks
|
queue = tracks
|
||||||
playTrack = 0
|
playTrack = 0
|
||||||
} else {
|
} else {
|
||||||
set({ shuffleOrder: undefined })
|
set(state => {
|
||||||
|
state.shuffleOrder = undefined
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
playTrack = playTrack || 0
|
playTrack = playTrack || 0
|
||||||
|
|
||||||
try {
|
try {
|
||||||
set({
|
set(state => {
|
||||||
queue,
|
state.queue = queue
|
||||||
queueName: name,
|
state.queueName = name
|
||||||
queueContextType: contextType,
|
state.queueContextType = contextType
|
||||||
queueContextId: contextId,
|
state.queueContextId = contextId
|
||||||
})
|
})
|
||||||
get().setCurrentTrackIdx(playTrack)
|
get().setCurrentTrackIdx(playTrack)
|
||||||
|
|
||||||
@@ -256,7 +282,10 @@ export const createTrackPlayerSlice = (set: SetState<Store>, get: GetState<Store
|
|||||||
},
|
},
|
||||||
|
|
||||||
progress: { position: 0, duration: 0, buffered: 0 },
|
progress: { position: 0, duration: 0, buffered: 0 },
|
||||||
setProgress: progress => set({ progress }),
|
setProgress: progress =>
|
||||||
|
set(state => {
|
||||||
|
state.progress = progress
|
||||||
|
}),
|
||||||
|
|
||||||
scrobbleTrack: async id => {
|
scrobbleTrack: async id => {
|
||||||
const client = get().client
|
const client = get().client
|
||||||
@@ -278,7 +307,9 @@ export const createTrackPlayerSlice = (set: SetState<Store>, get: GetState<Store
|
|||||||
if (netState === get().netState) {
|
if (netState === get().netState) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
set({ netState })
|
set(state => {
|
||||||
|
state.netState = netState
|
||||||
|
})
|
||||||
get().rebuildQueue()
|
get().rebuildQueue()
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -290,7 +321,7 @@ export const createTrackPlayerSlice = (set: SetState<Store>, get: GetState<Store
|
|||||||
}
|
}
|
||||||
|
|
||||||
const currentTrack = await getCurrentTrack()
|
const currentTrack = await getCurrentTrack()
|
||||||
const state = await getPlayerState()
|
const playerState = await getPlayerState()
|
||||||
const position = (await TrackPlayer.getPosition()) || 0
|
const position = (await TrackPlayer.getPosition()) || 0
|
||||||
|
|
||||||
const queueName = get().queueName
|
const queueName = get().queueName
|
||||||
@@ -308,11 +339,11 @@ export const createTrackPlayerSlice = (set: SetState<Store>, get: GetState<Store
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
set({
|
set(state => {
|
||||||
queue,
|
state.queue = queue
|
||||||
queueName,
|
state.queueName = queueName
|
||||||
queueContextId,
|
state.queueContextType = queueContextType
|
||||||
queueContextType,
|
state.queueContextId = queueContextId
|
||||||
})
|
})
|
||||||
get().setCurrentTrackIdx(currentTrack)
|
get().setCurrentTrackIdx(currentTrack)
|
||||||
|
|
||||||
@@ -324,7 +355,7 @@ export const createTrackPlayerSlice = (set: SetState<Store>, get: GetState<Store
|
|||||||
|
|
||||||
await TrackPlayer.seekTo(position)
|
await TrackPlayer.seekTo(position)
|
||||||
|
|
||||||
if (state === State.Playing || forcePlay) {
|
if (playerState === State.Playing || forcePlay) {
|
||||||
await TrackPlayer.play()
|
await TrackPlayer.play()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -344,17 +375,17 @@ export const createTrackPlayerSlice = (set: SetState<Store>, get: GetState<Store
|
|||||||
},
|
},
|
||||||
|
|
||||||
resetTrackPlayerState: () => {
|
resetTrackPlayerState: () => {
|
||||||
set({
|
set(state => {
|
||||||
queueName: undefined,
|
state.queueName = undefined
|
||||||
queueContextType: undefined,
|
state.queueContextType = undefined
|
||||||
queueContextId: undefined,
|
state.queueContextId = undefined
|
||||||
shuffleOrder: undefined,
|
state.shuffleOrder = undefined
|
||||||
repeatMode: RepeatMode.Off,
|
state.repeatMode = RepeatMode.Off
|
||||||
playerState: State.None,
|
state.playerState = State.None
|
||||||
currentTrack: undefined,
|
state.currentTrack = undefined
|
||||||
currentTrackIdx: undefined,
|
state.currentTrackIdx = undefined
|
||||||
queue: [],
|
state.queue = []
|
||||||
progress: { position: 0, duration: 0, buffered: 0 },
|
state.progress = { position: 0, duration: 0, buffered: 0 }
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Song } from '@app/models/library'
|
import { Song } from '@app/models/library'
|
||||||
import userAgent from '@app/util/userAgent'
|
import userAgent from '@app/util/userAgent'
|
||||||
import { GetState, SetState } from 'zustand'
|
import { GetStore, SetStore } from './store'
|
||||||
import { Store } from './store'
|
|
||||||
import { TrackExt } from './trackplayer'
|
import { TrackExt } from './trackplayer'
|
||||||
|
|
||||||
export type TrackPlayerMapSlice = {
|
export type TrackPlayerMapSlice = {
|
||||||
@@ -14,7 +13,7 @@ export const selectTrackPlayerMap = {
|
|||||||
mapTrackExtToSong: (store: TrackPlayerMapSlice) => store.mapTrackExtToSong,
|
mapTrackExtToSong: (store: TrackPlayerMapSlice) => store.mapTrackExtToSong,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createTrackPlayerMapSlice = (set: SetState<Store>, get: GetState<Store>): TrackPlayerMapSlice => ({
|
export const createTrackPlayerMapSlice = (set: SetStore, get: GetStore): TrackPlayerMapSlice => ({
|
||||||
mapSongtoTrackExt: async song => {
|
mapSongtoTrackExt: async song => {
|
||||||
let artwork = require('@res/fallback.png')
|
let artwork = require('@res/fallback.png')
|
||||||
if (song.coverArt) {
|
if (song.coverArt) {
|
||||||
|
|||||||
Reference in New Issue
Block a user