Skip to content

Instantly share code, notes, and snippets.

@shaundon
Created March 21, 2026 20:22
Show Gist options
  • Select an option

  • Save shaundon/76f18f6332efc8bfb0982316d1e38445 to your computer and use it in GitHub Desktop.

Select an option

Save shaundon/76f18f6332efc8bfb0982316d1e38445 to your computer and use it in GitHub Desktop.
//
// ContentView.swift
// sheet-test
//
// Created by Shaun Donnelly on 21/03/2026.
//
import SwiftUI
struct ContentView: View {
@State private var selectedDetent: PresentationDetent = .height(120)
@State private var sheetPresented = true
var body: some View {
Color(.systemGroupedBackground)
.ignoresSafeArea()
.sheet(isPresented: $sheetPresented) {
NowPlayingSheet(selectedDetent: $selectedDetent)
.presentationDetents(
[.height(120), .large],
selection: $selectedDetent
)
.presentationDragIndicator(.hidden)
.presentationBackgroundInteraction(
.enabled(upThrough: .height(120))
)
.presentationCornerRadius(40)
.interactiveDismissDisabled()
}
}
}
// MARK: - Now Playing Sheet
struct NowPlayingSheet: View {
@Binding var selectedDetent: PresentationDetent
private var isExpanded: Bool {
selectedDetent == .large
}
var body: some View {
VStack(spacing: 0) {
if isExpanded {
expandedView
} else {
compactView
}
}
.animation(.easeInOut(duration: 0.25), value: isExpanded)
}
// MARK: - Compact (mini player)
private var compactView: some View {
HStack(spacing: 14) {
albumArt(size: 48)
VStack(alignment: .leading, spacing: 2) {
Text("Blinding Lights")
.font(.subheadline)
.fontWeight(.semibold)
.lineLimit(1)
Text("The Weeknd")
.font(.caption)
.foregroundStyle(.secondary)
.lineLimit(1)
}
Spacer()
Button { } label: {
Image(systemName: "play.fill")
.font(.title3)
}
Button { } label: {
Image(systemName: "forward.fill")
.font(.title3)
}
}
.padding(.horizontal, 20)
.padding(.vertical, 14)
.contentShape(Rectangle())
.onTapGesture {
selectedDetent = .large
}
}
// MARK: - Expanded (full player)
private var expandedView: some View {
VStack(spacing: 24) {
// Drag indicator
Capsule()
.fill(Color.secondary.opacity(0.4))
.frame(width: 36, height: 5)
.padding(.top, 10)
Spacer()
albumArt(size: 280)
.shadow(color: .black.opacity(0.3), radius: 20, y: 10)
// Track info
VStack(spacing: 4) {
Text("Blinding Lights")
.font(.title2)
.fontWeight(.bold)
Text("The Weeknd — After Hours")
.font(.subheadline)
.foregroundStyle(.secondary)
}
// Progress bar
VStack(spacing: 6) {
ProgressView(value: 0.35)
.tint(.primary)
HStack {
Text("1:12")
.font(.caption2)
.foregroundStyle(.secondary)
Spacer()
Text("3:20")
.font(.caption2)
.foregroundStyle(.secondary)
}
}
.padding(.horizontal, 30)
// Playback controls
HStack(spacing: 40) {
Button { } label: {
Image(systemName: "backward.fill")
.font(.title2)
}
Button { } label: {
Image(systemName: "play.fill")
.font(.largeTitle)
}
Button { } label: {
Image(systemName: "forward.fill")
.font(.title2)
}
}
.foregroundStyle(.primary)
// Volume slider
HStack(spacing: 12) {
Image(systemName: "speaker.fill")
.font(.caption)
.foregroundStyle(.secondary)
ProgressView(value: 0.6)
.tint(.secondary)
Image(systemName: "speaker.wave.3.fill")
.font(.caption)
.foregroundStyle(.secondary)
}
.padding(.horizontal, 30)
Spacer()
// Bottom row
HStack {
Button { } label: {
Image(systemName: "quote.bubble")
}
Spacer()
Button { } label: {
Image(systemName: "airplayaudio")
}
Spacer()
Button { } label: {
Image(systemName: "list.bullet")
}
}
.font(.title3)
.foregroundStyle(.secondary)
.padding(.horizontal, 50)
.padding(.bottom, 20)
}
}
// MARK: - Shared
private func albumArt(size: CGFloat) -> some View {
RoundedRectangle(cornerRadius: size * 0.1)
.fill(
LinearGradient(
colors: [.purple, .blue],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
)
.overlay {
Image(systemName: "music.note")
.font(.system(size: size * 0.3))
.foregroundStyle(.white.opacity(0.8))
}
.frame(width: size, height: size)
}
}
#Preview {
ContentView()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment