import SwiftUI struct MiniPlayerView: View { @Environment(AppModel.self) private var model @Binding var isMiniPlayer: Bool var body: some View { HStack(spacing: 12) { Image(nsImage: model.playback.currentArtwork) .resizable() .scaledToFit() .frame(width: 64, height: 64) .background(.quaternary) .clipShape(RoundedRectangle(cornerRadius: 8)) VStack(alignment: .leading, spacing: 2) { Text(model.playback.currentStation?.name ?? String(localized: "No station selected")) .font(.headline) .lineLimit(1) Text(miniPlayerText) .font(.caption) .foregroundStyle(playerDetailColor) .lineLimit(1) } Spacer() Button { model.playback.togglePlayPause() } label: { Image(systemName: model.playback.isPlaying ? "pause.fill" : "play.fill") } .buttonStyle(.bordered) .controlSize(.small) .disabled(model.playback.currentStation == nil) Button { model.playback.stop() } label: { Image(systemName: "stop.fill") } .buttonStyle(.bordered) .controlSize(.small) HStack(spacing: 4) { Image(systemName: "speaker.wave.1") .font(.caption) Slider(value: Binding( get: { model.playback.volume }, set: { model.setVolume($0) } ), in: 0...1) .frame(width: 80) Image(systemName: "speaker.wave.3") .font(.caption) } .foregroundStyle(.secondary) Button { isMiniPlayer = false } label: { Image(systemName: "arrow.up.left.and.arrow.down.right") } .buttonStyle(.bordered) .controlSize(.small) .help("Show full window") } .padding(12) .frame(height: 110) .background(.bar) } private var miniPlayerText: 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 } }