import SwiftUI struct PlayerBarView: View { @Environment(AppModel.self) private var model var body: some View { HStack(spacing: 14) { Image(nsImage: model.playback.currentArtwork) .resizable() .scaledToFit() .frame(width: 46, height: 46) .background(.quaternary) .clipShape(RoundedRectangle(cornerRadius: 8)) VStack(alignment: .leading, spacing: 4) { Text(model.playback.currentStation?.name ?? model.library.selectedStation?.name ?? String(localized: "No station selected")) .font(.headline) .lineLimit(1) Text(nowPlayingText) .font(.subheadline) .foregroundStyle(playerDetailColor) .lineLimit(1) .help(nowPlayingText) } Spacer() radioControls HStack { Image(systemName: "speaker.wave.1") Slider(value: Binding( get: { model.playback.volume }, set: { model.setVolume($0) } ), in: 0...1) .frame(width: 150) Image(systemName: "speaker.wave.3") } .foregroundStyle(.secondary) } .padding(12) .background(.bar) } private var radioControls: some View { HStack(spacing: 8) { Button { model.playback.togglePlayPause() } label: { Label(model.playback.isPlaying ? "Pause" : "Play", systemImage: model.playback.isPlaying ? "pause.fill" : "play.fill") } .disabled(model.playback.currentStation == nil) Button { model.playback.stop() } label: { Label("Stop", systemImage: "stop.fill") } } } private var nowPlayingText: String { if let detail = model.playback.state.detail { return "\(model.playback.state.title): \(detail)" } switch model.playback.state { case .connecting, .buffering, .failed: return model.playback.state.title default: break } if !model.playback.currentTrackTitle.isEmpty && !model.playback.currentTrackArtist.isEmpty { return "\(model.playback.currentTrackArtist) - \(model.playback.currentTrackTitle)" } if !model.playback.currentTrackTitle.isEmpty { return model.playback.currentTrackTitle } if !model.playback.currentTrackArtist.isEmpty { return model.playback.currentTrackArtist } if let station = model.playback.currentStation, !station.tags.isEmpty { return station.tags } return String(localized: "Live radio") } private var playerDetailColor: Color { if case .failed = model.playback.state { return .red } if case .connecting = model.playback.state { return .secondary } if case .buffering = model.playback.state { return .orange } return .secondary } }