Queue, Favorites, Providers, Now playing
This commit is contained in:
@@ -34,6 +34,10 @@ final class MALibraryManager {
|
||||
private(set) var isLoadingAlbums = false
|
||||
private(set) var isLoadingPlaylists = false
|
||||
|
||||
/// URIs currently marked as favorites — source of truth for UI.
|
||||
/// Populated from decoded model data, then mutated optimistically on toggle.
|
||||
private(set) var favoriteURIs: Set<String> = []
|
||||
|
||||
// Last refresh timestamps (persisted in UserDefaults)
|
||||
private(set) var lastArtistsRefresh: Date?
|
||||
private(set) var lastAlbumsRefresh: Date?
|
||||
@@ -42,7 +46,7 @@ final class MALibraryManager {
|
||||
// MARK: - Disk Cache
|
||||
|
||||
/// Increment this whenever the model format changes to invalidate stale caches.
|
||||
private static let cacheVersion = 2
|
||||
private static let cacheVersion = 3
|
||||
|
||||
private let cacheDirectory: URL = {
|
||||
let caches = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
|
||||
@@ -96,6 +100,10 @@ final class MALibraryManager {
|
||||
logger.info("Loaded \(cached.count) playlists from disk cache")
|
||||
}
|
||||
|
||||
// Seed favorite URIs from cached data
|
||||
for artist in artists where artist.favorite { favoriteURIs.insert(artist.uri) }
|
||||
for album in albums where album.favorite { favoriteURIs.insert(album.uri) }
|
||||
|
||||
let ud = UserDefaults.standard
|
||||
lastArtistsRefresh = ud.object(forKey: "lib.lastArtistsRefresh") as? Date
|
||||
lastAlbumsRefresh = ud.object(forKey: "lib.lastAlbumsRefresh") as? Date
|
||||
@@ -152,10 +160,13 @@ final class MALibraryManager {
|
||||
if refresh {
|
||||
artists = newArtists
|
||||
artistsOffset = newArtists.count
|
||||
// Reset and repopulate artist favorites on refresh
|
||||
for a in artists where a.favorite { favoriteURIs.insert(a.uri) }
|
||||
} else {
|
||||
artists.append(contentsOf: newArtists)
|
||||
artistsOffset += newArtists.count
|
||||
}
|
||||
for a in newArtists where a.favorite { favoriteURIs.insert(a.uri) }
|
||||
hasMoreArtists = newArtists.count >= pageSize
|
||||
|
||||
if refresh || artistsOffset <= pageSize {
|
||||
@@ -199,10 +210,12 @@ final class MALibraryManager {
|
||||
if refresh {
|
||||
albums = newAlbums
|
||||
albumsOffset = newAlbums.count
|
||||
for a in albums where a.favorite { favoriteURIs.insert(a.uri) }
|
||||
} else {
|
||||
albums.append(contentsOf: newAlbums)
|
||||
albumsOffset += newAlbums.count
|
||||
}
|
||||
for a in newAlbums where a.favorite { favoriteURIs.insert(a.uri) }
|
||||
hasMoreAlbums = newAlbums.count >= pageSize
|
||||
|
||||
if refresh || albumsOffset <= pageSize {
|
||||
@@ -255,6 +268,53 @@ final class MALibraryManager {
|
||||
return try await service.getAlbumTracks(albumUri: albumUri)
|
||||
}
|
||||
|
||||
func getPlaylistTracks(playlistUri: String) async throws -> [MAMediaItem] {
|
||||
guard let service else { throw MAWebSocketClient.ClientError.notConnected }
|
||||
logger.info("Loading tracks for playlist \(playlistUri)")
|
||||
return try await service.getPlaylistTracks(playlistUri: playlistUri)
|
||||
}
|
||||
|
||||
// MARK: - Favorites
|
||||
|
||||
/// Returns whether the given URI is currently favorited.
|
||||
func isFavorite(uri: String) -> Bool {
|
||||
favoriteURIs.contains(uri)
|
||||
}
|
||||
|
||||
/// Toggle favorite for any item. Performs optimistic update, then calls server.
|
||||
/// Reverts on failure.
|
||||
func toggleFavorite(uri: String, currentlyFavorite: Bool) async {
|
||||
// Optimistic update
|
||||
if currentlyFavorite {
|
||||
favoriteURIs.remove(uri)
|
||||
} else {
|
||||
favoriteURIs.insert(uri)
|
||||
}
|
||||
|
||||
// Call server
|
||||
guard let service else {
|
||||
// Revert if no service
|
||||
if currentlyFavorite { favoriteURIs.insert(uri) } else { favoriteURIs.remove(uri) }
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
if currentlyFavorite {
|
||||
try await service.removeFavorite(uri: uri)
|
||||
} else {
|
||||
try await service.addFavorite(uri: uri)
|
||||
}
|
||||
} catch {
|
||||
// Revert on failure
|
||||
if currentlyFavorite {
|
||||
favoriteURIs.insert(uri)
|
||||
} else {
|
||||
favoriteURIs.remove(uri)
|
||||
}
|
||||
logger.error("Failed to toggle favorite for \(uri): \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Search
|
||||
|
||||
func search(query: String, mediaTypes: [MediaType]? = nil) async throws -> [MAMediaItem] {
|
||||
|
||||
Reference in New Issue
Block a user