Update from NavidromePlayer.zip (2026-04-03 20:04)

This commit is contained in:
Dallas Groot 2026-04-03 20:04:32 -07:00
parent 2fb1f6c19a
commit 36331d1f51

View file

@ -656,7 +656,11 @@ struct DynamicIslandView: View {
private let accentPink = Color(red: 1.0, green: 0.176, blue: 0.333)
var body: some View {
VStack {
VStack(spacing: 0) {
// Generous drag zone above and around the pill
Color.clear
.frame(height: 20)
HStack(spacing: 0) {
// Leading: compact album art pill
Group {
@ -666,79 +670,79 @@ struct DynamicIslandView: View {
Color.gray.opacity(0.3)
}
}
.frame(width: 28, height: 28)
.clipShape(RoundedRectangle(cornerRadius: 8, style: .continuous))
.frame(width: 32, height: 32)
.clipShape(RoundedRectangle(cornerRadius: 10, style: .continuous))
.matchedGeometryEffect(id: "albumArt", in: namespace)
.padding(.leading, 8)
.padding(.leading, 10)
// Song info (compact)
VStack(alignment: .leading, spacing: 0) {
Text(audioPlayer.currentSong?.title ?? "")
.font(.system(size: 11, weight: .semibold))
.font(.system(size: 12, weight: .semibold))
.foregroundColor(.white)
.lineLimit(1)
Text(audioPlayer.currentSong?.artist ?? "")
.font(.system(size: 9))
.font(.system(size: 10))
.foregroundColor(.white.opacity(0.5))
.lineLimit(1)
}
.padding(.leading, 6)
.frame(maxWidth: 100, alignment: .leading)
.padding(.leading, 8)
.frame(maxWidth: .infinity, alignment: .leading)
// Center spacer (hardware cutout zone)
Spacer()
// Trailing: compact visualizer
// Trailing: compact visualizer or play button
if VisualizerSettings.shared.enabled {
CompactVisualizerView(
isPlaying: audioPlayer.isPlaying,
accentColor: colorExtractor.isLoaded ? colorExtractor.primaryColor : accentPink,
height: 28
height: 32
)
.frame(width: 60, height: 28)
.clipShape(RoundedRectangle(cornerRadius: 8))
.frame(width: 64, height: 32)
.clipShape(RoundedRectangle(cornerRadius: 10))
} else {
// Play/pause when no visualizer
Button(action: { audioPlayer.togglePlayPause() }) {
Image(systemName: audioPlayer.isPlaying ? "pause.fill" : "play.fill")
.font(.system(size: 14))
.font(.system(size: 16))
.foregroundColor(.white)
}
.frame(width: 36, height: 28)
.frame(width: 40, height: 32)
}
Spacer().frame(width: 8)
Spacer().frame(width: 10)
}
.frame(height: 40)
.frame(height: 48)
.background(
RoundedRectangle(cornerRadius: 22, style: .continuous)
RoundedRectangle(cornerRadius: 26, style: .continuous)
.fill(.black)
.shadow(color: .black.opacity(0.5), radius: 10, y: 2)
)
.padding(.horizontal, 40)
.padding(.top, 10)
.contentShape(Rectangle())
.onTapGesture {
withAnimation(.easeInOut(duration: 0.35)) {
showNowPlaying = true
isDynamicIsland = false
}
}
.gesture(
DragGesture(minimumDistance: 10)
.onEnded { value in
if value.translation.height > 40 {
// Drag down return to mini player
withAnimation(.spring(response: 0.5, dampingFraction: 0.8)) {
isDynamicIsland = false
}
}
}
.shadow(color: .black.opacity(0.6), radius: 12, y: 2)
)
.padding(.horizontal, 32)
// Extra drag zone below the pill
Color.clear
.frame(height: 30)
Spacer()
}
.ignoresSafeArea(edges: .top)
.statusBarHidden(true)
// Large hit area for the whole top region
.contentShape(Rectangle())
.onTapGesture {
withAnimation(.easeInOut(duration: 0.35)) {
showNowPlaying = true
isDynamicIsland = false
}
}
.gesture(
DragGesture(minimumDistance: 8)
.onEnded { value in
if value.translation.height > 25 {
// Drag down return to mini player
withAnimation(.spring(response: 0.5, dampingFraction: 0.8)) {
isDynamicIsland = false
}
}
}
)
}
}