import SwiftUI struct iPhoneLibraryView: View { @State private var viewModel = iPhoneLibraryViewModel() var body: some View { NavigationStack { List { if let currentTitle = viewModel.nowPlaying.title { Section("Now Playing") { HStack(alignment: .center) { VStack(alignment: .leading, spacing: 4) { Text(currentTitle) .font(.headline) if let artist = viewModel.nowPlaying.artist { Text(artist) .foregroundStyle(.secondary) } Text(viewModel.nowPlaying.isPlaying ? "Playing offline" : "Paused") .font(.caption) .foregroundStyle(.secondary) } Spacer() if let trackID = viewModel.nowPlaying.trackID { Button(viewModel.nowPlaying.isPlaying ? "Pause" : "Play") { viewModel.togglePlayback(trackID: trackID) } .buttonStyle(.borderedProminent) } } } } Section("Remote tracks: \(viewModel.remoteTracks.count)") { ForEach(viewModel.remoteTracks) { track in VStack(alignment: .leading, spacing: 6) { HStack(alignment: .top) { VStack(alignment: .leading, spacing: 4) { Text(track.title) .font(.headline) Text(track.artist) .foregroundStyle(.secondary) } Spacer() Text(track.statusText) .font(.caption.weight(.semibold)) .padding(.horizontal, 10) .padding(.vertical, 4) .background(statusColor(for: track.statusText), in: Capsule()) .foregroundStyle(.white) } Text("Duration: \(track.durationText)") .font(.subheadline) .foregroundStyle(.secondary) Text("Remote track ID: \(track.remoteTrackID)") .font(.caption) .foregroundStyle(.tertiary) .textSelection(.enabled) HStack { Button("Download") { Task { await viewModel.downloadTrack(trackID: track.id) } } .buttonStyle(.bordered) .disabled(!track.canDownload) if track.canPlay { Button(track.playButtonTitle) { viewModel.togglePlayback(trackID: track.id) } .buttonStyle(.borderedProminent) } } if let error = track.lastDownloadError, track.statusText == "Failed" { Text(error) .font(.caption) .foregroundStyle(.red) } } .padding(.vertical, 4) } } } .overlay { overlayView } .navigationTitle("Velody") .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("Sync Remote Library") { Task { await viewModel.refreshSync() } } .disabled(viewModel.state == .loading) } } .safeAreaInset(edge: .bottom) { VStack(alignment: .leading, spacing: 4) { if let playbackError = viewModel.nowPlaying.errorMessage { Text(playbackError) .font(.footnote) .foregroundStyle(.red) } Text(viewModel.syncStatus) .font(.footnote) .foregroundStyle(.secondary) } .padding() .frame(maxWidth: .infinity, alignment: .leading) .background(.ultraThinMaterial) } } .task { await viewModel.loadIfNeeded() } } @ViewBuilder private var overlayView: some View { switch viewModel.state { case .idle: if viewModel.remoteTracks.isEmpty { ContentUnavailableView( "No Remote Library Yet", systemImage: "music.note.list", description: Text("Tap Sync Remote Library to fetch metadata from the backend.") ) } case .loading: ProgressView("Syncing remote library...") case .success: EmptyView() case .empty: ContentUnavailableView( "Empty Remote Library", systemImage: "music.note.list", description: Text("The backend returned no remote tracks for this iPhone.") ) case .networkError(let message): if viewModel.remoteTracks.isEmpty { ContentUnavailableView( "Network Error", systemImage: "wifi.exclamationmark", description: Text(message) ) } } } private func statusColor(for status: String) -> Color { switch status { case "Downloading": return .orange case "Downloaded": return .green case "Failed": return .red default: return .gray } } }