jellyflood/Shared/Components/NativeVideoPlayer.swift

112 lines
2.8 KiB
Swift

//
// Swiftfin is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//
// Copyright (c) 2025 Jellyfin & Jellyfin Contributors
//
import AVKit
import Factory
import JellyfinAPI
import Logging
import SwiftUI
// TODO: remove
struct NativeVideoPlayer: View {
@Environment(\.presentationCoordinator)
private var presentationCoordinator
@InjectedObject(\.mediaPlayerManager)
private var manager: MediaPlayerManager
@LazyState
private var proxy: AVMediaPlayerProxy
@Router
private var router
init() {
self._proxy = .init(wrappedValue: AVMediaPlayerProxy())
}
var body: some View {
ZStack {
Color.black
switch manager.state {
case .playback:
NativeVideoPlayerView(proxy: proxy)
default:
ProgressView()
}
}
.onAppear {
manager.proxy = proxy
manager.start()
}
.preference(key: IsStatusBarHiddenKey.self, value: true)
.backport
.onChange(of: presentationCoordinator.isPresented) { _, isPresented in
Container.shared.mediaPlayerManager.reset()
guard !isPresented else { return }
manager.stop()
}
.alert(
L10n.error,
isPresented: .constant(manager.error != nil)
) {
Button(L10n.close, role: .cancel) {
Container.shared.mediaPlayerManager.reset()
router.dismiss()
}
} message: {
// TODO: localize
Text("Unable to load this item.")
}
}
}
extension NativeVideoPlayer {
private struct NativeVideoPlayerView: UIViewControllerRepresentable {
let proxy: AVMediaPlayerProxy
func makeUIViewController(context: Context) -> UINativeVideoPlayerViewController {
UINativeVideoPlayerViewController(proxy: proxy)
}
func updateUIViewController(_ uiViewController: UINativeVideoPlayerViewController, context: Context) {}
}
private class UINativeVideoPlayerViewController: AVPlayerViewController {
private let proxy: AVMediaPlayerProxy
init(proxy: AVMediaPlayerProxy) {
self.proxy = proxy
super.init(nibName: nil, bundle: nil)
player = proxy.player
player?.allowsExternalPlayback = true
player?.appliesMediaSelectionCriteriaAutomatically = false
allowsPictureInPicturePlayback = true
#if !os(tvOS)
updatesNowPlayingInfoCenter = false
#endif
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
}