Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions App/Continuity/Views/DownloadQueueButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import SwiftUI
import Ingest

/// Live ingest affordance: arrow + remaining-job count in one glass capsule.
///
/// Isolated so `ingestJobs` updates (byte progress included) only invalidate this control,
/// not the library grid or Now Playing chrome. The count is a single token (`19`, not
/// `4/4 19`) with `lineLimit(1)` + `fixedSize` so a toolbar or island-adjacent slot
/// cannot wrap it onto two lines.
struct DownloadQueueButton: View {
@Environment(PreparationQueue.self) private var prepQueue
@Binding var showingDownloads: Bool
/// Library toolbar stays visible so Downloads is always reachable. Now Playing hides
/// the control when the queue is empty so it doesn't sit under the Dynamic Island.
var showsWhenEmpty: Bool = true

var body: some View {
let count = prepQueue.ingestJobs.count
if showsWhenEmpty || count > 0 {
Button {
showingDownloads = true
} label: {
HStack(spacing: 6) {
Image(systemName: count == 0 ? "arrow.down.circle" : "arrow.down.circle.fill")
if count > 0 {
Text("\(count)")
.font(.caption.weight(.bold).monospacedDigit())
.lineLimit(1)
.minimumScaleFactor(1)
}
}
.padding(.horizontal, count > 0 ? 10 : 8)
.padding(.vertical, 6)
.continuityGlassCapsule(interactive: true)
// Grow with the digits; never compress into a square that wraps `419` as `4/4`/`19`.
.fixedSize(horizontal: true, vertical: true)
}
.buttonStyle(.plain)
.accessibilityLabel(count == 0 ? "Downloads" : "\(count) downloads in progress")
}
}
}
29 changes: 1 addition & 28 deletions App/Continuity/Views/LibrarySheetView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ struct LibrarySheetView: View {
.navigationTitle("Continuity")
.toolbar {
ToolbarItem(placement: .topBarLeading) {
DownloadsToolbarButton(showingDownloads: $showingDownloads)
DownloadQueueButton(showingDownloads: $showingDownloads)
}
// Every action is a primaryAction so nothing collapses into a dead "…"
// overflow menu (secondaryAction items did, and looked broken).
Expand Down Expand Up @@ -119,30 +119,3 @@ private struct AddBadgeIcon: View {
}
}

/// Isolated so byte-level download progress only invalidates this control, not the library grid.
private struct DownloadsToolbarButton: View {
@Environment(PreparationQueue.self) private var prepQueue
@Binding var showingDownloads: Bool

var body: some View {
let count = prepQueue.ingestJobs.count
return Button {
showingDownloads = true
} label: {
Image(systemName: count == 0 ? "arrow.down.circle" : "arrow.down.circle.fill")
}
.accessibilityLabel("Downloads")
.overlay(alignment: .topTrailing) {
if count > 0 {
Text("\(count)")
.font(.system(size: 9, weight: .bold))
.padding(.horizontal, 4)
.padding(.vertical, 1)
.background(.tint, in: Capsule())
.foregroundStyle(.white)
.offset(x: 8, y: -8)
.accessibilityHidden(true)
}
}
}
}
12 changes: 12 additions & 0 deletions App/Continuity/Views/NowPlayingView.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import SwiftUI
import Ingest
import Playback
import Domain

Expand All @@ -12,6 +13,7 @@ struct NowPlayingView: View {
@Environment(MainPagerState.self) private var pagerState

@State private var showingTransitionSettings = false
@State private var showingDownloads = false

var body: some View {
// No backdrop here: MainPagerView supplies AlbumBackdrop as the page BACKGROUND
Expand Down Expand Up @@ -58,6 +60,16 @@ struct NowPlayingView: View {
}
.padding(.top, 8)
}
// Same control as the library toolbar, hidden when idle so it doesn't sit under
// the Dynamic Island. Isolated: job-count ticks don't rebuild this page.
.overlay(alignment: .topLeading) {
DownloadQueueButton(showingDownloads: $showingDownloads, showsWhenEmpty: false)
.padding(.leading, 16)
.padding(.top, 8)
}
.sheet(isPresented: $showingDownloads) {
DownloadsView()
}
.overlay(alignment: .bottom) {
pageChevron(
system: "chevron.compact.down",
Expand Down
Loading