yattee/Model/Player/PlayerControlsModel.swift

144 lines
3.7 KiB
Swift
Raw Normal View History

import Combine
2022-02-16 20:23:11 +00:00
import CoreMedia
import Foundation
import SwiftUI
final class PlayerControlsModel: ObservableObject {
2022-05-21 20:58:11 +00:00
@Published var isLoadingVideo = false
2022-02-16 20:23:11 +00:00
@Published var isPlaying = true
@Published var presentingControls = false { didSet { handlePresentationChange() } }
2022-06-24 23:39:29 +00:00
@Published var presentingControlsOverlay = false { didSet { handleOverlayPresentationChange() } }
2022-02-16 20:23:11 +00:00
@Published var timer: Timer?
#if os(tvOS)
var reporter = PassthroughSubject<String, Never>()
#endif
2022-02-16 20:23:11 +00:00
var player: PlayerModel!
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-16 20:23:11 +00:00
}
func handlePresentationChange() {
if presentingControls {
DispatchQueue.main.async { [weak self] in
2022-05-27 23:23:50 +00:00
self?.player?.backend.startControlsUpdates()
2022-02-16 20:23:11 +00:00
self?.resetTimer()
}
} else {
player?.backend.stopControlsUpdates()
2022-02-16 20:23:11 +00:00
timer?.invalidate()
timer = nil
}
}
2022-06-24 23:39:29 +00:00
func handleOverlayPresentationChange() {
player?.backend.setNeedsNetworkStateUpdates(presentingControlsOverlay)
2022-07-05 17:20:25 +00:00
if presentingControlsOverlay {
removeTimer()
} else {
resetTimer()
}
2022-06-24 23:39:29 +00:00
}
2022-02-16 20:23:11 +00:00
func show() {
2022-03-27 19:24:32 +00:00
guard !(player?.currentItem.isNil ?? true) else {
return
}
guard !presentingControls else {
return
}
2022-02-21 20:57:12 +00:00
2022-06-16 17:44:39 +00:00
player.backend.updateControls()
2022-02-16 20:23:11 +00:00
withAnimation(PlayerControls.animation) {
presentingControls = true
}
}
func hide() {
2022-06-07 21:27:48 +00:00
guard let player = player,
!player.musicMode
else {
return
}
2022-03-27 19:24:32 +00:00
2022-06-07 21:27:48 +00:00
player.backend.stopControlsUpdates()
guard !player.currentItem.isNil else {
2022-03-27 19:24:32 +00:00
return
}
guard presentingControls else {
return
}
2022-02-16 20:23:11 +00:00
withAnimation(PlayerControls.animation) {
presentingControls = false
}
}
func toggle() {
2022-06-07 21:27:48 +00:00
presentingControls ? hide() : show()
2022-02-16 20:23:11 +00:00
}
func resetTimer() {
removeTimer()
2022-06-07 21:27:48 +00:00
2022-06-07 22:05:02 +00:00
guard let player = player, !player.musicMode else {
2022-06-07 21:27:48 +00:00
return
}
2022-02-16 20:23:11 +00:00
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 14:38:37 +00:00
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-16 20:23:11 +00:00
func removeTimer() {
timer?.invalidate()
timer = nil
}
2022-03-27 19:24:32 +00:00
func update() {
2022-06-16 17:44:39 +00:00
player?.backend.updateControls()
2022-03-27 19:24:32 +00:00
}
2022-02-16 20:23:11 +00:00
}