iOS: iPhone Duo split layout at the hinge, 1.0 RC 3

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-11-09 07:57:58 -08:00
1 parent cf5f992e60
commit db55b5eea0
5 files changed
+86 -11

No files matched your search

+19 -5
View File
@@ -86,7 +86,21 @@ private extension UIColor {
// ---- now playing ----------------------------------------------------------------------------
/// Full screen, Now Playing owns the window's color scheme. Docked beside the library it only
/// sets its own pane's, since preferredColorScheme would repaint the library side too.
private struct NpScheme: ViewModifier {
var dark: Bool
var docked: Bool
func body(content: Content) -> some View {
if docked { content.environment(\.colorScheme, dark ? .dark : .light) }
else { content.preferredColorScheme(dark ? .dark : .light) }
}
}
struct NowPlayingScreen: View {
/// Shown beside the library on an unfolded iPhone Duo rather than as a full-screen cover:
/// no grabber, no drag to close, and its color scheme stays inside the pane.
var docked = false
@Environment(Ui.self) private var ui
@Environment(\.palette) private var base
@Environment(\.dismiss) private var dismiss
@@ -134,17 +148,17 @@ struct NowPlayingScreen: View {
.background(c.bg.ignoresSafeArea())
.overlay(alignment: .top) {
// Stands in for the sheet's grabber: tap or drag down to close.
Capsule().fill(c.label3).frame(width: 36, height: 5)
if !docked { Capsule().fill(c.label3).frame(width: 36, height: 5)
.frame(width: 120, height: 20).contentShape(Rectangle())
.onTapGesture { dismiss() }
.gesture(screenDrag)
.gesture(screenDrag) }
}
.offset(y: drop)
// On the art and the mixer: drag down anywhere to close, swipe up anywhere for the
// queue. The queue and lyrics scroll, so there it's the song header or the grabber.
.simultaneousGesture(screenDrag, including: panel == .Art || panel == .Mixer ? .all : .subviews)
.environment(\.palette, c)
.preferredColorScheme(c.dark ? .dark : .light)
.modifier(NpScheme(dark: c.dark, docked: docked))
.tint(c.label)
.animation(.easeInOut(duration: 0.3), value: tint)
.presentationBackground(.clear)
@@ -259,12 +273,12 @@ struct NowPlayingScreen: View {
DragGesture(minimumDistance: 20)
.onChanged { v in
let dy = v.translation.height
drop = dy > 0 && dy > abs(v.translation.width) ? dy : 0
drop = !docked && dy > 0 && dy > abs(v.translation.width) ? dy : 0
}
.onEnded { v in
let dy = v.translation.height
let vertical = abs(dy) > abs(v.translation.width)
if vertical && (dy > 120 || v.predictedEndTranslation.height > 300) { dismiss(); return }
if !docked && vertical && (dy > 120 || v.predictedEndTranslation.height > 300) { dismiss(); return }
withAnimation(.spring(duration: 0.3, bounce: 0.1)) { drop = 0 }
if vertical && dy < -50 { withAnimation(.spring(duration: 0.38, bounce: 0.12)) { panel = .Queue } }
}