iOS: Duo unfolded layout with right-edge tab rail, stems+queue deck and swap sides
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f4af7b6cf8
commit
08f7af9421
4 files changed
+138
-14
No files matched your search
@@ -224,15 +224,15 @@ struct NowPlayingScreen: View {
|
||||
.padding(.top, 14)
|
||||
HStack {
|
||||
let hidden = NowPlayingButton.hidden(g.settings.hiddenNowPlaying)
|
||||
if !hidden.contains(.Mixer) { PanelToggle(symbol: "slider.vertical.3", on: panel == .Mixer) { show(.Mixer) } }
|
||||
if !hidden.contains(.Mixer) { PanelToggle(symbol: "slider.vertical.3", on: docked ? ui.deck : panel == .Mixer) { show(.Mixer) } }
|
||||
if !hidden.contains(.Speed) { SpeedMenu() }
|
||||
if !hidden.contains(.Route) { Button { ui.showInSettings(.Eq) } label: { routeLabel(c) }.buttonStyle(PressFade()).frame(maxWidth: .infinity) } else { Spacer() }
|
||||
if !hidden.contains(.AirPlay) { AirPlayButton(tint: UIColor(c.label2), active: UIColor(c.accent)).frame(width: 40, height: 40) }
|
||||
if !hidden.contains(.Karaoke) { PanelToggle(symbol: "music.mic", on: pm.karaoke) { karaoke() } }
|
||||
}
|
||||
.frame(height: 48)
|
||||
// Swipe up on the art (or here) for the queue.
|
||||
Button { show(.Queue) } label: {
|
||||
// Swipe up on the art (or here) for the queue. Docked, the queue is already beside it.
|
||||
if !docked { Button { show(.Queue) } label: {
|
||||
VStack(spacing: 0) {
|
||||
Image(systemName: panel == .Queue ? "chevron.compact.down" : "chevron.compact.up").font(.system(size: 22, weight: .medium))
|
||||
if panel != .Queue { Text("Playing Next").font(.caption2.weight(.medium)) }
|
||||
@@ -240,7 +240,7 @@ struct NowPlayingScreen: View {
|
||||
.foregroundStyle(c.label3).frame(maxWidth: .infinity, minHeight: 30).contentShape(Rectangle())
|
||||
}
|
||||
.buttonStyle(PressFade())
|
||||
.gesture(swipe(up: panel != .Queue))
|
||||
.gesture(swipe(up: panel != .Queue)) }
|
||||
}
|
||||
.padding(.horizontal, 28)
|
||||
}
|
||||
@@ -257,6 +257,8 @@ struct NowPlayingScreen: View {
|
||||
}
|
||||
|
||||
private func show(_ to: NpPanel) {
|
||||
// Docked, the stems and the queue have the other side of the hinge to themselves.
|
||||
if docked && (to == .Mixer || to == .Queue) { withAnimation(.snappy) { ui.showDeck() }; return }
|
||||
withAnimation(.spring(duration: 0.38, bounce: 0.12)) { panel = panel == to ? .Art : to }
|
||||
}
|
||||
|
||||
@@ -905,6 +907,45 @@ struct FaderSlider: View {
|
||||
}
|
||||
}
|
||||
|
||||
// ---- deck -----------------------------------------------------------------------------------
|
||||
|
||||
/// Unfolded iPhone Duo: the stems over the queue, on the other side of the hinge from Now Playing.
|
||||
struct NowPlayingDeck: View {
|
||||
@Environment(\.palette) private var base
|
||||
@State private var tint: Color?
|
||||
private var g: AppGraph { .shared }
|
||||
|
||||
var body: some View {
|
||||
let c = tint.map { base.tinted($0) } ?? base
|
||||
let track = g.playback.current?.track
|
||||
GeometryReader { geo in
|
||||
if track != nil {
|
||||
VStack(spacing: 0) {
|
||||
Text("Stems").font(.headline).foregroundStyle(c.label)
|
||||
.frame(maxWidth: .infinity, alignment: .leading).padding(.horizontal, 24)
|
||||
MixerPanel().frame(height: geo.size.height * 0.52)
|
||||
Rectangle().fill(c.label3.opacity(0.35)).frame(height: 0.5).padding(.horizontal, 24).padding(.bottom, 8)
|
||||
QueuePanel()
|
||||
}
|
||||
} else {
|
||||
Text("Nothing Playing").font(.title3.weight(.semibold)).foregroundStyle(c.label2)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
}
|
||||
}
|
||||
.padding(.top, 12)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.background(c.bg.ignoresSafeArea())
|
||||
.environment(\.palette, c)
|
||||
.modifier(NpScheme(dark: c.dark, docked: true))
|
||||
.tint(c.label)
|
||||
.animation(.easeInOut(duration: 0.3), value: tint)
|
||||
.task(id: "\(track?.thumb ?? "")|\(g.settings.albumColorNowPlaying)|\(base.dark)") {
|
||||
guard g.settings.albumColorNowPlaying, let thumb = track?.thumb else { tint = nil; return }
|
||||
tint = await albumColor(thumb, dark: base.dark)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---- queue ----------------------------------------------------------------------------------
|
||||
|
||||
private struct QueuePanel: View {
|
||||
|
||||
Reference in new issue
Block a user