mirror of
https://github.com/yattee/yattee.git
synced 2024-11-10 00:08:21 +00:00
Remove Watch Next
This commit is contained in:
parent
67690bc435
commit
28f346dee2
@ -107,7 +107,6 @@ struct OpenVideosModel {
|
|||||||
prepending: playbackMode == .playNow || playbackMode == .playNext
|
prepending: playbackMode == .playNow || playbackMode == .playNext
|
||||||
)
|
)
|
||||||
|
|
||||||
WatchNextViewModel.shared.hide()
|
|
||||||
NavigationModel.shared.presentingChannelSheet = false
|
NavigationModel.shared.presentingChannelSheet = false
|
||||||
|
|
||||||
if playbackMode == .playNow || playbackMode == .shuffleAll {
|
if playbackMode == .playNow || playbackMode == .shuffleAll {
|
||||||
|
@ -105,7 +105,6 @@ extension PlayerBackend {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let action = {
|
|
||||||
switch model.playbackMode {
|
switch model.playbackMode {
|
||||||
case .queue, .shuffle:
|
case .queue, .shuffle:
|
||||||
model.prepareCurrentItemForHistory(finished: true)
|
model.prepareCurrentItemForHistory(finished: true)
|
||||||
@ -129,25 +128,6 @@ extension PlayerBackend {
|
|||||||
model.advanceToItem(item)
|
model.advanceToItem(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let actionAndHideWatchNext: (Bool) -> Void = { delay in
|
|
||||||
WatchNextViewModel.shared.hide()
|
|
||||||
if delay {
|
|
||||||
Delay.by(0.3) {
|
|
||||||
action()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
action()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if Defaults[.openWatchNextOnFinishedWatching], model.presentingPlayer {
|
|
||||||
let timer = Delay.by(TimeInterval(Defaults[.openWatchNextOnFinishedWatchingDelay]) ?? 5.0) {
|
|
||||||
actionAndHideWatchNext(true)
|
|
||||||
}
|
|
||||||
WatchNextViewModel.shared.finishedWatching(model.currentItem, timer: timer)
|
|
||||||
} else {
|
|
||||||
actionAndHideWatchNext(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateControls(completionHandler: (() -> Void)? = nil) {
|
func updateControls(completionHandler: (() -> Void)? = nil) {
|
||||||
print("updating controls")
|
print("updating controls")
|
||||||
|
@ -334,7 +334,6 @@ final class PlayerModel: ObservableObject {
|
|||||||
pause()
|
pause()
|
||||||
videoBeingOpened = video
|
videoBeingOpened = video
|
||||||
|
|
||||||
WatchNextViewModel.shared.hide()
|
|
||||||
navigation.presentingChannelSheet = false
|
navigation.presentingChannelSheet = false
|
||||||
|
|
||||||
var changeBackendHandler: (() -> Void)?
|
var changeBackendHandler: (() -> Void)?
|
||||||
|
@ -14,7 +14,6 @@ extension PlayerModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func play(_ videos: [Video], shuffling: Bool = false) {
|
func play(_ videos: [Video], shuffling: Bool = false) {
|
||||||
WatchNextViewModel.shared.hide()
|
|
||||||
navigation.presentingChannelSheet = false
|
navigation.presentingChannelSheet = false
|
||||||
|
|
||||||
playbackMode = shuffling ? .shuffle : .queue
|
playbackMode = shuffling ? .shuffle : .queue
|
||||||
@ -59,7 +58,6 @@ extension PlayerModel {
|
|||||||
|
|
||||||
comments.reset()
|
comments.reset()
|
||||||
stream = nil
|
stream = nil
|
||||||
WatchNextViewModel.shared.hide()
|
|
||||||
navigation.presentingChannelSheet = false
|
navigation.presentingChannelSheet = false
|
||||||
|
|
||||||
withAnimation {
|
withAnimation {
|
||||||
@ -180,7 +178,6 @@ extension PlayerModel {
|
|||||||
|
|
||||||
remove(newItem)
|
remove(newItem)
|
||||||
|
|
||||||
WatchNextViewModel.shared.hide()
|
|
||||||
navigation.presentingChannelSheet = false
|
navigation.presentingChannelSheet = false
|
||||||
currentItem = newItem
|
currentItem = newItem
|
||||||
currentItem.playbackTime = time
|
currentItem.playbackTime = time
|
||||||
@ -229,7 +226,6 @@ extension PlayerModel {
|
|||||||
|
|
||||||
withAnimation {
|
withAnimation {
|
||||||
aspectRatio = VideoPlayerView.defaultAspectRatio
|
aspectRatio = VideoPlayerView.defaultAspectRatio
|
||||||
WatchNextViewModel.shared.hide()
|
|
||||||
navigation.presentingChannelSheet = false
|
navigation.presentingChannelSheet = false
|
||||||
currentItem = item
|
currentItem = item
|
||||||
}
|
}
|
||||||
|
@ -1,205 +0,0 @@
|
|||||||
import Combine
|
|
||||||
import Defaults
|
|
||||||
import Foundation
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
final class WatchNextViewModel: ObservableObject {
|
|
||||||
enum Page: String, CaseIterable {
|
|
||||||
case queue
|
|
||||||
case related
|
|
||||||
case history
|
|
||||||
|
|
||||||
var title: String {
|
|
||||||
rawValue.capitalized.localized()
|
|
||||||
}
|
|
||||||
|
|
||||||
var systemImageName: String {
|
|
||||||
switch self {
|
|
||||||
case .queue:
|
|
||||||
return "list.and.film"
|
|
||||||
case .related:
|
|
||||||
return "rectangle.stack.fill"
|
|
||||||
case .history:
|
|
||||||
return "clock"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum PresentationReason {
|
|
||||||
case userInteracted
|
|
||||||
case finishedWatching
|
|
||||||
case closed
|
|
||||||
}
|
|
||||||
|
|
||||||
static let animation = Animation.easeIn(duration: 0.25)
|
|
||||||
static let shared = WatchNextViewModel()
|
|
||||||
|
|
||||||
@Published var item: PlayerQueueItem?
|
|
||||||
@Published private(set) var isPresenting = false
|
|
||||||
@Published var reason: PresentationReason?
|
|
||||||
@Published var page = Page.queue
|
|
||||||
|
|
||||||
@Published var countdown = 0.0
|
|
||||||
var countdownTimer: Timer?
|
|
||||||
|
|
||||||
var player = PlayerModel.shared
|
|
||||||
|
|
||||||
var autoplayTimer: Timer?
|
|
||||||
|
|
||||||
var isAutoplaying: Bool {
|
|
||||||
reason == .finishedWatching
|
|
||||||
}
|
|
||||||
|
|
||||||
var isHideable: Bool {
|
|
||||||
reason == .userInteracted
|
|
||||||
}
|
|
||||||
|
|
||||||
var isRestartable: Bool {
|
|
||||||
player.currentItem != nil && reason != .userInteracted
|
|
||||||
}
|
|
||||||
|
|
||||||
var canAutoplay: Bool {
|
|
||||||
switch player.playbackMode {
|
|
||||||
case .shuffle:
|
|
||||||
return !player.queue.isEmpty
|
|
||||||
default:
|
|
||||||
return nextFromTheQueue != nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func userInteractedOpen(_ item: PlayerQueueItem?) {
|
|
||||||
self.item = item
|
|
||||||
open(reason: .userInteracted)
|
|
||||||
}
|
|
||||||
|
|
||||||
func finishedWatching(_ item: PlayerQueueItem?, timer: Timer? = nil) {
|
|
||||||
if canAutoplay {
|
|
||||||
countdown = TimeInterval(Defaults[.openWatchNextOnFinishedWatchingDelay]) ?? 5.0
|
|
||||||
resetCountdownTimer()
|
|
||||||
autoplayTimer?.invalidate()
|
|
||||||
autoplayTimer = timer
|
|
||||||
} else {
|
|
||||||
timer?.invalidate()
|
|
||||||
}
|
|
||||||
self.item = item
|
|
||||||
open(reason: .finishedWatching)
|
|
||||||
}
|
|
||||||
|
|
||||||
func resetCountdownTimer() {
|
|
||||||
countdownTimer?.invalidate()
|
|
||||||
countdownTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { timer in
|
|
||||||
guard self.countdown > 0 else {
|
|
||||||
timer.invalidate()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.countdown = max(0, self.countdown - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func closed(_ item: PlayerQueueItem) {
|
|
||||||
self.item = item
|
|
||||||
open(reason: .closed)
|
|
||||||
}
|
|
||||||
|
|
||||||
func keepFromAutoplaying() {
|
|
||||||
userInteractedOpen(item)
|
|
||||||
cancelAutoplay()
|
|
||||||
}
|
|
||||||
|
|
||||||
func cancelAutoplay() {
|
|
||||||
autoplayTimer?.invalidate()
|
|
||||||
countdownTimer?.invalidate()
|
|
||||||
}
|
|
||||||
|
|
||||||
func restart() {
|
|
||||||
cancelAutoplay()
|
|
||||||
|
|
||||||
guard player.currentItem != nil else { return }
|
|
||||||
|
|
||||||
if reason == .closed {
|
|
||||||
hide()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
player.backend.seek(to: .zero, seekType: .loopRestart) { _ in
|
|
||||||
self.hide()
|
|
||||||
self.player.play()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func open(reason: PresentationReason) {
|
|
||||||
self.reason = reason
|
|
||||||
setPageAfterOpening()
|
|
||||||
|
|
||||||
guard !isPresenting else { return }
|
|
||||||
withAnimation(Self.animation) {
|
|
||||||
isPresenting = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
self.player.hide()
|
|
||||||
Delay.by(0.5) {
|
|
||||||
self.isPresenting = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if reason == .closed {
|
|
||||||
close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if canAutoplay {
|
|
||||||
cancelAutoplay()
|
|
||||||
hide()
|
|
||||||
} else {
|
|
||||||
close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func hide() {
|
|
||||||
guard isPresenting else { return }
|
|
||||||
withAnimation(Self.animation) {
|
|
||||||
isPresenting = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func resetItem() {
|
|
||||||
item = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func isAvailable(_ page: Page) -> Bool {
|
|
||||||
switch page {
|
|
||||||
case .queue:
|
|
||||||
return !player.queue.isEmpty
|
|
||||||
case .related:
|
|
||||||
guard let video = item?.video else { return false }
|
|
||||||
return !video.related.isEmpty
|
|
||||||
case .history:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var nextFromTheQueue: PlayerQueueItem? {
|
|
||||||
if player.playbackMode == .related {
|
|
||||||
return player.autoplayItem
|
|
||||||
} else if player.playbackMode == .queue {
|
|
||||||
return player.queue.first
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
@ -199,10 +199,8 @@ extension Defaults.Keys {
|
|||||||
static let actionButtonAddToPlaylistEnabled = Key<Bool>("actionButtonAddToPlaylistEnabled", default: true)
|
static let actionButtonAddToPlaylistEnabled = Key<Bool>("actionButtonAddToPlaylistEnabled", default: true)
|
||||||
static let actionButtonSubscribeEnabled = Key<Bool>("actionButtonSubscribeEnabled", default: false)
|
static let actionButtonSubscribeEnabled = Key<Bool>("actionButtonSubscribeEnabled", default: false)
|
||||||
static let actionButtonSettingsEnabled = Key<Bool>("actionButtonSettingsEnabled", default: true)
|
static let actionButtonSettingsEnabled = Key<Bool>("actionButtonSettingsEnabled", default: true)
|
||||||
static let actionButtonNextEnabled = Key<Bool>("actionButtonNextEnabled", default: true)
|
|
||||||
static let actionButtonHideEnabled = Key<Bool>("actionButtonHideEnabled", default: false)
|
static let actionButtonHideEnabled = Key<Bool>("actionButtonHideEnabled", default: false)
|
||||||
static let actionButtonCloseEnabled = Key<Bool>("actionButtonCloseEnabled", default: true)
|
static let actionButtonCloseEnabled = Key<Bool>("actionButtonCloseEnabled", default: true)
|
||||||
static let actionButtonNextQueueCountEnabled = Key<Bool>("actionButtonNextQueueCountEnabled", default: true)
|
|
||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
static let playerControlsLockOrientationEnabled = Key<Bool>("playerControlsLockOrientationEnabled", default: true)
|
static let playerControlsLockOrientationEnabled = Key<Bool>("playerControlsLockOrientationEnabled", default: true)
|
||||||
@ -217,7 +215,6 @@ extension Defaults.Keys {
|
|||||||
static let playerControlsRestartEnabled = Key<Bool>("playerControlsRestartEnabled", default: false)
|
static let playerControlsRestartEnabled = Key<Bool>("playerControlsRestartEnabled", default: false)
|
||||||
static let playerControlsAdvanceToNextEnabled = Key<Bool>("playerControlsAdvanceToNextEnabled", default: false)
|
static let playerControlsAdvanceToNextEnabled = Key<Bool>("playerControlsAdvanceToNextEnabled", default: false)
|
||||||
static let playerControlsPlaybackModeEnabled = Key<Bool>("playerControlsPlaybackModeEnabled", default: false)
|
static let playerControlsPlaybackModeEnabled = Key<Bool>("playerControlsPlaybackModeEnabled", default: false)
|
||||||
static let playerControlsNextEnabled = Key<Bool>("playerControlsNextEnabled", default: true)
|
|
||||||
static let playerControlsMusicModeEnabled = Key<Bool>("playerControlsMusicModeEnabled", default: true)
|
static let playerControlsMusicModeEnabled = Key<Bool>("playerControlsMusicModeEnabled", default: true)
|
||||||
|
|
||||||
static let mpvCacheSecs = Key<String>("mpvCacheSecs", default: "120")
|
static let mpvCacheSecs = Key<String>("mpvCacheSecs", default: "120")
|
||||||
@ -235,11 +232,6 @@ extension Defaults.Keys {
|
|||||||
static let playlistListingStyle = Key<ListingStyle>("playlistListingStyle", default: .cells)
|
static let playlistListingStyle = Key<ListingStyle>("playlistListingStyle", default: .cells)
|
||||||
static let channelPlaylistListingStyle = Key<ListingStyle>("channelPlaylistListingStyle", default: .cells)
|
static let channelPlaylistListingStyle = Key<ListingStyle>("channelPlaylistListingStyle", default: .cells)
|
||||||
static let searchListingStyle = Key<ListingStyle>("searchListingStyle", default: .cells)
|
static let searchListingStyle = Key<ListingStyle>("searchListingStyle", default: .cells)
|
||||||
|
|
||||||
static let openWatchNextOnFinishedWatching = Key<Bool>("openWatchNextOnFinishedWatching", default: true)
|
|
||||||
static let openWatchNextOnClose = Key<Bool>("openWatchNextOnClose", default: false)
|
|
||||||
static let openWatchNextOnFinishedWatchingDelay = Key<String>("openWatchNextOnFinishedWatchingDelay", default: "5")
|
|
||||||
|
|
||||||
static let hideShorts = Key<Bool>("hideShorts", default: false)
|
static let hideShorts = Key<Bool>("hideShorts", default: false)
|
||||||
static let showInspector = Key<ShowInspectorSetting>("showInspector", default: .onlyLocal)
|
static let showInspector = Key<ShowInspectorSetting>("showInspector", default: .onlyLocal)
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,6 @@ struct PlayerControls: View {
|
|||||||
|
|
||||||
@Default(.playerControlsLayout) private var regularPlayerControlsLayout
|
@Default(.playerControlsLayout) private var regularPlayerControlsLayout
|
||||||
@Default(.fullScreenPlayerControlsLayout) private var fullScreenPlayerControlsLayout
|
@Default(.fullScreenPlayerControlsLayout) private var fullScreenPlayerControlsLayout
|
||||||
@Default(.openWatchNextOnClose) private var openWatchNextOnClose
|
|
||||||
@Default(.buttonBackwardSeekDuration) private var buttonBackwardSeekDuration
|
@Default(.buttonBackwardSeekDuration) private var buttonBackwardSeekDuration
|
||||||
@Default(.buttonForwardSeekDuration) private var buttonForwardSeekDuration
|
@Default(.buttonForwardSeekDuration) private var buttonForwardSeekDuration
|
||||||
|
|
||||||
@ -40,7 +39,6 @@ struct PlayerControls: View {
|
|||||||
@Default(.playerControlsRestartEnabled) private var playerControlsRestartEnabled
|
@Default(.playerControlsRestartEnabled) private var playerControlsRestartEnabled
|
||||||
@Default(.playerControlsAdvanceToNextEnabled) private var playerControlsAdvanceToNextEnabled
|
@Default(.playerControlsAdvanceToNextEnabled) private var playerControlsAdvanceToNextEnabled
|
||||||
@Default(.playerControlsPlaybackModeEnabled) private var playerControlsPlaybackModeEnabled
|
@Default(.playerControlsPlaybackModeEnabled) private var playerControlsPlaybackModeEnabled
|
||||||
@Default(.playerControlsNextEnabled) private var playerControlsNextEnabled
|
|
||||||
@Default(.playerControlsMusicModeEnabled) private var playerControlsMusicModeEnabled
|
@Default(.playerControlsMusicModeEnabled) private var playerControlsMusicModeEnabled
|
||||||
|
|
||||||
private let controlsOverlayModel = ControlOverlaysModel.shared
|
private let controlsOverlayModel = ControlOverlaysModel.shared
|
||||||
@ -162,9 +160,6 @@ struct PlayerControls: View {
|
|||||||
if playerControlsPlaybackModeEnabled {
|
if playerControlsPlaybackModeEnabled {
|
||||||
playbackModeButton
|
playbackModeButton
|
||||||
}
|
}
|
||||||
if playerControlsNextEnabled {
|
|
||||||
watchNextButton
|
|
||||||
}
|
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
closeVideoButton
|
closeVideoButton
|
||||||
#else
|
#else
|
||||||
@ -360,13 +355,8 @@ struct PlayerControls: View {
|
|||||||
|
|
||||||
private var closeVideoButton: some View {
|
private var closeVideoButton: some View {
|
||||||
button("Close", systemImage: "xmark") {
|
button("Close", systemImage: "xmark") {
|
||||||
if openWatchNextOnClose {
|
|
||||||
player.pause()
|
|
||||||
WatchNextViewModel.shared.closed(player.currentItem)
|
|
||||||
} else {
|
|
||||||
player.closeCurrentItem()
|
player.closeCurrentItem()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
.focused($focusedField, equals: .close)
|
.focused($focusedField, equals: .close)
|
||||||
#endif
|
#endif
|
||||||
@ -409,12 +399,6 @@ struct PlayerControls: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var watchNextButton: some View {
|
|
||||||
button("Watch Next", systemImage: Constants.nextSystemImage) {
|
|
||||||
WatchNextViewModel.shared.userInteractedOpen(player.currentItem)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var seekBackwardButton: some View {
|
var seekBackwardButton: some View {
|
||||||
var foregroundColor: Color?
|
var foregroundColor: Color?
|
||||||
var fontSize: Double?
|
var fontSize: Double?
|
||||||
|
@ -57,7 +57,7 @@ struct InspectorView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var header: some View {
|
var header: some View {
|
||||||
Text("Inspector")
|
Text("Inspector".localized())
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
@ -7,7 +7,6 @@ struct VideoActions: View {
|
|||||||
case addToPlaylist
|
case addToPlaylist
|
||||||
case subscribe
|
case subscribe
|
||||||
case settings
|
case settings
|
||||||
case next
|
|
||||||
case hide
|
case hide
|
||||||
case close
|
case close
|
||||||
}
|
}
|
||||||
@ -19,17 +18,14 @@ struct VideoActions: View {
|
|||||||
|
|
||||||
var video: Video?
|
var video: Video?
|
||||||
|
|
||||||
@Default(.openWatchNextOnClose) private var openWatchNextOnClose
|
|
||||||
@Default(.playerActionsButtonLabelStyle) private var playerActionsButtonLabelStyle
|
@Default(.playerActionsButtonLabelStyle) private var playerActionsButtonLabelStyle
|
||||||
|
|
||||||
@Default(.actionButtonShareEnabled) private var actionButtonShareEnabled
|
@Default(.actionButtonShareEnabled) private var actionButtonShareEnabled
|
||||||
@Default(.actionButtonAddToPlaylistEnabled) private var actionButtonAddToPlaylistEnabled
|
@Default(.actionButtonAddToPlaylistEnabled) private var actionButtonAddToPlaylistEnabled
|
||||||
@Default(.actionButtonSubscribeEnabled) private var actionButtonSubscribeEnabled
|
@Default(.actionButtonSubscribeEnabled) private var actionButtonSubscribeEnabled
|
||||||
@Default(.actionButtonSettingsEnabled) private var actionButtonSettingsEnabled
|
@Default(.actionButtonSettingsEnabled) private var actionButtonSettingsEnabled
|
||||||
@Default(.actionButtonNextEnabled) private var actionButtonNextEnabled
|
|
||||||
@Default(.actionButtonHideEnabled) private var actionButtonHideEnabled
|
@Default(.actionButtonHideEnabled) private var actionButtonHideEnabled
|
||||||
@Default(.actionButtonCloseEnabled) private var actionButtonCloseEnabled
|
@Default(.actionButtonCloseEnabled) private var actionButtonCloseEnabled
|
||||||
@Default(.actionButtonNextQueueCountEnabled) private var actionButtonNextQueueCountEnabled
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(spacing: 6) {
|
HStack(spacing: 6) {
|
||||||
@ -55,8 +51,6 @@ struct VideoActions: View {
|
|||||||
return actionButtonSubscribeEnabled
|
return actionButtonSubscribeEnabled
|
||||||
case .settings:
|
case .settings:
|
||||||
return actionButtonSettingsEnabled
|
return actionButtonSettingsEnabled
|
||||||
case .next:
|
|
||||||
return actionButtonNextEnabled
|
|
||||||
case .hide:
|
case .hide:
|
||||||
return actionButtonHideEnabled
|
return actionButtonHideEnabled
|
||||||
case .close:
|
case .close:
|
||||||
@ -126,10 +120,6 @@ struct VideoActions: View {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case .next:
|
|
||||||
actionButton(nextLabel, systemImage: Constants.nextSystemImage) {
|
|
||||||
WatchNextViewModel.shared.userInteractedOpen(player.currentItem)
|
|
||||||
}
|
|
||||||
case .hide:
|
case .hide:
|
||||||
actionButton("Hide", systemImage: "chevron.down") {
|
actionButton("Hide", systemImage: "chevron.down") {
|
||||||
player.hide(animate: true)
|
player.hide(animate: true)
|
||||||
@ -137,27 +127,14 @@ struct VideoActions: View {
|
|||||||
|
|
||||||
case .close:
|
case .close:
|
||||||
actionButton("Close", systemImage: "xmark") {
|
actionButton("Close", systemImage: "xmark") {
|
||||||
if player.presentingPlayer, openWatchNextOnClose {
|
|
||||||
player.pause()
|
|
||||||
WatchNextViewModel.shared.closed(player.currentItem)
|
|
||||||
} else {
|
|
||||||
player.closeCurrentItem()
|
player.closeCurrentItem()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
.disabled(!isActionable(action))
|
.disabled(!isActionable(action))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var nextLabel: String {
|
|
||||||
if actionButtonNextQueueCountEnabled, !player.queue.isEmpty {
|
|
||||||
return "\("Next".localized()) • \(player.queue.count)"
|
|
||||||
}
|
|
||||||
|
|
||||||
return "Next".localized()
|
|
||||||
}
|
|
||||||
|
|
||||||
func actionButton(
|
func actionButton(
|
||||||
_ name: String,
|
_ name: String,
|
||||||
systemImage: String,
|
systemImage: String,
|
||||||
|
@ -80,8 +80,6 @@ struct VideoPlayerView: View {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
overlay
|
overlay
|
||||||
|
|
||||||
WatchNextView()
|
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
if player.musicMode {
|
if player.musicMode {
|
||||||
|
@ -1,363 +0,0 @@
|
|||||||
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 model.isPresenting {
|
|
||||||
#if os(iOS)
|
|
||||||
NavigationView {
|
|
||||||
watchNext
|
|
||||||
.toolbar {
|
|
||||||
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)
|
|
||||||
.padding()
|
|
||||||
#endif
|
|
||||||
watchNext
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.transition(.opacity)
|
|
||||||
.zIndex(0)
|
|
||||||
#if os(tvOS)
|
|
||||||
.background(Color.background(scheme: colorScheme))
|
|
||||||
#else
|
|
||||||
.background(Color.background)
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
var watchNext: some View {
|
|
||||||
ScrollView {
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
if model.isAutoplaying,
|
|
||||||
let item = model.nextFromTheQueue
|
|
||||||
{
|
|
||||||
HStack {
|
|
||||||
Text("Playing Next in \(Int(model.countdown.rounded()))...")
|
|
||||||
.font(.headline.monospacedDigit())
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
Button {
|
|
||||||
model.keepFromAutoplaying()
|
|
||||||
} label: {
|
|
||||||
Label("Cancel", systemImage: "pause.fill")
|
|
||||||
#if os(iOS)
|
|
||||||
.imageScale(.large)
|
|
||||||
.padding([.vertical, .leading])
|
|
||||||
.font(.headline.bold())
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if os(tvOS)
|
|
||||||
.padding(.top, 10)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PlayerQueueRow(item: item)
|
|
||||||
|
|
||||||
Divider()
|
|
||||||
.padding(.vertical, 5)
|
|
||||||
}
|
|
||||||
|
|
||||||
moreVideos
|
|
||||||
.padding(.top, 15)
|
|
||||||
}
|
|
||||||
.padding(.horizontal)
|
|
||||||
}
|
|
||||||
#if os(iOS)
|
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
|
||||||
#endif
|
|
||||||
#if !os(macOS)
|
|
||||||
.navigationTitle(model.page.title)
|
|
||||||
.toolbar {
|
|
||||||
ToolbarItem(placement: .cancellationAction) {
|
|
||||||
hideCloseButton
|
|
||||||
}
|
|
||||||
|
|
||||||
ToolbarItem(placement: .primaryAction) {
|
|
||||||
reopenButton
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
playbackModePicker
|
|
||||||
} label: {
|
|
||||||
HStack(spacing: 12) {
|
|
||||||
menuLabel
|
|
||||||
.foregroundColor(.primary)
|
|
||||||
|
|
||||||
Image(systemName: "chevron.down.circle.fill")
|
|
||||||
.foregroundColor(.accentColor)
|
|
||||||
.imageScale(.small)
|
|
||||||
}
|
|
||||||
.transaction { t in t.animation = nil }
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
var menuLabel: some View {
|
|
||||||
HStack {
|
|
||||||
Image(systemName: model.page.systemImageName)
|
|
||||||
.imageScale(.small)
|
|
||||||
Text(model.page == .queue ? queueTitle : model.page.title)
|
|
||||||
.font(.headline)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var pagePicker: some View {
|
|
||||||
Picker("Page", selection: $model.page) {
|
|
||||||
ForEach(WatchNextViewModel.Page.allCases, id: \.rawValue) { page in
|
|
||||||
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 {
|
|
||||||
Group {
|
|
||||||
if model.isHideable {
|
|
||||||
hideButton
|
|
||||||
} else {
|
|
||||||
closeButton
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if !os(tvOS)
|
|
||||||
.keyboardShortcut(.cancelAction)
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
var hideButton: some View {
|
|
||||||
Button {
|
|
||||||
model.hide()
|
|
||||||
} label: {
|
|
||||||
Label("Hide", systemImage: "xmark")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var closeButton: some View {
|
|
||||||
Button {
|
|
||||||
model.close()
|
|
||||||
} label: {
|
|
||||||
Label("Close", systemImage: "xmark")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ViewBuilder var reopenButton: some View {
|
|
||||||
if model.isRestartable {
|
|
||||||
Button {
|
|
||||||
model.restart()
|
|
||||||
} label: {
|
|
||||||
Label(model.reason == .userInteracted ? "Back" : "Reopen", systemImage: "arrow.counterclockwise")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
VStack(spacing: 12) {
|
|
||||||
switch model.page {
|
|
||||||
case .queue:
|
|
||||||
|
|
||||||
if player.playbackMode == .related, !(model.isAutoplaying && model.canAutoplay) {
|
|
||||||
autoplaying
|
|
||||||
|
|
||||||
Divider()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (model.isAutoplaying && model.canAutoplay && !queueForMoreVideos.isEmpty) ||
|
|
||||||
(!model.isAutoplaying && !queueForMoreVideos.isEmpty)
|
|
||||||
{
|
|
||||||
HStack {
|
|
||||||
Text("Next in queue")
|
|
||||||
.font(.headline)
|
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
ClearQueueButton()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !queueForMoreVideos.isEmpty {
|
|
||||||
LazyVStack {
|
|
||||||
ForEach(queueForMoreVideos) { item in
|
|
||||||
ContentItemView(item: item)
|
|
||||||
.environment(\.inQueueListing, true)
|
|
||||||
.environment(\.listingStyle, .list)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
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 {
|
|
||||||
ForEach(item.video.related) { video in
|
|
||||||
ContentItemView(item: .init(video: video))
|
|
||||||
.environment(\.listingStyle, .list)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Label("Nothing was played",
|
|
||||||
systemImage: WatchNextViewModel.Page.related.systemImageName)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
case .history:
|
|
||||||
if saveHistory {
|
|
||||||
HistoryView(limit: 15)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ViewBuilder var playbackModeControl: some View {
|
|
||||||
#if os(tvOS)
|
|
||||||
Button {
|
|
||||||
player.playbackMode = player.playbackMode.next()
|
|
||||||
} label: {
|
|
||||||
Label(player.playbackMode.description, systemImage: player.playbackMode.systemImage)
|
|
||||||
.transaction { t in t.animation = nil }
|
|
||||||
.frame(minWidth: 350)
|
|
||||||
}
|
|
||||||
#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 {
|
|
||||||
static var previews: some View {
|
|
||||||
WatchNextView()
|
|
||||||
.onAppear {
|
|
||||||
WatchNextViewModel.shared.finishedWatching(.init(.fixture))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -15,12 +15,10 @@ struct PlayerControlsSettings: View {
|
|||||||
@Default(.systemControlsSeekDuration) private var systemControlsSeekDuration
|
@Default(.systemControlsSeekDuration) private var systemControlsSeekDuration
|
||||||
@Default(.actionButtonShareEnabled) private var actionButtonShareEnabled
|
@Default(.actionButtonShareEnabled) private var actionButtonShareEnabled
|
||||||
@Default(.actionButtonSubscribeEnabled) private var actionButtonSubscribeEnabled
|
@Default(.actionButtonSubscribeEnabled) private var actionButtonSubscribeEnabled
|
||||||
@Default(.actionButtonNextEnabled) private var actionButtonNextEnabled
|
|
||||||
@Default(.actionButtonCloseEnabled) private var actionButtonCloseEnabled
|
@Default(.actionButtonCloseEnabled) private var actionButtonCloseEnabled
|
||||||
@Default(.actionButtonAddToPlaylistEnabled) private var actionButtonAddToPlaylistEnabled
|
@Default(.actionButtonAddToPlaylistEnabled) private var actionButtonAddToPlaylistEnabled
|
||||||
@Default(.actionButtonSettingsEnabled) private var actionButtonSettingsEnabled
|
@Default(.actionButtonSettingsEnabled) private var actionButtonSettingsEnabled
|
||||||
@Default(.actionButtonHideEnabled) private var actionButtonHideEnabled
|
@Default(.actionButtonHideEnabled) private var actionButtonHideEnabled
|
||||||
@Default(.actionButtonNextQueueCountEnabled) private var actionButtonNextQueueCountEnabled
|
|
||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
@Default(.playerControlsLockOrientationEnabled) private var playerControlsLockOrientationEnabled
|
@Default(.playerControlsLockOrientationEnabled) private var playerControlsLockOrientationEnabled
|
||||||
@ -30,7 +28,6 @@ struct PlayerControlsSettings: View {
|
|||||||
@Default(.playerControlsRestartEnabled) private var playerControlsRestartEnabled
|
@Default(.playerControlsRestartEnabled) private var playerControlsRestartEnabled
|
||||||
@Default(.playerControlsAdvanceToNextEnabled) private var playerControlsAdvanceToNextEnabled
|
@Default(.playerControlsAdvanceToNextEnabled) private var playerControlsAdvanceToNextEnabled
|
||||||
@Default(.playerControlsPlaybackModeEnabled) private var playerControlsPlaybackModeEnabled
|
@Default(.playerControlsPlaybackModeEnabled) private var playerControlsPlaybackModeEnabled
|
||||||
@Default(.playerControlsNextEnabled) private var playerControlsNextEnabled
|
|
||||||
@Default(.playerControlsMusicModeEnabled) private var playerControlsMusicModeEnabled
|
@Default(.playerControlsMusicModeEnabled) private var playerControlsMusicModeEnabled
|
||||||
|
|
||||||
private var player = PlayerModel.shared
|
private var player = PlayerModel.shared
|
||||||
@ -109,8 +106,6 @@ struct PlayerControlsSettings: View {
|
|||||||
Section(header: SettingsHeader(text: "Actions Buttons")) {
|
Section(header: SettingsHeader(text: "Actions Buttons")) {
|
||||||
actionButtonToggles
|
actionButtonToggles
|
||||||
}
|
}
|
||||||
|
|
||||||
actionButtonNextQueueCountEnabledToggle
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var systemControlsCommandsPicker: some View {
|
private var systemControlsCommandsPicker: some View {
|
||||||
@ -274,7 +269,6 @@ struct PlayerControlsSettings: View {
|
|||||||
Toggle("Add to Playlist", isOn: $actionButtonAddToPlaylistEnabled)
|
Toggle("Add to Playlist", isOn: $actionButtonAddToPlaylistEnabled)
|
||||||
Toggle("Subscribe/Unsubscribe", isOn: $actionButtonSubscribeEnabled)
|
Toggle("Subscribe/Unsubscribe", isOn: $actionButtonSubscribeEnabled)
|
||||||
Toggle("Settings", isOn: $actionButtonSettingsEnabled)
|
Toggle("Settings", isOn: $actionButtonSettingsEnabled)
|
||||||
Toggle("Watch Next", isOn: $actionButtonNextEnabled)
|
|
||||||
Toggle("Hide player", isOn: $actionButtonHideEnabled)
|
Toggle("Hide player", isOn: $actionButtonHideEnabled)
|
||||||
Toggle("Close video", isOn: $actionButtonCloseEnabled)
|
Toggle("Close video", isOn: $actionButtonCloseEnabled)
|
||||||
}
|
}
|
||||||
@ -289,16 +283,11 @@ struct PlayerControlsSettings: View {
|
|||||||
#endif
|
#endif
|
||||||
Toggle("Restart", isOn: $playerControlsRestartEnabled)
|
Toggle("Restart", isOn: $playerControlsRestartEnabled)
|
||||||
Toggle("Play next item", isOn: $playerControlsAdvanceToNextEnabled)
|
Toggle("Play next item", isOn: $playerControlsAdvanceToNextEnabled)
|
||||||
Toggle("Watch Next", isOn: $playerControlsNextEnabled)
|
|
||||||
Toggle("Playback mode", isOn: $playerControlsPlaybackModeEnabled)
|
Toggle("Playback mode", isOn: $playerControlsPlaybackModeEnabled)
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
Toggle("Music mode", isOn: $playerControlsMusicModeEnabled)
|
Toggle("Music mode", isOn: $playerControlsMusicModeEnabled)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
var actionButtonNextQueueCountEnabledToggle: some View {
|
|
||||||
Toggle("Count of items in queue in Watch Next button", isOn: $actionButtonNextQueueCountEnabled)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PlayerControlsSettings_Previews: PreviewProvider {
|
struct PlayerControlsSettings_Previews: PreviewProvider {
|
||||||
|
@ -24,9 +24,6 @@ struct PlayerSettings: View {
|
|||||||
|
|
||||||
@Default(.enableReturnYouTubeDislike) private var enableReturnYouTubeDislike
|
@Default(.enableReturnYouTubeDislike) private var enableReturnYouTubeDislike
|
||||||
|
|
||||||
@Default(.openWatchNextOnClose) private var openWatchNextOnClose
|
|
||||||
@Default(.openWatchNextOnFinishedWatching) private var openWatchNextOnFinishedWatching
|
|
||||||
@Default(.openWatchNextOnFinishedWatchingDelay) private var openWatchNextOnFinishedWatchingDelay
|
|
||||||
@Default(.showInspector) private var showInspector
|
@Default(.showInspector) private var showInspector
|
||||||
|
|
||||||
@ObservedObject private var accounts = AccountsModel.shared
|
@ObservedObject private var accounts = AccountsModel.shared
|
||||||
@ -75,12 +72,6 @@ struct PlayerSettings: View {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Section(header: SettingsHeader(text: "Watch Next")) {
|
|
||||||
openWatchNextOnFinishedWatchingToggle
|
|
||||||
openWatchNextOnFinishedWatchingDelayTextField
|
|
||||||
openWatchNextOnCloseToggle
|
|
||||||
}
|
|
||||||
|
|
||||||
let interface = Section(header: SettingsHeader(text: "Interface".localized())) {
|
let interface = Section(header: SettingsHeader(text: "Interface".localized())) {
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
if idiom == .pad {
|
if idiom == .pad {
|
||||||
@ -150,33 +141,6 @@ struct PlayerSettings: View {
|
|||||||
.modifier(SettingsPickerModifier())
|
.modifier(SettingsPickerModifier())
|
||||||
}
|
}
|
||||||
|
|
||||||
private var openWatchNextOnCloseToggle: some View {
|
|
||||||
Toggle("Open after manual close of video", isOn: $openWatchNextOnClose)
|
|
||||||
}
|
|
||||||
|
|
||||||
private var openWatchNextOnFinishedWatchingToggle: some View {
|
|
||||||
Toggle("Open after watching video", isOn: $openWatchNextOnFinishedWatching)
|
|
||||||
}
|
|
||||||
|
|
||||||
private var openWatchNextOnFinishedWatchingDelayTextField: some View {
|
|
||||||
HStack {
|
|
||||||
Text("Autoplay delay")
|
|
||||||
.frame(minWidth: 140, alignment: .leading)
|
|
||||||
#if !os(iOS)
|
|
||||||
Spacer()
|
|
||||||
#endif
|
|
||||||
TextField("Delay", text: $openWatchNextOnFinishedWatchingDelay)
|
|
||||||
#if !os(iOS)
|
|
||||||
.frame(maxWidth: 100, alignment: .trailing)
|
|
||||||
#endif
|
|
||||||
.labelsHidden()
|
|
||||||
#if !os(macOS)
|
|
||||||
.keyboardType(.numberPad)
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
.multilineTextAlignment(.trailing)
|
|
||||||
}
|
|
||||||
|
|
||||||
private var sidebarPicker: some View {
|
private var sidebarPicker: some View {
|
||||||
Picker("Sidebar", selection: $playerSidebar) {
|
Picker("Sidebar", selection: $playerSidebar) {
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
|
@ -220,12 +220,6 @@
|
|||||||
371F2F1A269B43D300E4A7AB /* NavigationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371F2F19269B43D300E4A7AB /* NavigationModel.swift */; };
|
371F2F1A269B43D300E4A7AB /* NavigationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371F2F19269B43D300E4A7AB /* NavigationModel.swift */; };
|
||||||
371F2F1B269B43D300E4A7AB /* NavigationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371F2F19269B43D300E4A7AB /* NavigationModel.swift */; };
|
371F2F1B269B43D300E4A7AB /* NavigationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371F2F19269B43D300E4A7AB /* NavigationModel.swift */; };
|
||||||
371F2F1C269B43D300E4A7AB /* NavigationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371F2F19269B43D300E4A7AB /* NavigationModel.swift */; };
|
371F2F1C269B43D300E4A7AB /* NavigationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371F2F19269B43D300E4A7AB /* NavigationModel.swift */; };
|
||||||
37220560294BE2C700E0D176 /* WatchNextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722055F294BE2C700E0D176 /* WatchNextView.swift */; };
|
|
||||||
37220561294BE2C700E0D176 /* WatchNextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722055F294BE2C700E0D176 /* WatchNextView.swift */; };
|
|
||||||
37220562294BE2C700E0D176 /* WatchNextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722055F294BE2C700E0D176 /* WatchNextView.swift */; };
|
|
||||||
37220564294BEB2800E0D176 /* WatchNextViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37220563294BEB2800E0D176 /* WatchNextViewModel.swift */; };
|
|
||||||
37220565294BEB2800E0D176 /* WatchNextViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37220563294BEB2800E0D176 /* WatchNextViewModel.swift */; };
|
|
||||||
37220566294BEB2800E0D176 /* WatchNextViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37220563294BEB2800E0D176 /* WatchNextViewModel.swift */; };
|
|
||||||
3722AEBC274DA396005EA4D6 /* Badge+Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBB274DA396005EA4D6 /* Badge+Backport.swift */; };
|
3722AEBC274DA396005EA4D6 /* Badge+Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBB274DA396005EA4D6 /* Badge+Backport.swift */; };
|
||||||
3722AEBE274DA401005EA4D6 /* Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBD274DA401005EA4D6 /* Backport.swift */; };
|
3722AEBE274DA401005EA4D6 /* Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBD274DA401005EA4D6 /* Backport.swift */; };
|
||||||
3726386E2948A4B80043702D /* Badge+Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBB274DA396005EA4D6 /* Badge+Backport.swift */; };
|
3726386E2948A4B80043702D /* Badge+Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3722AEBB274DA396005EA4D6 /* Badge+Backport.swift */; };
|
||||||
@ -1197,8 +1191,6 @@
|
|||||||
371CC76F29468BDC00979C1A /* SettingsButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsButtons.swift; sourceTree = "<group>"; };
|
371CC76F29468BDC00979C1A /* SettingsButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsButtons.swift; sourceTree = "<group>"; };
|
||||||
371CC7732946963000979C1A /* ListingStyleButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListingStyleButtons.swift; sourceTree = "<group>"; };
|
371CC7732946963000979C1A /* ListingStyleButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListingStyleButtons.swift; sourceTree = "<group>"; };
|
||||||
371F2F19269B43D300E4A7AB /* NavigationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationModel.swift; sourceTree = "<group>"; };
|
371F2F19269B43D300E4A7AB /* NavigationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationModel.swift; sourceTree = "<group>"; };
|
||||||
3722055F294BE2C700E0D176 /* WatchNextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchNextView.swift; sourceTree = "<group>"; };
|
|
||||||
37220563294BEB2800E0D176 /* WatchNextViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchNextViewModel.swift; sourceTree = "<group>"; };
|
|
||||||
3722AEBB274DA396005EA4D6 /* Badge+Backport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Badge+Backport.swift"; sourceTree = "<group>"; };
|
3722AEBB274DA396005EA4D6 /* Badge+Backport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Badge+Backport.swift"; sourceTree = "<group>"; };
|
||||||
3722AEBD274DA401005EA4D6 /* Backport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Backport.swift; sourceTree = "<group>"; };
|
3722AEBD274DA401005EA4D6 /* Backport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Backport.swift; sourceTree = "<group>"; };
|
||||||
3722AEBF274DAEB8005EA4D6 /* Tint+Backport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Tint+Backport.swift"; sourceTree = "<group>"; };
|
3722AEBF274DAEB8005EA4D6 /* Tint+Backport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Tint+Backport.swift"; sourceTree = "<group>"; };
|
||||||
@ -1833,7 +1825,6 @@
|
|||||||
374924E629215FB60017D862 /* TapRecognizerViewModifier.swift */,
|
374924E629215FB60017D862 /* TapRecognizerViewModifier.swift */,
|
||||||
37B81AF826D2C9A700675966 /* VideoPlayerSizeModifier.swift */,
|
37B81AF826D2C9A700675966 /* VideoPlayerSizeModifier.swift */,
|
||||||
37BE0BCE26A0E2D50092E2DB /* VideoPlayerView.swift */,
|
37BE0BCE26A0E2D50092E2DB /* VideoPlayerView.swift */,
|
||||||
3722055F294BE2C700E0D176 /* WatchNextView.swift */,
|
|
||||||
);
|
);
|
||||||
path = Player;
|
path = Player;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -2429,7 +2420,6 @@
|
|||||||
37F5E8B5291BE9D0006C15F5 /* URLBookmarkModel.swift */,
|
37F5E8B5291BE9D0006C15F5 /* URLBookmarkModel.swift */,
|
||||||
37D4B19626717E1500C925CA /* Video.swift */,
|
37D4B19626717E1500C925CA /* Video.swift */,
|
||||||
3784CDDE27772EE40055BBF2 /* Watch.swift */,
|
3784CDDE27772EE40055BBF2 /* Watch.swift */,
|
||||||
37220563294BEB2800E0D176 /* WatchNextViewModel.swift */,
|
|
||||||
37130A59277657090033018A /* Yattee.xcdatamodeld */,
|
37130A59277657090033018A /* Yattee.xcdatamodeld */,
|
||||||
);
|
);
|
||||||
path = Model;
|
path = Model;
|
||||||
@ -3072,7 +3062,6 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
37220564294BEB2800E0D176 /* WatchNextViewModel.swift in Sources */,
|
|
||||||
37E6D79C2944AE1A00550C3D /* FeedModel.swift in Sources */,
|
37E6D79C2944AE1A00550C3D /* FeedModel.swift in Sources */,
|
||||||
37C8E701294FC97D00EEAB14 /* QueueView.swift in Sources */,
|
37C8E701294FC97D00EEAB14 /* QueueView.swift in Sources */,
|
||||||
374710052755291C00CE0F87 /* SearchTextField.swift in Sources */,
|
374710052755291C00CE0F87 /* SearchTextField.swift in Sources */,
|
||||||
@ -3137,7 +3126,6 @@
|
|||||||
37484C1926FC837400287258 /* PlayerSettings.swift in Sources */,
|
37484C1926FC837400287258 /* PlayerSettings.swift in Sources */,
|
||||||
3711403F26B206A6005B3555 /* SearchModel.swift in Sources */,
|
3711403F26B206A6005B3555 /* SearchModel.swift in Sources */,
|
||||||
3729037E2739E47400EA99F6 /* MenuCommands.swift in Sources */,
|
3729037E2739E47400EA99F6 /* MenuCommands.swift in Sources */,
|
||||||
37220560294BE2C700E0D176 /* WatchNextView.swift in Sources */,
|
|
||||||
37F64FE426FE70A60081B69E /* RedrawOnModifier.swift in Sources */,
|
37F64FE426FE70A60081B69E /* RedrawOnModifier.swift in Sources */,
|
||||||
37EBD8C427AF0DA800F1C24B /* PlayerBackend.swift in Sources */,
|
37EBD8C427AF0DA800F1C24B /* PlayerBackend.swift in Sources */,
|
||||||
376A33E02720CAD6000C1D6B /* VideosApp.swift in Sources */,
|
376A33E02720CAD6000C1D6B /* VideosApp.swift in Sources */,
|
||||||
@ -3513,7 +3501,6 @@
|
|||||||
376578862685429C00D4EA09 /* CaseIterable+Next.swift in Sources */,
|
376578862685429C00D4EA09 /* CaseIterable+Next.swift in Sources */,
|
||||||
37A9965F26D6F9B9006E3224 /* HomeView.swift in Sources */,
|
37A9965F26D6F9B9006E3224 /* HomeView.swift in Sources */,
|
||||||
37F4AE7326828F0900BD60EA /* VerticalCells.swift in Sources */,
|
37F4AE7326828F0900BD60EA /* VerticalCells.swift in Sources */,
|
||||||
37220561294BE2C700E0D176 /* WatchNextView.swift in Sources */,
|
|
||||||
37001560271B12DD0049C794 /* SiestaConfiguration.swift in Sources */,
|
37001560271B12DD0049C794 /* SiestaConfiguration.swift in Sources */,
|
||||||
372D85DE283841B800FF3C7D /* PiPDelegate.swift in Sources */,
|
372D85DE283841B800FF3C7D /* PiPDelegate.swift in Sources */,
|
||||||
37F13B63285E43C000B137E4 /* ControlsOverlay.swift in Sources */,
|
37F13B63285E43C000B137E4 /* ControlsOverlay.swift in Sources */,
|
||||||
@ -3606,7 +3593,6 @@
|
|||||||
373CFAF02697A78B003CB2C6 /* AddToPlaylistView.swift in Sources */,
|
373CFAF02697A78B003CB2C6 /* AddToPlaylistView.swift in Sources */,
|
||||||
3763495226DFF59D00B9A393 /* AppSidebarRecents.swift in Sources */,
|
3763495226DFF59D00B9A393 /* AppSidebarRecents.swift in Sources */,
|
||||||
370015AA28BBAE7F000149FD /* ProgressBar.swift in Sources */,
|
370015AA28BBAE7F000149FD /* ProgressBar.swift in Sources */,
|
||||||
37220565294BEB2800E0D176 /* WatchNextViewModel.swift in Sources */,
|
|
||||||
371B7E672759786B00D21217 /* Comment+Fixtures.swift in Sources */,
|
371B7E672759786B00D21217 /* Comment+Fixtures.swift in Sources */,
|
||||||
3769C02F2779F18600DDB3EA /* PlaceholderProgressView.swift in Sources */,
|
3769C02F2779F18600DDB3EA /* PlaceholderProgressView.swift in Sources */,
|
||||||
37BA794426DBA973002A0235 /* PlaylistsModel.swift in Sources */,
|
37BA794426DBA973002A0235 /* PlaylistsModel.swift in Sources */,
|
||||||
@ -3703,7 +3689,6 @@
|
|||||||
37F4AE7426828F0900BD60EA /* VerticalCells.swift in Sources */,
|
37F4AE7426828F0900BD60EA /* VerticalCells.swift in Sources */,
|
||||||
376578872685429C00D4EA09 /* CaseIterable+Next.swift in Sources */,
|
376578872685429C00D4EA09 /* CaseIterable+Next.swift in Sources */,
|
||||||
37BDFF1D29487C5A000C6404 /* ChannelListItem.swift in Sources */,
|
37BDFF1D29487C5A000C6404 /* ChannelListItem.swift in Sources */,
|
||||||
37220562294BE2C700E0D176 /* WatchNextView.swift in Sources */,
|
|
||||||
37D4B1802671650A00C925CA /* YatteeApp.swift in Sources */,
|
37D4B1802671650A00C925CA /* YatteeApp.swift in Sources */,
|
||||||
3748187026A769D60084E870 /* DetailBadge.swift in Sources */,
|
3748187026A769D60084E870 /* DetailBadge.swift in Sources */,
|
||||||
3741A32C27E7EFFD00D266D1 /* PlayerControls.swift in Sources */,
|
3741A32C27E7EFFD00D266D1 /* PlayerControls.swift in Sources */,
|
||||||
@ -3913,7 +3898,6 @@
|
|||||||
37484C1B26FC837400287258 /* PlayerSettings.swift in Sources */,
|
37484C1B26FC837400287258 /* PlayerSettings.swift in Sources */,
|
||||||
372915E82687E3B900F5A35B /* Defaults.swift in Sources */,
|
372915E82687E3B900F5A35B /* Defaults.swift in Sources */,
|
||||||
37BAB54C269B39FD00E75ED1 /* TVNavigationView.swift in Sources */,
|
37BAB54C269B39FD00E75ED1 /* TVNavigationView.swift in Sources */,
|
||||||
37220566294BEB2800E0D176 /* WatchNextViewModel.swift in Sources */,
|
|
||||||
3718B9A62921A9BE0003DB2E /* PreferenceKeys.swift in Sources */,
|
3718B9A62921A9BE0003DB2E /* PreferenceKeys.swift in Sources */,
|
||||||
3797758D2689345500DD52A8 /* Store.swift in Sources */,
|
3797758D2689345500DD52A8 /* Store.swift in Sources */,
|
||||||
37484C2F26FC844700287258 /* InstanceSettings.swift in Sources */,
|
37484C2F26FC844700287258 /* InstanceSettings.swift in Sources */,
|
||||||
|
Loading…
Reference in New Issue
Block a user