mirror of
https://github.com/yattee/yattee.git
synced 2024-12-22 13:33:42 +00:00
Watch Next menu improvements
This commit is contained in:
parent
2ce903b6c3
commit
636e8205fe
@ -36,7 +36,7 @@ final class PlayerModel: ObservableObject {
|
||||
case .queue:
|
||||
return "Queue"
|
||||
case .shuffle:
|
||||
return "Queue, shuffled"
|
||||
return "Queue - shuffled"
|
||||
case .loopOne:
|
||||
return "Loop one"
|
||||
case .related:
|
||||
|
@ -42,7 +42,7 @@ final class WatchNextViewModel: ObservableObject {
|
||||
@Published var countdown = 0.0
|
||||
var countdownTimer: Timer?
|
||||
|
||||
private var player = PlayerModel.shared
|
||||
var player = PlayerModel.shared
|
||||
|
||||
var autoplayTimer: Timer?
|
||||
|
||||
@ -129,7 +129,7 @@ final class WatchNextViewModel: ObservableObject {
|
||||
|
||||
private func open(reason: PresentationReason) {
|
||||
self.reason = reason
|
||||
page = Page.allCases.first { isAvailable($0) } ?? .history
|
||||
setPageAfterOpening()
|
||||
|
||||
guard !isPresenting else { return }
|
||||
withAnimation(Self.animation) {
|
||||
@ -137,6 +137,19 @@ final class WatchNextViewModel: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
private func setPageAfterOpening() {
|
||||
let firstAvailable = Page.allCases.first { isAvailable($0) } ?? .history
|
||||
|
||||
switch reason {
|
||||
case .finishedWatching:
|
||||
page = player.playbackMode == .related ? .queue : firstAvailable
|
||||
case .closed:
|
||||
page = player.playbackMode == .related ? .queue : firstAvailable
|
||||
default:
|
||||
page = firstAvailable
|
||||
}
|
||||
}
|
||||
|
||||
func close() {
|
||||
let close = {
|
||||
self.player.closeCurrentItem()
|
||||
|
@ -87,11 +87,9 @@ struct PlayerQueueView: View {
|
||||
ForEach(player.queue) { item in
|
||||
PlayerQueueRow(item: item)
|
||||
.contextMenu {
|
||||
removeButton(item)
|
||||
removeAllButton()
|
||||
|
||||
if let video = item.video {
|
||||
VideoContextMenuView(video: video)
|
||||
.environment(\.inQueueListing, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -116,22 +114,6 @@ struct PlayerQueueView: View {
|
||||
.transaction { t in t.disablesAnimations = true }
|
||||
}
|
||||
}
|
||||
|
||||
private func removeButton(_ item: PlayerQueueItem) -> some View {
|
||||
Button {
|
||||
player.remove(item)
|
||||
} label: {
|
||||
Label("Remove from the queue", systemImage: "trash")
|
||||
}
|
||||
}
|
||||
|
||||
private func removeAllButton() -> some View {
|
||||
Button {
|
||||
player.removeQueueItems()
|
||||
} label: {
|
||||
Label("Clear the queue", systemImage: "trash.fill")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct PlayerQueueView_Previews: PreviewProvider {
|
||||
|
@ -96,13 +96,13 @@ struct VideoDetails: View {
|
||||
ContentItem(video: player.currentVideo)
|
||||
}
|
||||
|
||||
var pageMenu: some View {
|
||||
@ViewBuilder var pageMenu: some View {
|
||||
#if os(macOS)
|
||||
pagePicker
|
||||
.labelsHidden()
|
||||
.offset(x: 15, y: 15)
|
||||
.frame(maxWidth: 200)
|
||||
#else
|
||||
#elseif os(iOS)
|
||||
Menu {
|
||||
pagePicker
|
||||
} label: {
|
||||
@ -224,6 +224,8 @@ struct VideoDetails: View {
|
||||
.secondaryBackground
|
||||
#elseif os(iOS)
|
||||
.background
|
||||
#else
|
||||
.clear
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -35,8 +35,15 @@ struct WatchNextView: View {
|
||||
Spacer()
|
||||
|
||||
HStack {
|
||||
if model.isRestartable {
|
||||
reopenButton
|
||||
Text("Mode")
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
playbackModeControl
|
||||
|
||||
HStack {
|
||||
if model.isRestartable {
|
||||
reopenButton
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .trailing)
|
||||
@ -83,6 +90,9 @@ struct WatchNextView: View {
|
||||
#endif
|
||||
|
||||
PlayerQueueRow(item: item)
|
||||
|
||||
Divider()
|
||||
.padding(.vertical, 5)
|
||||
}
|
||||
|
||||
moreVideos
|
||||
@ -123,6 +133,7 @@ struct WatchNextView: View {
|
||||
#else
|
||||
Menu {
|
||||
pagePicker
|
||||
playbackModePicker
|
||||
} label: {
|
||||
HStack(spacing: 12) {
|
||||
menuLabel
|
||||
@ -142,7 +153,7 @@ struct WatchNextView: View {
|
||||
HStack {
|
||||
Image(systemName: model.page.systemImageName)
|
||||
.imageScale(.small)
|
||||
Text(model.page.title)
|
||||
Text(model.page == .queue ? queueTitle : model.page.title)
|
||||
.font(.headline)
|
||||
}
|
||||
}
|
||||
@ -150,12 +161,19 @@ struct WatchNextView: View {
|
||||
var pagePicker: some View {
|
||||
Picker("Page", selection: $model.page) {
|
||||
ForEach(WatchNextViewModel.Page.allCases, id: \.rawValue) { page in
|
||||
Label(page.title, systemImage: page.systemImageName)
|
||||
.tag(page)
|
||||
Label(
|
||||
page == .queue ? queueTitle : page.title,
|
||||
systemImage: page.systemImageName
|
||||
)
|
||||
.tag(page)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var queueTitle: String {
|
||||
"\(WatchNextViewModel.Page.queue.title) • \(player.queue.count)"
|
||||
}
|
||||
|
||||
@ViewBuilder var hideCloseButton: some View {
|
||||
if model.isHideable {
|
||||
hideButton
|
||||
@ -194,14 +212,30 @@ struct WatchNextView: View {
|
||||
VStack(spacing: 12) {
|
||||
switch model.page {
|
||||
case .queue:
|
||||
let queueForMoreVideos = player.queue.isEmpty ? [] : player.queue.suffix(from: model.isAutoplaying ? 1 : 0)
|
||||
|
||||
if player.playbackMode == .related, !(model.isAutoplaying && model.canAutoplay) {
|
||||
autoplaying
|
||||
|
||||
Divider()
|
||||
}
|
||||
|
||||
let queueForMoreVideos = player.queue.isEmpty ? [] : player.queue.suffix(from: player.playbackMode == .queue ? 1 : 0)
|
||||
|
||||
if (model.isAutoplaying && model.canAutoplay && !queueForMoreVideos.isEmpty) ||
|
||||
(!model.isAutoplaying && !queueForMoreVideos.isEmpty)
|
||||
{
|
||||
Text("Next in queue")
|
||||
.font(.headline)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
|
||||
if !queueForMoreVideos.isEmpty {
|
||||
ForEach(queueForMoreVideos) { item in
|
||||
ContentItemView(item: .init(video: item.video))
|
||||
.environment(\.inQueueListing, true)
|
||||
.environment(\.listingStyle, .list)
|
||||
}
|
||||
} else if player.playbackMode != .related && player.playbackMode != .loopOne {
|
||||
} else {
|
||||
Label(
|
||||
model.isAutoplaying ? "Nothing more in the queue" : "Queue is empty",
|
||||
systemImage: WatchNextViewModel.Page.queue.systemImageName
|
||||
@ -226,6 +260,71 @@ struct WatchNextView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder var playbackModeControl: some View {
|
||||
#if os(tvOS)
|
||||
Button {
|
||||
player.playbackMode = player.playbackMode.next()
|
||||
} label: {
|
||||
Label(player.playbackMode.description, systemImage: player.playbackMode.systemImage)
|
||||
}
|
||||
#elseif os(macOS)
|
||||
playbackModePicker
|
||||
.modifier(SettingsPickerModifier())
|
||||
#if os(macOS)
|
||||
.frame(maxWidth: 150)
|
||||
#endif
|
||||
#else
|
||||
Menu {
|
||||
playbackModePicker
|
||||
} label: {
|
||||
Label(player.playbackMode.description, systemImage: player.playbackMode.systemImage)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
var playbackModePicker: some View {
|
||||
Picker("Playback Mode", selection: $model.player.playbackMode) {
|
||||
ForEach(PlayerModel.PlaybackMode.allCases, id: \.rawValue) { mode in
|
||||
Label(mode.description, systemImage: mode.systemImage).tag(mode)
|
||||
}
|
||||
}
|
||||
.labelsHidden()
|
||||
}
|
||||
|
||||
@ViewBuilder var autoplaying: some View {
|
||||
Section(header: autoplayingHeader) {
|
||||
if let item = player.autoplayItem {
|
||||
PlayerQueueRow(item: item, autoplay: true)
|
||||
} else {
|
||||
Group {
|
||||
if player.currentItem.isNil {
|
||||
Text("Not Playing")
|
||||
} else {
|
||||
Text("Finding something to play...")
|
||||
}
|
||||
}
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var autoplayingHeader: some View {
|
||||
HStack {
|
||||
Text("Autoplaying Next")
|
||||
.font(.headline)
|
||||
Spacer()
|
||||
Button {
|
||||
player.setRelatedAutoplayItem()
|
||||
} label: {
|
||||
Label("Find Other", systemImage: "arrow.triangle.2.circlepath.circle")
|
||||
.labelStyle(.iconOnly)
|
||||
.foregroundColor(.accentColor)
|
||||
}
|
||||
.disabled(player.currentItem.isNil)
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct WatchNextView_Previews: PreviewProvider {
|
||||
|
Loading…
Reference in New Issue
Block a user