mirror of
https://github.com/yattee/yattee.git
synced 2025-08-06 10:44:06 +00:00
Model improvements
This commit is contained in:
@@ -12,11 +12,11 @@ final class AVPlayerBackend: PlayerBackend {
|
||||
|
||||
private var logger = Logger(label: "avplayer-backend")
|
||||
|
||||
var model: PlayerModel!
|
||||
var controls: PlayerControlsModel!
|
||||
var playerTime: PlayerTimeModel!
|
||||
var networkState: NetworkStateModel!
|
||||
var seek: SeekModel!
|
||||
var model: PlayerModel! { .shared }
|
||||
var controls: PlayerControlsModel! { .shared }
|
||||
var playerTime: PlayerTimeModel! { .shared }
|
||||
var networkState: NetworkStateModel! { .shared }
|
||||
var seek: SeekModel! { .shared }
|
||||
|
||||
var stream: Stream?
|
||||
var video: Video?
|
||||
@@ -76,11 +76,7 @@ final class AVPlayerBackend: PlayerBackend {
|
||||
|
||||
internal var controlsUpdates = false
|
||||
|
||||
init(model: PlayerModel, controls: PlayerControlsModel?, playerTime: PlayerTimeModel?) {
|
||||
self.model = model
|
||||
self.controls = controls
|
||||
self.playerTime = playerTime ?? PlayerTimeModel.shared
|
||||
|
||||
init() {
|
||||
addFrequentTimeObserver()
|
||||
addInfrequentTimeObserver()
|
||||
addPlayerTimeControlStatusObserver()
|
||||
|
@@ -13,11 +13,11 @@ final class MPVBackend: PlayerBackend {
|
||||
|
||||
private var logger = Logger(label: "mpv-backend")
|
||||
|
||||
var model: PlayerModel!
|
||||
var controls: PlayerControlsModel!
|
||||
var playerTime: PlayerTimeModel!
|
||||
var networkState: NetworkStateModel!
|
||||
var seek: SeekModel!
|
||||
var model: PlayerModel! { .shared }
|
||||
var controls: PlayerControlsModel! { .shared }
|
||||
var playerTime: PlayerTimeModel! { .shared }
|
||||
var networkState: NetworkStateModel! { .shared }
|
||||
var seek: SeekModel! { .shared }
|
||||
|
||||
var stream: Stream?
|
||||
var video: Video?
|
||||
@@ -120,17 +120,7 @@ final class MPVBackend: PlayerBackend {
|
||||
client?.cacheDuration ?? 0
|
||||
}
|
||||
|
||||
init(
|
||||
model: PlayerModel,
|
||||
controls: PlayerControlsModel? = nil,
|
||||
playerTime: PlayerTimeModel? = nil,
|
||||
networkState: NetworkStateModel? = nil
|
||||
) {
|
||||
self.model = model
|
||||
self.controls = controls
|
||||
self.playerTime = playerTime ?? PlayerTimeModel.shared
|
||||
self.networkState = networkState
|
||||
|
||||
init() {
|
||||
clientTimer = .init(interval: .seconds(Self.timeUpdateInterval), mode: .infinite) { [weak self] _ in
|
||||
self?.getTimeUpdates()
|
||||
}
|
||||
|
@@ -6,11 +6,10 @@ import Foundation
|
||||
#endif
|
||||
|
||||
protocol PlayerBackend {
|
||||
var model: PlayerModel! { get set }
|
||||
var controls: PlayerControlsModel! { get set }
|
||||
var playerTime: PlayerTimeModel! { get set }
|
||||
var seek: SeekModel! { get set }
|
||||
var networkState: NetworkStateModel! { get set }
|
||||
var model: PlayerModel! { get }
|
||||
var controls: PlayerControlsModel! { get }
|
||||
var playerTime: PlayerTimeModel! { get }
|
||||
var networkState: NetworkStateModel! { get }
|
||||
|
||||
var stream: Stream? { get set }
|
||||
var video: Video? { get set }
|
||||
@@ -69,20 +68,20 @@ protocol PlayerBackend {
|
||||
|
||||
extension PlayerBackend {
|
||||
func seek(to time: CMTime, seekType: SeekType, completionHandler: ((Bool) -> Void)? = nil) {
|
||||
seek.registerSeek(at: time, type: seekType, restore: currentTime)
|
||||
model.seek.registerSeek(at: time, type: seekType, restore: currentTime)
|
||||
seek(to: time, seekType: seekType, completionHandler: completionHandler)
|
||||
}
|
||||
|
||||
func seek(to seconds: Double, seekType: SeekType, completionHandler: ((Bool) -> Void)? = nil) {
|
||||
let seconds = CMTime.secondsInDefaultTimescale(seconds)
|
||||
seek.registerSeek(at: seconds, type: seekType, restore: currentTime)
|
||||
model.seek.registerSeek(at: seconds, type: seekType, restore: currentTime)
|
||||
seek(to: seconds, seekType: seekType, completionHandler: completionHandler)
|
||||
}
|
||||
|
||||
func seek(relative time: CMTime, seekType: SeekType, completionHandler: ((Bool) -> Void)? = nil) {
|
||||
if let currentTime = currentTime, let duration = playerItemDuration {
|
||||
let seekTime = min(max(0, currentTime.seconds + time.seconds), duration.seconds)
|
||||
seek.registerSeek(at: .secondsInDefaultTimescale(seekTime), type: seekType, restore: currentTime)
|
||||
model.seek.registerSeek(at: .secondsInDefaultTimescale(seekTime), type: seekType, restore: currentTime)
|
||||
seek(to: seekTime, seekType: seekType, completionHandler: completionHandler)
|
||||
}
|
||||
}
|
||||
|
21
Model/Player/ControlsOverlayModel.swift
Normal file
21
Model/Player/ControlsOverlayModel.swift
Normal file
@@ -0,0 +1,21 @@
|
||||
import Defaults
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
final class ControlOverlaysModel: ObservableObject {
|
||||
static let shared = ControlOverlaysModel()
|
||||
@Published var presenting = false { didSet { handlePresentationChange() } }
|
||||
|
||||
private lazy var controls = PlayerControlsModel.shared
|
||||
private lazy var player: PlayerModel! = PlayerModel.shared
|
||||
|
||||
func toggle() {
|
||||
presenting.toggle()
|
||||
controls.objectWillChange.send()
|
||||
}
|
||||
|
||||
private func handlePresentationChange() {
|
||||
guard let player = player else { return }
|
||||
player.backend.setNeedsNetworkStateUpdates(presenting && Defaults[.showMPVPlaybackStats])
|
||||
}
|
||||
}
|
@@ -10,7 +10,6 @@ final class PlayerControlsModel: ObservableObject {
|
||||
@Published var isLoadingVideo = false
|
||||
@Published var isPlaying = true
|
||||
@Published var presentingControls = false { didSet { handlePresentationChange() } }
|
||||
@Published var presentingControlsOverlay = false { didSet { handleSettingsOverlayPresentationChange() } }
|
||||
@Published var presentingDetailsOverlay = false { didSet { handleDetailsOverlayPresentationChange() } }
|
||||
var timer: Timer?
|
||||
|
||||
@@ -18,24 +17,21 @@ final class PlayerControlsModel: ObservableObject {
|
||||
private(set) var reporter = PassthroughSubject<String, Never>()
|
||||
#endif
|
||||
|
||||
var player: PlayerModel!
|
||||
private var player: PlayerModel! { .shared }
|
||||
private var controlsOverlayModel = ControlOverlaysModel.shared
|
||||
|
||||
init(
|
||||
isLoadingVideo: Bool = false,
|
||||
isPlaying: Bool = true,
|
||||
presentingControls: Bool = false,
|
||||
presentingControlsOverlay: Bool = false,
|
||||
presentingDetailsOverlay: Bool = false,
|
||||
timer: Timer? = nil,
|
||||
player: PlayerModel? = nil
|
||||
timer: Timer? = nil
|
||||
) {
|
||||
self.isLoadingVideo = isLoadingVideo
|
||||
self.isPlaying = isPlaying
|
||||
self.presentingControls = presentingControls
|
||||
self.presentingControlsOverlay = presentingControlsOverlay
|
||||
self.presentingDetailsOverlay = presentingDetailsOverlay
|
||||
self.timer = timer
|
||||
self.player = player ?? .shared
|
||||
}
|
||||
|
||||
func handlePresentationChange() {
|
||||
@@ -60,26 +56,22 @@ final class PlayerControlsModel: ObservableObject {
|
||||
}
|
||||
|
||||
func handleSettingsOverlayPresentationChange() {
|
||||
player?.backend.setNeedsNetworkStateUpdates(presentingControlsOverlay && Defaults[.showMPVPlaybackStats])
|
||||
player?.backend.setNeedsNetworkStateUpdates(controlsOverlayModel.presenting && Defaults[.showMPVPlaybackStats])
|
||||
}
|
||||
|
||||
func handleDetailsOverlayPresentationChange() {}
|
||||
|
||||
var presentingOverlays: Bool {
|
||||
presentingDetailsOverlay || presentingControlsOverlay
|
||||
presentingDetailsOverlay || controlsOverlayModel.presenting
|
||||
}
|
||||
|
||||
func hideOverlays() {
|
||||
presentingDetailsOverlay = false
|
||||
presentingControlsOverlay = false
|
||||
controlsOverlayModel.presenting = false
|
||||
}
|
||||
|
||||
func show() {
|
||||
guard !(player?.currentItem.isNil ?? true) else {
|
||||
return
|
||||
}
|
||||
|
||||
guard !presentingControls else {
|
||||
guard !player.currentItem.isNil, !presentingControls else {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -132,4 +124,8 @@ final class PlayerControlsModel: ObservableObject {
|
||||
timer?.invalidate()
|
||||
timer = nil
|
||||
}
|
||||
|
||||
func update() {
|
||||
player?.backend.updateControls()
|
||||
}
|
||||
}
|
||||
|
@@ -58,8 +58,8 @@ final class PlayerModel: ObservableObject {
|
||||
@Published var presentingPlayer = false { didSet { handlePresentationChange() } }
|
||||
@Published var activeBackend = PlayerBackendType.mpv
|
||||
|
||||
var avPlayerBackend: AVPlayerBackend!
|
||||
var mpvBackend: MPVBackend!
|
||||
var avPlayerBackend = AVPlayerBackend()
|
||||
var mpvBackend = MPVBackend()
|
||||
#if !os(macOS)
|
||||
var mpvController = MPVViewController()
|
||||
#endif
|
||||
@@ -124,34 +124,10 @@ final class PlayerModel: ObservableObject {
|
||||
|
||||
var accounts: AccountsModel
|
||||
var comments: CommentsModel
|
||||
var controls: PlayerControlsModel { didSet {
|
||||
backends.forEach { backend in
|
||||
var backend = backend
|
||||
backend.controls = controls
|
||||
backend.controls.player = self
|
||||
}
|
||||
}}
|
||||
var playerTime: PlayerTimeModel { didSet {
|
||||
backends.forEach { backend in
|
||||
var backend = backend
|
||||
backend.playerTime = playerTime
|
||||
backend.playerTime.player = self
|
||||
}
|
||||
}}
|
||||
var networkState: NetworkStateModel { didSet {
|
||||
backends.forEach { backend in
|
||||
var backend = backend
|
||||
backend.networkState = networkState
|
||||
backend.networkState.player = self
|
||||
}
|
||||
}}
|
||||
var seek: SeekModel { didSet {
|
||||
backends.forEach { backend in
|
||||
var backend = backend
|
||||
backend.seek = seek
|
||||
backend.seek.player = self
|
||||
}
|
||||
}}
|
||||
var controls: PlayerControlsModel { .shared }
|
||||
var playerTime: PlayerTimeModel { .shared }
|
||||
var networkState: NetworkStateModel { .shared }
|
||||
var seek: SeekModel { .shared }
|
||||
var navigation: NavigationModel
|
||||
|
||||
var context: NSManagedObjectContext = PersistenceController.shared.container.viewContext
|
||||
@@ -194,30 +170,11 @@ final class PlayerModel: ObservableObject {
|
||||
init(
|
||||
accounts: AccountsModel = AccountsModel(),
|
||||
comments: CommentsModel = CommentsModel(),
|
||||
controls: PlayerControlsModel = PlayerControlsModel(),
|
||||
navigation: NavigationModel = NavigationModel(),
|
||||
playerTime: PlayerTimeModel = PlayerTimeModel(),
|
||||
networkState: NetworkStateModel = NetworkStateModel(),
|
||||
seek: SeekModel = SeekModel()
|
||||
navigation: NavigationModel = NavigationModel()
|
||||
) {
|
||||
self.accounts = accounts
|
||||
self.comments = comments
|
||||
self.controls = controls
|
||||
self.navigation = navigation
|
||||
self.playerTime = playerTime
|
||||
self.networkState = networkState
|
||||
self.seek = seek
|
||||
|
||||
self.avPlayerBackend = AVPlayerBackend(
|
||||
model: self,
|
||||
controls: controls,
|
||||
playerTime: playerTime
|
||||
)
|
||||
self.mpvBackend = MPVBackend(
|
||||
model: self,
|
||||
playerTime: playerTime,
|
||||
networkState: networkState
|
||||
)
|
||||
|
||||
#if !os(macOS)
|
||||
mpvBackend.controller = mpvController
|
||||
|
Reference in New Issue
Block a user