mirror of
https://github.com/yattee/yattee.git
synced 2026-05-12 10:25:02 +00:00
Open queue sheet from tvOS player controls
Turn the tvOS bottom-row queue count indicator into a focusable button that opens QueueManagementSheet in a fullScreenCover with an ultraThinMaterial backdrop, matching the Settings sheet pattern. Hide the sheet's close toolbar button on tvOS (Menu button dismisses) and replace the unusable Menu-based queue mode picker with an icon-only tap-to-cycle button.
This commit is contained in:
@@ -41,6 +41,7 @@ struct QueueManagementSheet: View {
|
|||||||
queueModeMenu
|
queueModeMenu
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
ToolbarItem(placement: .confirmationAction) {
|
ToolbarItem(placement: .confirmationAction) {
|
||||||
Button(role: .cancel) {
|
Button(role: .cancel) {
|
||||||
dismiss()
|
dismiss()
|
||||||
@@ -49,6 +50,7 @@ struct QueueManagementSheet: View {
|
|||||||
.labelStyle(.iconOnly)
|
.labelStyle(.iconOnly)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.presentationDragIndicator(.visible)
|
.presentationDragIndicator(.visible)
|
||||||
@@ -209,6 +211,14 @@ struct QueueManagementSheet: View {
|
|||||||
/// Menu for selecting queue mode (shuffle, repeat, etc.)
|
/// Menu for selecting queue mode (shuffle, repeat, etc.)
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private var queueModeMenu: some View {
|
private var queueModeMenu: some View {
|
||||||
|
#if os(tvOS)
|
||||||
|
Button {
|
||||||
|
cycleQueueMode()
|
||||||
|
} label: {
|
||||||
|
Image(systemName: playerState?.queueMode.icon ?? "list.bullet")
|
||||||
|
.foregroundStyle(.tint)
|
||||||
|
}
|
||||||
|
#else
|
||||||
Menu {
|
Menu {
|
||||||
ForEach(QueueMode.allCases, id: \.self) { mode in
|
ForEach(QueueMode.allCases, id: \.self) { mode in
|
||||||
Button {
|
Button {
|
||||||
@@ -226,6 +236,15 @@ struct QueueManagementSheet: View {
|
|||||||
}
|
}
|
||||||
.foregroundStyle(.tint)
|
.foregroundStyle(.tint)
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private func cycleQueueMode() {
|
||||||
|
guard let playerState else { return }
|
||||||
|
let modes = QueueMode.allCases
|
||||||
|
let currentIndex = modes.firstIndex(of: playerState.queueMode) ?? 0
|
||||||
|
let nextIndex = (currentIndex + 1) % modes.count
|
||||||
|
playerState.queueMode = modes[nextIndex]
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Actions
|
// MARK: - Actions
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ struct TVPlayerControlsView: View {
|
|||||||
@FocusState.Binding var focusedControl: TVPlayerFocusTarget?
|
@FocusState.Binding var focusedControl: TVPlayerFocusTarget?
|
||||||
|
|
||||||
let onShowSettings: () -> Void
|
let onShowSettings: () -> Void
|
||||||
|
let onShowQueue: () -> Void
|
||||||
let onShowDetails: () -> Void
|
let onShowDetails: () -> Void
|
||||||
let onShowComments: () -> Void
|
let onShowComments: () -> Void
|
||||||
let onShowDebug: () -> Void
|
let onShowDebug: () -> Void
|
||||||
@@ -241,15 +242,20 @@ struct TVPlayerControlsView: View {
|
|||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
// Queue indicator (if videos in queue)
|
// Queue button (if videos in queue)
|
||||||
if let state = playerState, state.hasNext {
|
if let state = playerState, state.hasNext {
|
||||||
HStack(spacing: 8) {
|
Button {
|
||||||
|
onShowQueue()
|
||||||
|
} label: {
|
||||||
|
VStack(spacing: 6) {
|
||||||
Image(systemName: "list.bullet")
|
Image(systemName: "list.bullet")
|
||||||
.font(.system(size: 20))
|
.font(.system(size: 28))
|
||||||
Text(String(localized: "queue.section.count \(state.queue.count)"))
|
Text(String(localized: "queue.section.count \(state.queue.count)"))
|
||||||
.font(.subheadline)
|
.font(.caption)
|
||||||
}
|
}
|
||||||
.foregroundStyle(.white.opacity(0.6))
|
}
|
||||||
|
.buttonStyle(TVActionButtonStyle())
|
||||||
|
.focused($focusedControl, equals: .queueButton)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ enum TVPlayerFocusTarget: Hashable {
|
|||||||
case debugButton
|
case debugButton
|
||||||
case playNext
|
case playNext
|
||||||
case closeButton
|
case closeButton
|
||||||
|
case queueButton
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Main tvOS fullscreen player view.
|
/// Main tvOS fullscreen player view.
|
||||||
@@ -45,6 +46,9 @@ struct TVPlayerView: View {
|
|||||||
/// Whether the quality sheet is shown.
|
/// Whether the quality sheet is shown.
|
||||||
@State private var showingQualitySheet = false
|
@State private var showingQualitySheet = false
|
||||||
|
|
||||||
|
/// Whether the queue sheet is shown.
|
||||||
|
@State private var showingQueueSheet = false
|
||||||
|
|
||||||
/// Whether the debug overlay is shown.
|
/// Whether the debug overlay is shown.
|
||||||
@State private var isDebugOverlayVisible = false
|
@State private var isDebugOverlayVisible = false
|
||||||
|
|
||||||
@@ -109,6 +113,14 @@ struct TVPlayerView: View {
|
|||||||
.fullScreenCover(isPresented: $showingQualitySheet) {
|
.fullScreenCover(isPresented: $showingQualitySheet) {
|
||||||
qualitySheetContent
|
qualitySheetContent
|
||||||
}
|
}
|
||||||
|
.fullScreenCover(isPresented: $showingQueueSheet) {
|
||||||
|
ZStack {
|
||||||
|
Rectangle()
|
||||||
|
.fill(.ultraThinMaterial)
|
||||||
|
.ignoresSafeArea()
|
||||||
|
QueueManagementSheet()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Quality Sheet Content
|
// MARK: - Quality Sheet Content
|
||||||
@@ -195,6 +207,7 @@ struct TVPlayerView: View {
|
|||||||
playerService: playerService,
|
playerService: playerService,
|
||||||
focusedControl: $focusedControl,
|
focusedControl: $focusedControl,
|
||||||
onShowSettings: { showQualitySheet() },
|
onShowSettings: { showQualitySheet() },
|
||||||
|
onShowQueue: { showQueueSheet() },
|
||||||
onShowDetails: { showDetailsPanel(tab: .info) },
|
onShowDetails: { showDetailsPanel(tab: .info) },
|
||||||
onShowComments: { showDetailsPanel(tab: .comments) },
|
onShowComments: { showDetailsPanel(tab: .comments) },
|
||||||
onShowDebug: { showDebugOverlay() },
|
onShowDebug: { showDebugOverlay() },
|
||||||
@@ -419,6 +432,11 @@ struct TVPlayerView: View {
|
|||||||
showingQualitySheet = true
|
showingQualitySheet = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func showQueueSheet() {
|
||||||
|
stopControlsTimer()
|
||||||
|
showingQueueSheet = true
|
||||||
|
}
|
||||||
|
|
||||||
private func switchToStream(_ stream: Stream, audioStream: Stream? = nil) {
|
private func switchToStream(_ stream: Stream, audioStream: Stream? = nil) {
|
||||||
guard let video = playerState?.currentVideo else { return }
|
guard let video = playerState?.currentVideo else { return }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user