// // RadiosView.swift // Mobile Music Assistant // // Created by Sven Hanold on 26.03.26. // import SwiftUI struct RadiosView: View { @Environment(MAService.self) private var service @State private var radios: [MAMediaItem] = [] @State private var isLoading = true @State private var errorMessage: String? @State private var showError = false @State private var selectedRadio: MAMediaItem? private var players: [MAPlayer] { Array(service.playerManager.players.values) .filter { $0.available } .sorted { $0.name < $1.name } } var body: some View { List(radios) { radio in Button { handleRadioTap(radio) } label: { RadioRow(radio: radio) } .buttonStyle(.plain) .listRowSeparator(.visible) } .listStyle(.plain) .overlay { if isLoading { ProgressView() } else if radios.isEmpty && errorMessage == nil { ContentUnavailableView( "No Radio Stations", systemImage: "antenna.radiowaves.left.and.right", description: Text("No radio stations found in your library.") ) } } .task { await loadRadios() } .refreshable { await loadRadios() } .alert("Error", isPresented: $showError) { Button("OK", role: .cancel) { } } message: { if let errorMessage { Text(errorMessage) } } .sheet(item: $selectedRadio) { radio in EnhancedPlayerPickerView( players: players, onSelect: { player in Task { await playRadio(radio, on: player) } } ) } } private func handleRadioTap(_ radio: MAMediaItem) { if players.count == 1 { Task { await playRadio(radio, on: players.first!) } } else { selectedRadio = radio } } private func loadRadios() async { isLoading = true errorMessage = nil do { radios = try await service.getRadios() isLoading = false } catch { errorMessage = error.localizedDescription showError = true isLoading = false } } private func playRadio(_ radio: MAMediaItem, on player: MAPlayer) async { do { try await service.playerManager.playMedia(playerId: player.playerId, uri: radio.uri) } catch { errorMessage = error.localizedDescription showError = true } } } // MARK: - Radio Row private struct RadioRow: View { @Environment(MAService.self) private var service let radio: MAMediaItem var body: some View { HStack(spacing: 12) { CachedAsyncImage(url: service.imageProxyURL(path: radio.imageUrl, provider: radio.imageProvider, size: 128)) { image in image.resizable().aspectRatio(contentMode: .fill) } placeholder: { RoundedRectangle(cornerRadius: 8) .fill(Color.gray.opacity(0.2)) .overlay { Image(systemName: "antenna.radiowaves.left.and.right") .foregroundStyle(.secondary) } } .frame(width: 50, height: 50) .clipShape(RoundedRectangle(cornerRadius: 8)) Text(radio.name) .font(.body) .lineLimit(2) Spacer() Image(systemName: "play.circle") .font(.title2) .foregroundStyle(.secondary) } .padding(.vertical, 4) } } #Preview { NavigationStack { RadiosView() .environment(MAService()) } }