Watch next improvements, clear queue buttons

This commit is contained in:
Arkadiusz Fal 2022-12-21 18:21:44 +01:00
parent 18cbbd3c90
commit c01ff56854
5 changed files with 138 additions and 71 deletions

View File

@ -66,4 +66,12 @@ struct PlayerQueueItem: Hashable, Identifiable, Defaults.Serializable {
func hash(into hasher: inout Hasher) { func hash(into hasher: inout Hasher) {
hasher.combine(id) hasher.combine(id)
} }
var contentItem: ContentItem {
.init(video: contentItemVideo)
}
var contentItemVideo: Video {
video ?? Video(app: app ?? .invidious, instanceURL: instanceURL, videoID: videoID, length: videoDuration ?? 0)
}
} }

View File

@ -13,25 +13,29 @@ struct QueueView: View {
expanded.toggle() expanded.toggle()
} }
} label: { } label: {
HStack { HStack(spacing: 12) {
sectionLabel(label) sectionLabel(label)
Spacer() Spacer()
Label("Show more", systemImage: expanded ? "chevron.up" : "chevron.down") ClearQueueButton()
.animation(nil, value: expanded) if items.count > 1 {
.foregroundColor(.accentColor) Label("Show more", systemImage: expanded ? "chevron.up" : "chevron.down")
.imageScale(.large) .animation(nil, value: expanded)
.labelStyle(.iconOnly) .foregroundColor(.accentColor)
.opacity(items.count > 1 ? 1 : 0) .imageScale(.large)
.labelStyle(.iconOnly)
}
} }
} }
.buttonStyle(.plain) .buttonStyle(.plain)
ForEach(limitedItems) { item in LazyVStack(alignment: .leading) {
ContentItemView(item: .init(video: item.video)) ForEach(limitedItems) { item in
.environment(\.listingStyle, .list) ContentItemView(item: .init(video: item.video))
.environment(\.inQueueListing, true) .environment(\.listingStyle, .list)
.environment(\.noListingDividers, limit == 1) .environment(\.inQueueListing, true)
.transition(.opacity) .environment(\.noListingDividers, limit == 1)
.transition(.opacity)
}
} }
} }
} }
@ -46,12 +50,12 @@ struct QueueView: View {
return "Next in Queue (\(items.count))" return "Next in Queue (\(items.count))"
} }
var limitedItems: [PlayerQueueItem] { var limitedItems: [ContentItem] {
if let limit { if let limit {
return Array(items.prefix(limit)) return Array(items.prefix(limit).map(\.contentItem))
} }
return items return items.map(\.contentItem)
} }
var items: [PlayerQueueItem] { var items: [PlayerQueueItem] {

View File

@ -11,59 +11,62 @@ struct WatchNextView: View {
var body: some View { var body: some View {
Group { Group {
#if os(iOS) if model.isPresenting {
NavigationView { #if os(iOS)
watchNext NavigationView {
.toolbar { watchNext
ToolbarItem(placement: .principal) { .toolbar {
watchNextMenu ToolbarItem(placement: .principal) {
} watchNextMenu
}
}
.navigationViewStyle(.stack)
#else
VStack {
HStack {
hideCloseButton
.labelStyle(.iconOnly)
.frame(maxWidth: .infinity, alignment: .leading)
Spacer()
watchNextMenu
.frame(maxWidth: .infinity)
Spacer()
HStack {
#if os(macOS)
Text("Mode")
.foregroundColor(.secondary)
#endif
playbackModeControl
HStack {
if model.isRestartable {
reopenButton
} }
} }
}
.frame(maxWidth: .infinity, alignment: .trailing)
} }
#if os(macOS) .navigationViewStyle(.stack)
.padding() #else
#endif VStack {
watchNext HStack {
} hideCloseButton
#endif .labelStyle(.iconOnly)
.frame(maxWidth: .infinity, alignment: .leading)
Spacer()
watchNextMenu
.frame(maxWidth: .infinity)
Spacer()
HStack {
#if os(macOS)
Text("Mode")
.foregroundColor(.secondary)
#endif
playbackModeControl
HStack {
if model.isRestartable {
reopenButton
}
}
}
.frame(maxWidth: .infinity, alignment: .trailing)
}
#if os(macOS)
.padding()
#endif
watchNext
}
#endif
}
} }
.transition(.opacity)
.zIndex(0)
#if os(tvOS) #if os(tvOS)
.background(Color.background(scheme: colorScheme)) .background(Color.background(scheme: colorScheme))
#else #else
.background(Color.background) .background(Color.background)
#endif #endif
.opacity(model.isPresenting ? 1 : 0)
} }
var watchNext: some View { var watchNext: some View {
@ -211,6 +214,13 @@ struct WatchNextView: View {
} }
} }
var queueForMoreVideos: [ContentItem] {
guard !player.queue.isEmpty else { return [] }
let suffix = player.playbackMode == .queue && model.isAutoplaying && model.canAutoplay ? 1 : 0
return player.queue.suffix(from: suffix).map(\.contentItem)
}
@ViewBuilder var moreVideos: some View { @ViewBuilder var moreVideos: some View {
VStack(spacing: 12) { VStack(spacing: 12) {
switch model.page { switch model.page {
@ -222,21 +232,27 @@ struct WatchNextView: View {
Divider() Divider()
} }
let queueForMoreVideos = player.queue.isEmpty ? [] : player.queue.suffix(from: player.playbackMode == .queue && model.isAutoplaying && model.canAutoplay ? 1 : 0)
if (model.isAutoplaying && model.canAutoplay && !queueForMoreVideos.isEmpty) || if (model.isAutoplaying && model.canAutoplay && !queueForMoreVideos.isEmpty) ||
(!model.isAutoplaying && !queueForMoreVideos.isEmpty) (!model.isAutoplaying && !queueForMoreVideos.isEmpty)
{ {
Text("Next in queue") HStack {
.font(.headline) Text("Next in queue")
.frame(maxWidth: .infinity, alignment: .leading) .font(.headline)
.frame(maxWidth: .infinity, alignment: .leading)
Spacer()
ClearQueueButton()
}
} }
if !queueForMoreVideos.isEmpty { if !queueForMoreVideos.isEmpty {
ForEach(queueForMoreVideos) { item in LazyVStack {
ContentItemView(item: .init(video: item.video)) ForEach(queueForMoreVideos) { item in
.environment(\.inQueueListing, true) ContentItemView(item: item)
.environment(\.listingStyle, .list) .environment(\.inQueueListing, true)
.environment(\.listingStyle, .list)
}
} }
} else { } else {
Label( Label(

View File

@ -0,0 +1,31 @@
import SwiftUI
struct ClearQueueButton: View {
private var navigation = NavigationModel.shared
var body: some View {
Button {
navigation.presentAlert(
Alert(
title: Text("Are you sure you want to clear the queue?"),
primaryButton: .destructive(Text("Clear All")) {
PlayerModel.shared.removeQueueItems()
},
secondaryButton: .cancel()
)
)
} label: {
Label("Clear Queue", systemImage: "trash")
.font(.headline)
.labelStyle(.iconOnly)
.foregroundColor(.secondary)
}
.buttonStyle(.plain)
}
}
struct ClearQueueButton_Previews: PreviewProvider {
static var previews: some View {
ClearQueueButton()
}
}

View File

@ -684,6 +684,9 @@
37A2B346294723850050933E /* CacheModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A2B345294723850050933E /* CacheModel.swift */; }; 37A2B346294723850050933E /* CacheModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A2B345294723850050933E /* CacheModel.swift */; };
37A2B347294723850050933E /* CacheModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A2B345294723850050933E /* CacheModel.swift */; }; 37A2B347294723850050933E /* CacheModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A2B345294723850050933E /* CacheModel.swift */; };
37A2B348294723850050933E /* CacheModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A2B345294723850050933E /* CacheModel.swift */; }; 37A2B348294723850050933E /* CacheModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A2B345294723850050933E /* CacheModel.swift */; };
37A362BA2953707F00BDF328 /* ClearQueueButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A362B92953707F00BDF328 /* ClearQueueButton.swift */; };
37A362BB2953707F00BDF328 /* ClearQueueButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A362B92953707F00BDF328 /* ClearQueueButton.swift */; };
37A362BC2953707F00BDF328 /* ClearQueueButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A362B92953707F00BDF328 /* ClearQueueButton.swift */; };
37A5DBC4285DFF5400CA4DD1 /* SwiftUIPager in Frameworks */ = {isa = PBXBuildFile; productRef = 37A5DBC3285DFF5400CA4DD1 /* SwiftUIPager */; }; 37A5DBC4285DFF5400CA4DD1 /* SwiftUIPager in Frameworks */ = {isa = PBXBuildFile; productRef = 37A5DBC3285DFF5400CA4DD1 /* SwiftUIPager */; };
37A5DBC6285E06B100CA4DD1 /* SwiftUIPager in Frameworks */ = {isa = PBXBuildFile; productRef = 37A5DBC5285E06B100CA4DD1 /* SwiftUIPager */; }; 37A5DBC6285E06B100CA4DD1 /* SwiftUIPager in Frameworks */ = {isa = PBXBuildFile; productRef = 37A5DBC5285E06B100CA4DD1 /* SwiftUIPager */; };
37A5DBC8285E371400CA4DD1 /* ControlBackgroundModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A5DBC7285E371400CA4DD1 /* ControlBackgroundModifier.swift */; }; 37A5DBC8285E371400CA4DD1 /* ControlBackgroundModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A5DBC7285E371400CA4DD1 /* ControlBackgroundModifier.swift */; };
@ -1359,6 +1362,7 @@
379DC3D028BA4EB400B09677 /* Seek.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Seek.swift; sourceTree = "<group>"; }; 379DC3D028BA4EB400B09677 /* Seek.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Seek.swift; sourceTree = "<group>"; };
379F141E289ECE7F00DE48B5 /* QualitySettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QualitySettings.swift; sourceTree = "<group>"; }; 379F141E289ECE7F00DE48B5 /* QualitySettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QualitySettings.swift; sourceTree = "<group>"; };
37A2B345294723850050933E /* CacheModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheModel.swift; sourceTree = "<group>"; }; 37A2B345294723850050933E /* CacheModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheModel.swift; sourceTree = "<group>"; };
37A362B92953707F00BDF328 /* ClearQueueButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClearQueueButton.swift; sourceTree = "<group>"; };
37A5DBC7285E371400CA4DD1 /* ControlBackgroundModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlBackgroundModifier.swift; sourceTree = "<group>"; }; 37A5DBC7285E371400CA4DD1 /* ControlBackgroundModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlBackgroundModifier.swift; sourceTree = "<group>"; };
37A81BF8294BD1440081D322 /* WatchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchView.swift; sourceTree = "<group>"; }; 37A81BF8294BD1440081D322 /* WatchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchView.swift; sourceTree = "<group>"; };
37A9965926D6F8CA006E3224 /* HorizontalCells.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HorizontalCells.swift; sourceTree = "<group>"; }; 37A9965926D6F8CA006E3224 /* HorizontalCells.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HorizontalCells.swift; sourceTree = "<group>"; };
@ -1853,6 +1857,7 @@
children = ( children = (
37635FE3291EA6CF00C11E79 /* AccentButton.swift */, 37635FE3291EA6CF00C11E79 /* AccentButton.swift */,
37E6D79F2944CD3800550C3D /* CacheStatusHeader.swift */, 37E6D79F2944CD3800550C3D /* CacheStatusHeader.swift */,
37A362B92953707F00BDF328 /* ClearQueueButton.swift */,
37FB285D272225E800A57617 /* ContentItemView.swift */, 37FB285D272225E800A57617 /* ContentItemView.swift */,
372CFD14285F2E2A00B0B54B /* ControlsBar.swift */, 372CFD14285F2E2A00B0B54B /* ControlsBar.swift */,
3748186D26A769D60084E870 /* DetailBadge.swift */, 3748186D26A769D60084E870 /* DetailBadge.swift */,
@ -3155,6 +3160,7 @@
37A81BF9294BD1440081D322 /* WatchView.swift in Sources */, 37A81BF9294BD1440081D322 /* WatchView.swift in Sources */,
37EFAC0828C138CD00ED9B89 /* ControlsOverlayModel.swift in Sources */, 37EFAC0828C138CD00ED9B89 /* ControlsOverlayModel.swift in Sources */,
37F4AD2628613B81004D0F66 /* Color+Debug.swift in Sources */, 37F4AD2628613B81004D0F66 /* Color+Debug.swift in Sources */,
37A362BA2953707F00BDF328 /* ClearQueueButton.swift in Sources */,
3700155F271B12DD0049C794 /* SiestaConfiguration.swift in Sources */, 3700155F271B12DD0049C794 /* SiestaConfiguration.swift in Sources */,
37F13B62285E43C000B137E4 /* ControlsOverlay.swift in Sources */, 37F13B62285E43C000B137E4 /* ControlsOverlay.swift in Sources */,
375E45F827B1AC4700BA7902 /* PlayerControlsModel.swift in Sources */, 375E45F827B1AC4700BA7902 /* PlayerControlsModel.swift in Sources */,
@ -3432,6 +3438,7 @@
3776924F294630110055EC18 /* ChannelAvatarView.swift in Sources */, 3776924F294630110055EC18 /* ChannelAvatarView.swift in Sources */,
37BA221229526A19000DAD1F /* ControlsGradientView.swift in Sources */, 37BA221229526A19000DAD1F /* ControlsGradientView.swift in Sources */,
37BC50AD2778BCBA00510953 /* HistoryModel.swift in Sources */, 37BC50AD2778BCBA00510953 /* HistoryModel.swift in Sources */,
37A362BB2953707F00BDF328 /* ClearQueueButton.swift in Sources */,
3752069E285E910600CA655F /* ChapterView.swift in Sources */, 3752069E285E910600CA655F /* ChapterView.swift in Sources */,
37030FF827B0347C00ECDDAA /* MPVPlayerView.swift in Sources */, 37030FF827B0347C00ECDDAA /* MPVPlayerView.swift in Sources */,
378E50FC26FE8B9F00F49626 /* Instance.swift in Sources */, 378E50FC26FE8B9F00F49626 /* Instance.swift in Sources */,
@ -3751,6 +3758,7 @@
375EC95B289EEB8200751258 /* QualityProfileForm.swift in Sources */, 375EC95B289EEB8200751258 /* QualityProfileForm.swift in Sources */,
371B7E682759786B00D21217 /* Comment+Fixtures.swift in Sources */, 371B7E682759786B00D21217 /* Comment+Fixtures.swift in Sources */,
37BE0BD126A0E2D50092E2DB /* VideoPlayerView.swift in Sources */, 37BE0BD126A0E2D50092E2DB /* VideoPlayerView.swift in Sources */,
37A362BC2953707F00BDF328 /* ClearQueueButton.swift in Sources */,
37AAF27E26737323007FC770 /* PopularView.swift in Sources */, 37AAF27E26737323007FC770 /* PopularView.swift in Sources */,
37E80F45287B7AC000561799 /* ControlsBar.swift in Sources */, 37E80F45287B7AC000561799 /* ControlsBar.swift in Sources */,
3743CA50270EFE3400E4D32B /* PlayerQueueRow.swift in Sources */, 3743CA50270EFE3400E4D32B /* PlayerQueueRow.swift in Sources */,