2023-05-20 20:49:10 +00:00
|
|
|
import Defaults
|
2022-08-06 13:27:34 +00:00
|
|
|
import SwiftUI
|
|
|
|
|
|
|
|
struct PlayerBackendView: View {
|
|
|
|
#if os(iOS)
|
|
|
|
@Environment(\.verticalSizeClass) private var verticalSizeClass
|
2023-05-20 22:18:10 +00:00
|
|
|
@ObservedObject private var safeAreaModel = SafeAreaModel.shared
|
2022-08-06 13:27:34 +00:00
|
|
|
#endif
|
2022-11-24 20:36:05 +00:00
|
|
|
@ObservedObject private var player = PlayerModel.shared
|
2022-08-06 13:27:34 +00:00
|
|
|
|
2023-05-20 20:49:10 +00:00
|
|
|
@Default(.avPlayerUsesSystemControls) private var avPlayerUsesSystemControls
|
|
|
|
|
2022-08-06 13:27:34 +00:00
|
|
|
var body: some View {
|
|
|
|
ZStack(alignment: .top) {
|
|
|
|
Group {
|
2022-12-20 22:21:12 +00:00
|
|
|
ZStack {
|
|
|
|
Group {
|
|
|
|
switch player.activeBackend {
|
|
|
|
case .mpv:
|
|
|
|
player.mpvPlayerView
|
|
|
|
case .appleAVPlayer:
|
2023-05-20 20:49:10 +00:00
|
|
|
#if os(tvOS)
|
|
|
|
AppleAVPlayerView()
|
|
|
|
#else
|
|
|
|
if avPlayerUsesSystemControls,
|
|
|
|
!player.playingInPictureInPicture,
|
|
|
|
!player.avPlayerBackend.isStartingPiP
|
|
|
|
{
|
|
|
|
AppleAVPlayerView()
|
|
|
|
} else if !avPlayerUsesSystemControls ||
|
2023-05-22 20:48:11 +00:00
|
|
|
player.playingInPictureInPicture ||
|
2023-05-20 20:49:10 +00:00
|
|
|
player.avPlayerBackend.isStartingPiP
|
|
|
|
{
|
|
|
|
AppleAVPlayerLayerView()
|
|
|
|
}
|
|
|
|
#endif
|
2022-12-20 22:21:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
.zIndex(0)
|
2022-08-06 13:27:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
.overlay(GeometryReader { proxy in
|
|
|
|
Color.clear
|
2022-08-13 14:46:45 +00:00
|
|
|
.onAppear { player.playerSize = proxy.size }
|
2022-08-06 13:27:34 +00:00
|
|
|
.onChange(of: proxy.size) { _ in player.playerSize = proxy.size }
|
2024-09-15 17:53:34 +00:00
|
|
|
.onChange(of: player.currentItem?.id) { _ in player.playerSize = proxy.size }
|
2022-08-06 13:27:34 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
#if !os(tvOS)
|
2023-05-20 20:49:10 +00:00
|
|
|
if player.activeBackend == .mpv || !avPlayerUsesSystemControls {
|
|
|
|
PlayerGestures()
|
|
|
|
}
|
2023-05-21 10:09:18 +00:00
|
|
|
PlayerControls()
|
|
|
|
#if os(iOS)
|
|
|
|
.padding(.top, controlsTopPadding)
|
|
|
|
.padding(.bottom, controlsBottomPadding)
|
|
|
|
#endif
|
2022-08-28 22:29:29 +00:00
|
|
|
#else
|
|
|
|
hiddenControlsButton
|
2022-08-06 13:27:34 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#if os(iOS)
|
2022-09-01 23:05:31 +00:00
|
|
|
.statusBarHidden(player.playingFullScreen)
|
2022-08-06 13:27:34 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#if os(iOS)
|
|
|
|
var controlsTopPadding: Double {
|
2022-09-01 23:05:31 +00:00
|
|
|
guard player.playingFullScreen else { return 0 }
|
2022-08-06 13:27:34 +00:00
|
|
|
|
|
|
|
if UIDevice.current.userInterfaceIdiom != .pad {
|
2023-05-20 14:04:58 +00:00
|
|
|
return verticalSizeClass == .compact ? safeAreaModel.safeArea.top : 0
|
2022-08-06 13:27:34 +00:00
|
|
|
}
|
2023-06-17 12:09:51 +00:00
|
|
|
return safeAreaModel.safeArea.top.isZero ? safeAreaModel.safeArea.bottom : safeAreaModel.safeArea.top
|
2022-08-06 13:27:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var controlsBottomPadding: Double {
|
|
|
|
if UIDevice.current.userInterfaceIdiom != .pad {
|
2023-05-20 14:04:58 +00:00
|
|
|
return player.playingFullScreen || verticalSizeClass == .compact ? safeAreaModel.safeArea.bottom : 0
|
2022-08-06 13:27:34 +00:00
|
|
|
}
|
2023-06-17 12:09:51 +00:00
|
|
|
return player.playingFullScreen ? safeAreaModel.safeArea.bottom : 0
|
2022-08-06 13:27:34 +00:00
|
|
|
}
|
|
|
|
#endif
|
2022-08-28 22:29:29 +00:00
|
|
|
|
|
|
|
#if os(tvOS)
|
|
|
|
private var hiddenControlsButton: some View {
|
|
|
|
VStack {
|
|
|
|
Button {
|
|
|
|
player.controls.show()
|
|
|
|
} label: {
|
|
|
|
EmptyView()
|
|
|
|
}
|
|
|
|
.offset(y: -100)
|
|
|
|
.buttonStyle(.plain)
|
|
|
|
.background(Color.clear)
|
|
|
|
.foregroundColor(.clear)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2022-08-06 13:27:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct PlayerBackendView_Previews: PreviewProvider {
|
|
|
|
static var previews: some View {
|
|
|
|
PlayerBackendView()
|
|
|
|
.injectFixtureEnvironmentObjects()
|
|
|
|
}
|
|
|
|
}
|