Controls layouts, gestures and settings

This commit is contained in:
Arkadiusz Fal
2022-08-28 19:18:49 +02:00
parent 5b785cc9c2
commit 0f7d826a3e
28 changed files with 1318 additions and 537 deletions

View File

@@ -145,7 +145,7 @@ final class AVPlayerBackend: PlayerBackend {
avPlayer.replaceCurrentItem(with: nil)
}
func seek(to time: CMTime, completionHandler: ((Bool) -> Void)?) {
func seek(to time: CMTime, seekType _: PlayerTimeModel.SeekType, completionHandler: ((Bool) -> Void)?) {
guard !model.live else { return }
avPlayer.seek(
@@ -156,12 +156,6 @@ final class AVPlayerBackend: PlayerBackend {
)
}
func seek(relative time: CMTime, completionHandler: ((Bool) -> Void)? = nil) {
if let currentTime = currentTime {
seek(to: currentTime + time, completionHandler: completionHandler)
}
}
func setRate(_ rate: Float) {
avPlayer.rate = rate
}
@@ -461,10 +455,11 @@ final class AVPlayerBackend: PlayerBackend {
if self.model.activeBackend != .appleAVPlayer {
self.startPictureInPictureOnSwitch = true
let seconds = self.model.mpvBackend.currentTime?.seconds ?? 0
self.seek(to: seconds) { finished in
guard finished else { return }
self.model.pause()
self.model.changeActiveBackend(from: .mpv, to: .appleAVPlayer, changingStream: false)
self.seek(to: seconds, seekType: .backendSync) { _ in
DispatchQueue.main.async {
self.model.pause()
self.model.changeActiveBackend(from: .mpv, to: .appleAVPlayer, changingStream: false)
}
}
}
}
@@ -537,9 +532,7 @@ final class AVPlayerBackend: PlayerBackend {
#endif
if self.controlsUpdates {
self.playerTime.duration = self.playerItemDuration ?? .zero
self.playerTime.currentTime = self.currentTime ?? .zero
self.model.objectWillChange.send()
self.updateControls()
}
}
}
@@ -607,8 +600,6 @@ final class AVPlayerBackend: PlayerBackend {
}
}
func updateControls() {}
func startControlsUpdates() {
guard model.presentingPlayer, model.controls.presentingControls, !model.controls.presentingOverlays else {
logger.info("ignored controls update start")
@@ -680,6 +671,7 @@ final class AVPlayerBackend: PlayerBackend {
}
}
func getTimeUpdates() {}
func setNeedsDrawing(_: Bool) {}
func setSize(_: Double, _: Double) {}
func setNeedsNetworkStateUpdates(_: Bool) {}

View File

@@ -8,7 +8,7 @@ import Repeat
import SwiftUI
final class MPVBackend: PlayerBackend {
static var controlsUpdateInterval = 0.5
static var timeUpdateInterval = 0.5
static var networkStateUpdateInterval = 1.0
private var logger = Logger(label: "mpv-backend")
@@ -131,8 +131,8 @@ final class MPVBackend: PlayerBackend {
self.playerTime = playerTime
self.networkState = networkState
clientTimer = .init(interval: .seconds(Self.controlsUpdateInterval), mode: .infinite) { [weak self] _ in
self?.getClientUpdates()
clientTimer = .init(interval: .seconds(Self.timeUpdateInterval), mode: .infinite) { [weak self] _ in
self?.getTimeUpdates()
}
networkStateTimer = .init(interval: .seconds(Self.networkStateUpdateInterval), mode: .infinite) { [weak self] _ in
@@ -204,7 +204,7 @@ final class MPVBackend: PlayerBackend {
let segment = self.model.sponsorBlock.segments.first,
self.model.lastSkipped.isNil
{
self.seek(to: segment.endTime) { finished in
self.seek(to: segment.endTime, seekType: .segmentSkip(segment.category)) { finished in
guard finished else {
return
}
@@ -299,17 +299,9 @@ final class MPVBackend: PlayerBackend {
client?.stop()
}
func seek(to time: CMTime, completionHandler: ((Bool) -> Void)?) {
func seek(to time: CMTime, seekType _: PlayerTimeModel.SeekType, completionHandler: ((Bool) -> Void)?) {
client?.seek(to: time) { [weak self] _ in
self?.getClientUpdates()
self?.updateControls()
completionHandler?(true)
}
}
func seek(relative time: CMTime, completionHandler: ((Bool) -> Void)? = nil) {
client?.seek(relative: time) { [weak self] _ in
self?.getClientUpdates()
self?.getTimeUpdates()
self?.updateControls()
completionHandler?(true)
}
@@ -328,31 +320,6 @@ final class MPVBackend: PlayerBackend {
func closePiP() {}
func updateControls() {
self.logger.info("updating controls")
guard model.presentingPlayer, !model.controls.presentingOverlays else {
self.logger.info("ignored controls update")
return
}
DispatchQueue.main.async(qos: .userInteractive) { [weak self] in
guard let self = self else {
return
}
#if !os(macOS)
guard UIApplication.shared.applicationState != .background else {
self.logger.info("not performing controls updates in background")
return
}
#endif
self.playerTime.currentTime = self.currentTime ?? .zero
self.playerTime.duration = self.playerItemDuration ?? .zero
}
}
func startControlsUpdates() {
guard model.presentingPlayer, model.controls.presentingControls, !model.controls.presentingOverlays else {
self.logger.info("ignored controls update start")
@@ -373,7 +340,7 @@ final class MPVBackend: PlayerBackend {
private var handleSegmentsThrottle = Throttle(interval: 1)
private func getClientUpdates() {
func getTimeUpdates() {
currentTime = client?.currentTime
playerItemDuration = client?.duration
@@ -458,8 +425,7 @@ final class MPVBackend: PlayerBackend {
return
}
getClientUpdates()
getTimeUpdates()
eofPlaybackModeAction()
}

View File

@@ -1,6 +1,9 @@
import CoreMedia
import Defaults
import Foundation
#if !os(macOS)
import UIKit
#endif
protocol PlayerBackend {
var model: PlayerModel! { get set }
@@ -38,9 +41,8 @@ protocol PlayerBackend {
func stop()
func seek(to time: CMTime, completionHandler: ((Bool) -> Void)?)
func seek(to seconds: Double, completionHandler: ((Bool) -> Void)?)
func seek(relative time: CMTime, completionHandler: ((Bool) -> Void)?)
func seek(to time: CMTime, seekType: PlayerTimeModel.SeekType, completionHandler: ((Bool) -> Void)?)
func seek(to seconds: Double, seekType: PlayerTimeModel.SeekType, completionHandler: ((Bool) -> Void)?)
func setRate(_ rate: Float)
@@ -51,7 +53,8 @@ protocol PlayerBackend {
func startMusicMode()
func stopMusicMode()
func updateControls()
func getTimeUpdates()
func updateControls(completionHandler: (() -> Void)?)
func startControlsUpdates()
func stopControlsUpdates()
@@ -64,16 +67,23 @@ protocol PlayerBackend {
}
extension PlayerBackend {
func seek(to time: CMTime, completionHandler: ((Bool) -> Void)? = nil) {
seek(to: time, completionHandler: completionHandler)
func seek(to time: CMTime, seekType: PlayerTimeModel.SeekType, completionHandler: ((Bool) -> Void)? = nil) {
playerTime.registerSeek(at: time, type: seekType, restore: currentTime)
seek(to: time, seekType: seekType, completionHandler: completionHandler)
}
func seek(to seconds: Double, completionHandler: ((Bool) -> Void)? = nil) {
seek(to: .secondsInDefaultTimescale(seconds), completionHandler: completionHandler)
func seek(to seconds: Double, seekType: PlayerTimeModel.SeekType, completionHandler: ((Bool) -> Void)? = nil) {
let seconds = CMTime.secondsInDefaultTimescale(seconds)
playerTime.registerSeek(at: seconds, type: seekType, restore: currentTime)
seek(to: seconds, seekType: seekType, completionHandler: completionHandler)
}
func seek(relative time: CMTime, completionHandler: ((Bool) -> Void)? = nil) {
seek(relative: time, completionHandler: completionHandler)
func seek(relative time: CMTime, seekType: PlayerTimeModel.SeekType, completionHandler: ((Bool) -> Void)? = nil) {
if let currentTime = currentTime, let duration = playerItemDuration {
let seekTime = min(max(0, currentTime.seconds + time.seconds), duration.seconds)
playerTime.registerSeek(at: .secondsInDefaultTimescale(seekTime), type: seekType, restore: currentTime)
seek(to: seekTime, seekType: seekType, completionHandler: completionHandler)
}
}
func eofPlaybackModeAction() {
@@ -92,7 +102,7 @@ extension PlayerBackend {
model.advanceToNextItem()
}
case .loopOne:
model.backend.seek(to: .zero) { _ in
model.backend.seek(to: .zero, seekType: .loopRestart) { _ in
self.model.play()
}
case .related:
@@ -101,4 +111,27 @@ extension PlayerBackend {
model.advanceToItem(item)
}
}
func updateControls(completionHandler: (() -> Void)? = nil) {
print("updating controls")
guard model.presentingPlayer, !model.controls.presentingOverlays else {
print("ignored controls update")
completionHandler?()
return
}
DispatchQueue.main.async(qos: .userInteractive) {
#if !os(macOS)
guard UIApplication.shared.applicationState != .background else {
print("not performing controls updates in background")
completionHandler?()
return
}
#endif
self.playerTime.currentTime = self.currentTime ?? .zero
self.playerTime.duration = self.playerItemDuration ?? .zero
completionHandler?()
}
}
}