Updated API calls and Library View

This commit is contained in:
2026-03-27 15:44:33 +01:00
parent e9b6412d71
commit f931c92d94
6 changed files with 632 additions and 207 deletions
@@ -7,27 +7,73 @@
import SwiftUI
enum LibraryTab: String, CaseIterable {
case artists = "Artists"
case albums = "Albums"
case playlists = "Playlists"
case radio = "Radio"
}
struct LibraryView: View {
@Environment(MAService.self) private var service
@State private var selectedTab: LibraryTab = .artists
@State private var refreshError: String?
@State private var showError = false
private var isRefreshing: Bool {
switch selectedTab {
case .artists: return service.libraryManager.isLoadingArtists
case .albums: return service.libraryManager.isLoadingAlbums
case .playlists: return service.libraryManager.isLoadingPlaylists
case .radio: return false
}
}
private var lastRefresh: Date? {
switch selectedTab {
case .artists: return service.libraryManager.lastArtistsRefresh
case .albums: return service.libraryManager.lastAlbumsRefresh
case .playlists: return service.libraryManager.lastPlaylistsRefresh
case .radio: return nil
}
}
var body: some View {
NavigationStack {
TabView {
Tab("Artists", systemImage: "music.mic") {
ArtistsView()
}
Tab("Albums", systemImage: "square.stack") {
AlbumsView()
}
Tab("Playlists", systemImage: "music.note.list") {
PlaylistsView()
Group {
switch selectedTab {
case .artists: ArtistsView()
case .albums: AlbumsView()
case .playlists: PlaylistsView()
case .radio: RadiosView()
}
}
.tabViewStyle(.page(indexDisplayMode: .always))
.navigationTitle("Library")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button {
Task { await refresh() }
} label: {
if isRefreshing {
ProgressView()
} else {
Image(systemName: "arrow.clockwise")
}
}
.disabled(isRefreshing || selectedTab == .radio)
.help(lastRefreshLabel)
}
ToolbarItem(placement: .principal) {
Picker("Library", selection: $selectedTab) {
ForEach(LibraryTab.allCases, id: \.self) { tab in
Text(tab.rawValue).tag(tab)
}
}
.pickerStyle(.segmented)
.frame(maxWidth: 360)
}
ToolbarItem(placement: .primaryAction) {
NavigationLink {
SearchView()
@@ -36,6 +82,37 @@ struct LibraryView: View {
}
}
}
.navigationDestination(for: MAArtist.self) { ArtistDetailView(artist: $0) }
.navigationDestination(for: MAAlbum.self) { AlbumDetailView(album: $0) }
.navigationDestination(for: MAPlaylist.self) { PlaylistDetailView(playlist: $0) }
.alert("Refresh Failed", isPresented: $showError) {
Button("OK", role: .cancel) { }
} message: {
if let refreshError { Text(refreshError) }
}
}
}
// MARK: - Helpers
private var lastRefreshLabel: String {
guard let date = lastRefresh else { return "Never refreshed" }
let formatter = RelativeDateTimeFormatter()
formatter.unitsStyle = .full
return "Last refreshed \(formatter.localizedString(for: date, relativeTo: .now))"
}
private func refresh() async {
do {
switch selectedTab {
case .artists: try await service.libraryManager.loadArtists(refresh: true)
case .albums: try await service.libraryManager.loadAlbums(refresh: true)
case .playlists: try await service.libraryManager.loadPlaylists(refresh: true)
case .radio: break
}
} catch {
refreshError = error.localizedDescription
showError = true
}
}
}