2022-06-30 03:13:39 +05:30
|
|
|
import Combine
|
2022-02-17 01:53:11 +05:30
|
|
|
import CoreMedia
|
|
|
|
import Foundation
|
|
|
|
import SwiftUI
|
|
|
|
|
|
|
|
final class PlayerControlsModel: ObservableObject {
|
2022-05-22 02:28:11 +05:30
|
|
|
@Published var isLoadingVideo = false
|
2022-02-17 01:53:11 +05:30
|
|
|
@Published var isPlaying = true
|
|
|
|
@Published var presentingControls = false { didSet { handlePresentationChange() } }
|
2022-06-25 05:09:29 +05:30
|
|
|
@Published var presentingControlsOverlay = false { didSet { handleOverlayPresentationChange() } }
|
2022-02-17 01:53:11 +05:30
|
|
|
@Published var timer: Timer?
|
|
|
|
|
2022-06-30 03:13:39 +05:30
|
|
|
#if os(tvOS)
|
|
|
|
var reporter = PassthroughSubject<String, Never>()
|
|
|
|
#endif
|
|
|
|
|
2022-02-17 01:53:11 +05:30
|
|
|
var player: PlayerModel!
|
|
|
|
|
2022-06-18 18:09:49 +05:30
|
|
|
init(
|
|
|
|
isLoadingVideo: Bool = false,
|
|
|
|
isPlaying: Bool = true,
|
|
|
|
presentingControls: Bool = false,
|
|
|
|
presentingControlsOverlay: Bool = false,
|
|
|
|
timer: Timer? = nil,
|
|
|
|
player: PlayerModel? = nil
|
|
|
|
) {
|
|
|
|
self.isLoadingVideo = isLoadingVideo
|
|
|
|
self.isPlaying = isPlaying
|
|
|
|
self.presentingControls = presentingControls
|
|
|
|
self.presentingControlsOverlay = presentingControlsOverlay
|
|
|
|
self.timer = timer
|
|
|
|
self.player = player
|
2022-02-17 01:53:11 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
func handlePresentationChange() {
|
|
|
|
if presentingControls {
|
|
|
|
DispatchQueue.main.async { [weak self] in
|
2022-05-28 04:53:50 +05:30
|
|
|
self?.player?.backend.startControlsUpdates()
|
2022-02-17 01:53:11 +05:30
|
|
|
self?.resetTimer()
|
|
|
|
}
|
|
|
|
} else {
|
2022-06-18 18:09:49 +05:30
|
|
|
player?.backend.stopControlsUpdates()
|
2022-02-17 01:53:11 +05:30
|
|
|
timer?.invalidate()
|
|
|
|
timer = nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-25 05:09:29 +05:30
|
|
|
func handleOverlayPresentationChange() {
|
|
|
|
player?.backend.setNeedsNetworkStateUpdates(presentingControlsOverlay)
|
2022-07-05 22:50:25 +05:30
|
|
|
if presentingControlsOverlay {
|
|
|
|
removeTimer()
|
|
|
|
} else {
|
|
|
|
resetTimer()
|
|
|
|
}
|
2022-06-25 05:09:29 +05:30
|
|
|
}
|
|
|
|
|
2022-02-17 01:53:11 +05:30
|
|
|
func show() {
|
2022-03-28 00:54:32 +05:30
|
|
|
guard !(player?.currentItem.isNil ?? true) else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
guard !presentingControls else {
|
|
|
|
return
|
|
|
|
}
|
2022-02-22 02:27:12 +05:30
|
|
|
|
2022-06-16 23:14:39 +05:30
|
|
|
player.backend.updateControls()
|
2022-02-17 01:53:11 +05:30
|
|
|
withAnimation(PlayerControls.animation) {
|
|
|
|
presentingControls = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func hide() {
|
2022-06-08 02:57:48 +05:30
|
|
|
guard let player = player,
|
|
|
|
!player.musicMode
|
|
|
|
else {
|
|
|
|
return
|
|
|
|
}
|
2022-03-28 00:54:32 +05:30
|
|
|
|
2022-06-08 02:57:48 +05:30
|
|
|
player.backend.stopControlsUpdates()
|
|
|
|
|
|
|
|
guard !player.currentItem.isNil else {
|
2022-03-28 00:54:32 +05:30
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
guard presentingControls else {
|
|
|
|
return
|
|
|
|
}
|
2022-02-17 01:53:11 +05:30
|
|
|
withAnimation(PlayerControls.animation) {
|
|
|
|
presentingControls = false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func toggle() {
|
2022-06-08 02:57:48 +05:30
|
|
|
presentingControls ? hide() : show()
|
2022-02-17 01:53:11 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
func resetTimer() {
|
|
|
|
removeTimer()
|
2022-06-08 02:57:48 +05:30
|
|
|
|
2022-06-08 03:35:02 +05:30
|
|
|
guard let player = player, !player.musicMode else {
|
2022-06-08 02:57:48 +05:30
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-02-17 01:53:11 +05:30
|
|
|
timer = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false) { _ in
|
|
|
|
withAnimation(PlayerControls.animation) { [weak self] in
|
|
|
|
self?.presentingControls = false
|
|
|
|
self?.player.backend.stopControlsUpdates()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-29 20:08:37 +05:30
|
|
|
func startPiP(startImmediately: Bool = true) {
|
|
|
|
if player.activeBackend == .mpv {
|
|
|
|
player.avPlayerBackend.switchToMPVOnPipClose = true
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !os(macOS)
|
|
|
|
player.exitFullScreen()
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if player.activeBackend != PlayerBackendType.appleAVPlayer {
|
|
|
|
player.saveTime { [weak player] in
|
|
|
|
player?.changeActiveBackend(from: .mpv, to: .appleAVPlayer)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak player] in
|
|
|
|
player?.avPlayerBackend.startPictureInPictureOnPlay = true
|
|
|
|
if startImmediately {
|
|
|
|
player?.pipController?.startPictureInPicture()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-17 01:53:11 +05:30
|
|
|
func removeTimer() {
|
|
|
|
timer?.invalidate()
|
|
|
|
timer = nil
|
|
|
|
}
|
2022-03-28 00:54:32 +05:30
|
|
|
|
|
|
|
func update() {
|
2022-06-16 23:14:39 +05:30
|
|
|
player?.backend.updateControls()
|
2022-03-28 00:54:32 +05:30
|
|
|
}
|
2022-02-17 01:53:11 +05:30
|
|
|
}
|