yattee/Shared/Player/WatchNextView.swift

268 lines
8.0 KiB
Swift
Raw Normal View History

2022-12-17 23:08:30 +00:00
import Defaults
import SwiftUI
struct WatchNextView: View {
@ObservedObject private var model = WatchNextViewModel.shared
@ObservedObject private var player = PlayerModel.shared
@Default(.saveHistory) private var saveHistory
@Environment(\.colorScheme) private var colorScheme
var body: some View {
Group {
#if os(iOS)
NavigationView {
watchNext
2022-12-18 18:39:03 +00:00
.toolbar {
ToolbarItem(placement: .principal) {
watchNextMenu
}
}
2022-12-17 23:08:30 +00:00
}
#else
VStack {
HStack {
2022-12-18 18:39:03 +00:00
hideCloseButton
.labelStyle(.iconOnly)
.frame(maxWidth: .infinity, alignment: .leading)
Spacer()
watchNextMenu
.frame(maxWidth: .infinity)
2022-12-17 23:08:30 +00:00
Spacer()
2022-12-18 18:39:03 +00:00
HStack {
if model.isRestartable {
reopenButton
}
}
.frame(maxWidth: .infinity, alignment: .trailing)
2022-12-17 23:08:30 +00:00
}
2022-12-18 18:39:03 +00:00
#if os(macOS)
2022-12-17 23:08:30 +00:00
.padding()
2022-12-18 18:39:03 +00:00
#endif
2022-12-17 23:08:30 +00:00
watchNext
}
#endif
}
#if os(tvOS)
.background(Color.background(scheme: colorScheme))
#else
.background(Color.background)
#endif
2022-12-18 18:39:03 +00:00
.opacity(model.isPresenting ? 1 : 0)
2022-12-17 23:08:30 +00:00
}
var watchNext: some View {
ScrollView {
VStack(alignment: .leading) {
if model.isAutoplaying,
2022-12-18 18:39:03 +00:00
let item = model.nextFromTheQueue
2022-12-17 23:08:30 +00:00
{
HStack {
2022-12-18 18:39:03 +00:00
Text("Playing Next in \(Int(model.countdown.rounded()))...")
.font(.headline.monospacedDigit())
2022-12-17 23:08:30 +00:00
Spacer()
Button {
2022-12-18 18:39:03 +00:00
model.keepFromAutoplaying()
2022-12-17 23:08:30 +00:00
} label: {
2022-12-18 18:39:03 +00:00
Label("Cancel", systemImage: "pause.fill")
#if os(iOS)
.imageScale(.large)
.padding([.vertical, .leading])
.font(.headline.bold())
#endif
2022-12-17 23:08:30 +00:00
}
}
2022-12-18 18:39:03 +00:00
#if os(tvOS)
.padding(.top, 10)
#endif
2022-12-17 23:08:30 +00:00
PlayerQueueRow(item: item)
}
2022-12-18 18:39:03 +00:00
2022-12-17 23:08:30 +00:00
moreVideos
2022-12-18 18:39:03 +00:00
.padding(.top, 15)
2022-12-17 23:08:30 +00:00
}
.padding(.horizontal)
}
2022-12-18 12:11:06 +00:00
#if os(iOS)
2022-12-17 23:08:30 +00:00
.navigationBarTitleDisplayMode(.inline)
2022-12-18 12:11:06 +00:00
#endif
2022-12-17 23:08:30 +00:00
#if !os(macOS)
2022-12-18 18:39:03 +00:00
.navigationTitle(model.page.title)
.toolbar {
ToolbarItem(placement: .cancellationAction) {
hideCloseButton
}
ToolbarItem(placement: .primaryAction) {
reopenButton
}
}
#endif
}
2022-12-17 23:08:30 +00:00
2022-12-18 18:39:03 +00:00
var watchNextMenu: some View {
#if os(tvOS)
Button {
model.page = model.page.next()
} label: {
menuLabel
}
#elseif os(macOS)
pagePicker
.modifier(SettingsPickerModifier())
#if os(macOS)
.frame(maxWidth: 150)
#endif
#else
Menu {
pagePicker
} label: {
HStack(spacing: 12) {
menuLabel
.foregroundColor(.primary)
Image(systemName: "chevron.down.circle.fill")
.foregroundColor(.accentColor)
.imageScale(.small)
2022-12-17 23:08:30 +00:00
}
2022-12-18 18:39:03 +00:00
.transaction { t in t.animation = nil }
2022-12-17 23:08:30 +00:00
}
2022-12-18 18:39:03 +00:00
2022-12-17 23:08:30 +00:00
#endif
}
2022-12-18 18:39:03 +00:00
var menuLabel: some View {
HStack {
Image(systemName: model.page.systemImageName)
.imageScale(.small)
Text(model.page.title)
.font(.headline)
}
}
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)
}
}
}
@ViewBuilder var hideCloseButton: some View {
if model.isHideable {
hideButton
} else {
closeButton
}
}
var hideButton: some View {
Button {
model.hide()
} label: {
Label("Hide", systemImage: "chevron.down")
}
}
2022-12-17 23:08:30 +00:00
var closeButton: some View {
Button {
2022-12-18 18:39:03 +00:00
model.close()
2022-12-17 23:08:30 +00:00
} label: {
Label("Close", systemImage: "xmark")
}
}
@ViewBuilder var reopenButton: some View {
2022-12-18 18:39:03 +00:00
if model.isRestartable {
2022-12-17 23:08:30 +00:00
Button {
2022-12-18 18:39:03 +00:00
model.restart()
2022-12-17 23:08:30 +00:00
} label: {
2022-12-18 18:39:03 +00:00
Label(model.reason == .userInteracted ? "Back" : "Reopen", systemImage: "arrow.counterclockwise")
2022-12-17 23:08:30 +00:00
}
}
}
@ViewBuilder var moreVideos: some View {
VStack(spacing: 12) {
2022-12-18 18:39:03 +00:00
switch model.page {
case .queue:
let queueForMoreVideos = player.queue.isEmpty ? [] : player.queue.suffix(from: model.isAutoplaying ? 1 : 0)
if !queueForMoreVideos.isEmpty {
2022-12-17 23:08:30 +00:00
ForEach(queueForMoreVideos) { item in
2022-12-18 18:39:03 +00:00
PlayerQueueRow(item: item)
.contextMenu {
removeButton(item)
removeAllButton()
2022-12-17 23:08:30 +00:00
2022-12-18 18:39:03 +00:00
if let video = item.video {
VideoContextMenuView(video: video)
}
}
#if os(tvOS)
.padding(.horizontal, 30)
#endif
2022-12-17 23:08:30 +00:00
2022-12-18 18:39:03 +00:00
#if !os(tvOS)
Divider()
#endif
}
} else if player.playbackMode != .related && player.playbackMode != .loopOne {
Label(
model.isAutoplaying ? "Nothing more in the queue" : "Queue is empty",
systemImage: WatchNextViewModel.Page.queue.systemImageName
)
.foregroundColor(.secondary)
}
case .related:
if let item = model.item {
2022-12-17 23:08:30 +00:00
ForEach(item.video.related) { video in
ContentItemView(item: .init(video: video))
.environment(\.listingStyle, .list)
}
2022-12-18 18:39:03 +00:00
} else {
Label("Nothing was played",
systemImage: WatchNextViewModel.Page.related.systemImageName)
.foregroundColor(.secondary)
2022-12-17 23:08:30 +00:00
}
2022-12-18 18:39:03 +00:00
case .history:
if saveHistory {
2022-12-17 23:08:30 +00:00
HistoryView(limit: 15)
}
}
}
}
2022-12-18 18:39:03 +00:00
private func removeButton(_ item: PlayerQueueItem) -> some View {
Button {
player.remove(item)
} label: {
Label("Remove from the queue", systemImage: "trash")
2022-12-17 23:08:30 +00:00
}
2022-12-18 18:39:03 +00:00
}
2022-12-17 23:08:30 +00:00
2022-12-18 18:39:03 +00:00
private func removeAllButton() -> some View {
Button {
player.removeQueueItems()
} label: {
Label("Clear the queue", systemImage: "trash.fill")
}
2022-12-17 23:08:30 +00:00
}
}
2022-12-18 18:39:03 +00:00
struct WatchNextView_Previews: PreviewProvider {
2022-12-17 23:08:30 +00:00
static var previews: some View {
WatchNextView()
.onAppear {
2022-12-18 18:39:03 +00:00
WatchNextViewModel.shared.finishedWatching(.init(.fixture))
2022-12-17 23:08:30 +00:00
}
}
}