2021-07-18 22:32:46 +00:00
|
|
|
import AVKit
|
2021-10-05 20:20:09 +00:00
|
|
|
import Defaults
|
2021-07-18 22:32:46 +00:00
|
|
|
import Siesta
|
|
|
|
import SwiftUI
|
|
|
|
|
|
|
|
struct VideoPlayerView: View {
|
2021-09-18 20:36:42 +00:00
|
|
|
static let defaultAspectRatio: Double = 1.77777778
|
|
|
|
static var defaultMinimumHeightLeft: Double {
|
2021-08-22 19:13:33 +00:00
|
|
|
#if os(macOS)
|
|
|
|
300
|
|
|
|
#else
|
|
|
|
200
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2021-11-03 23:00:17 +00:00
|
|
|
@State private var playerSize: CGSize = .zero
|
2021-10-05 20:20:09 +00:00
|
|
|
@State private var fullScreen = false
|
2021-07-18 22:32:46 +00:00
|
|
|
|
2021-08-22 19:13:33 +00:00
|
|
|
#if os(iOS)
|
2021-10-05 20:20:09 +00:00
|
|
|
@Environment(\.dismiss) private var dismiss
|
|
|
|
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
|
2021-08-22 19:13:33 +00:00
|
|
|
@Environment(\.verticalSizeClass) private var verticalSizeClass
|
|
|
|
#endif
|
2021-08-16 22:46:18 +00:00
|
|
|
|
2021-10-05 20:20:09 +00:00
|
|
|
@EnvironmentObject<PlayerModel> private var player
|
2021-09-25 08:18:22 +00:00
|
|
|
|
2021-10-05 20:20:09 +00:00
|
|
|
var body: some View {
|
2021-11-04 22:01:27 +00:00
|
|
|
#if os(macOS)
|
|
|
|
HSplitView {
|
|
|
|
content
|
|
|
|
}
|
|
|
|
.frame(idealWidth: 1000, maxWidth: 1100, minHeight: 700)
|
|
|
|
#else
|
|
|
|
GeometryReader { geometry in
|
2021-11-03 23:00:17 +00:00
|
|
|
HStack(spacing: 0) {
|
|
|
|
content
|
|
|
|
}
|
|
|
|
.onAppear {
|
|
|
|
self.playerSize = geometry.size
|
|
|
|
}
|
|
|
|
.onChange(of: geometry.size) { size in
|
|
|
|
self.playerSize = size
|
|
|
|
}
|
2021-10-05 20:20:09 +00:00
|
|
|
.navigationBarHidden(true)
|
2021-11-04 22:01:27 +00:00
|
|
|
}
|
|
|
|
#endif
|
2021-07-18 22:32:46 +00:00
|
|
|
}
|
|
|
|
|
2021-10-05 20:20:09 +00:00
|
|
|
var content: some View {
|
|
|
|
Group {
|
2021-10-28 17:14:55 +00:00
|
|
|
Group {
|
2021-10-05 20:20:09 +00:00
|
|
|
#if os(tvOS)
|
2021-10-28 17:14:55 +00:00
|
|
|
player.playerView
|
2021-10-05 20:20:09 +00:00
|
|
|
#else
|
|
|
|
GeometryReader { geometry in
|
|
|
|
VStack(spacing: 0) {
|
|
|
|
#if os(iOS)
|
|
|
|
if verticalSizeClass == .regular {
|
|
|
|
PlaybackBar()
|
|
|
|
}
|
|
|
|
#elseif os(macOS)
|
|
|
|
PlaybackBar()
|
|
|
|
#endif
|
2021-07-18 22:32:46 +00:00
|
|
|
|
2021-10-05 20:20:09 +00:00
|
|
|
if player.currentItem.isNil {
|
|
|
|
playerPlaceholder(geometry: geometry)
|
|
|
|
} else {
|
2021-11-02 23:02:02 +00:00
|
|
|
#if os(macOS)
|
|
|
|
Player()
|
|
|
|
.modifier(VideoPlayerSizeModifier(geometry: geometry))
|
|
|
|
|
|
|
|
#else
|
|
|
|
player.playerView
|
|
|
|
.modifier(VideoPlayerSizeModifier(geometry: geometry))
|
|
|
|
#endif
|
2021-08-22 19:13:33 +00:00
|
|
|
}
|
2021-10-05 20:20:09 +00:00
|
|
|
}
|
2021-08-22 19:13:33 +00:00
|
|
|
#if os(iOS)
|
2021-10-05 20:20:09 +00:00
|
|
|
.onSwipeGesture(
|
|
|
|
up: {
|
|
|
|
withAnimation {
|
|
|
|
fullScreen = true
|
2021-08-22 19:13:33 +00:00
|
|
|
}
|
2021-10-05 20:20:09 +00:00
|
|
|
},
|
|
|
|
down: { dismiss() }
|
|
|
|
)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
.background(.black)
|
|
|
|
|
|
|
|
Group {
|
|
|
|
#if os(iOS)
|
|
|
|
if verticalSizeClass == .regular {
|
|
|
|
VideoDetails(sidebarQueue: sidebarQueueBinding, fullScreen: $fullScreen)
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
2021-11-03 23:00:17 +00:00
|
|
|
VideoDetails(sidebarQueue: sidebarQueueBinding, fullScreen: $fullScreen)
|
2021-10-05 20:20:09 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
.background()
|
|
|
|
.modifier(VideoDetailsPaddingModifier(geometry: geometry, fullScreen: fullScreen))
|
2021-08-22 19:13:33 +00:00
|
|
|
}
|
2021-10-05 20:20:09 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#if os(macOS)
|
|
|
|
.frame(minWidth: 650)
|
|
|
|
#endif
|
|
|
|
#if os(iOS)
|
|
|
|
if sidebarQueue {
|
2021-11-03 23:00:17 +00:00
|
|
|
PlayerQueueView(sidebarQueue: .constant(true), fullScreen: $fullScreen)
|
2021-10-05 20:20:09 +00:00
|
|
|
.frame(maxWidth: 350)
|
2021-07-18 22:32:46 +00:00
|
|
|
}
|
2021-10-05 20:20:09 +00:00
|
|
|
#elseif os(macOS)
|
2021-11-03 23:00:17 +00:00
|
|
|
if Defaults[.playerSidebar] != .never {
|
|
|
|
PlayerQueueView(sidebarQueue: sidebarQueueBinding, fullScreen: $fullScreen)
|
|
|
|
.frame(minWidth: 250)
|
|
|
|
}
|
2021-07-18 22:32:46 +00:00
|
|
|
#endif
|
|
|
|
}
|
2021-10-05 20:20:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func playerPlaceholder(geometry: GeometryProxy) -> some View {
|
|
|
|
HStack {
|
|
|
|
Spacer()
|
|
|
|
VStack {
|
|
|
|
Spacer()
|
|
|
|
VStack(spacing: 10) {
|
|
|
|
#if !os(tvOS)
|
|
|
|
Image(systemName: "ticket")
|
2021-10-19 21:27:04 +00:00
|
|
|
.font(.system(size: 120))
|
2021-10-05 20:20:09 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
Spacer()
|
|
|
|
}
|
|
|
|
.foregroundColor(.gray)
|
|
|
|
Spacer()
|
2021-07-18 22:32:46 +00:00
|
|
|
}
|
2021-10-05 20:20:09 +00:00
|
|
|
.contentShape(Rectangle())
|
|
|
|
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: geometry.size.width / VideoPlayerView.defaultAspectRatio)
|
2021-07-18 22:32:46 +00:00
|
|
|
}
|
2021-08-22 19:13:33 +00:00
|
|
|
|
2021-11-03 23:00:17 +00:00
|
|
|
var sidebarQueue: Bool {
|
|
|
|
switch Defaults[.playerSidebar] {
|
|
|
|
case .never:
|
|
|
|
return false
|
|
|
|
case .always:
|
|
|
|
return true
|
|
|
|
case .whenFits:
|
|
|
|
return playerSize.width > 900
|
2021-10-05 20:20:09 +00:00
|
|
|
}
|
2021-11-03 23:00:17 +00:00
|
|
|
}
|
2021-10-05 20:20:09 +00:00
|
|
|
|
2021-11-03 23:00:17 +00:00
|
|
|
var sidebarQueueBinding: Binding<Bool> {
|
|
|
|
Binding(
|
|
|
|
get: { sidebarQueue },
|
|
|
|
set: { _ in }
|
|
|
|
)
|
|
|
|
}
|
2021-08-22 19:13:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct VideoPlayerView_Previews: PreviewProvider {
|
|
|
|
static var previews: some View {
|
2021-10-05 20:20:09 +00:00
|
|
|
VideoPlayerView()
|
|
|
|
.injectFixtureEnvironmentObjects()
|
2021-08-22 19:13:33 +00:00
|
|
|
}
|
2021-07-18 22:32:46 +00:00
|
|
|
}
|