mirror of
https://github.com/yattee/yattee.git
synced 2025-10-10 17:38:15 +00:00
Controls layouts, gestures and settings
This commit is contained in:
@@ -1,13 +1,35 @@
|
||||
import CoreMedia
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
final class PlayerTimeModel: ObservableObject {
|
||||
enum SeekType: Equatable {
|
||||
case segmentSkip(String)
|
||||
case segmentRestore
|
||||
case userInteracted
|
||||
case loopRestart
|
||||
case backendSync
|
||||
|
||||
var presentable: Bool {
|
||||
self != .backendSync
|
||||
}
|
||||
}
|
||||
|
||||
static let timePlaceholder = "--:--"
|
||||
|
||||
@Published var currentTime = CMTime.zero
|
||||
@Published var duration = CMTime.zero
|
||||
|
||||
var player: PlayerModel?
|
||||
@Published var lastSeekTime: CMTime?
|
||||
@Published var lastSeekType: SeekType?
|
||||
@Published var restoreSeekTime: CMTime?
|
||||
|
||||
@Published var gestureSeek = 0.0
|
||||
@Published var gestureStart = 0.0
|
||||
|
||||
@Published var seekOSDDismissed = true
|
||||
|
||||
var player: PlayerModel!
|
||||
|
||||
var forceHours: Bool {
|
||||
duration.seconds >= 60 * 60
|
||||
@@ -30,15 +52,73 @@ final class PlayerTimeModel: ObservableObject {
|
||||
}
|
||||
|
||||
var withoutSegmentsPlaybackTime: String {
|
||||
guard let withoutSegmentsDuration = player?.playerItemDurationWithoutSponsorSegments?.seconds else {
|
||||
return Self.timePlaceholder
|
||||
}
|
||||
|
||||
guard let withoutSegmentsDuration = player?.playerItemDurationWithoutSponsorSegments?.seconds else { return Self.timePlaceholder }
|
||||
return withoutSegmentsDuration.formattedAsPlaybackTime(forceHours: forceHours) ?? Self.timePlaceholder
|
||||
}
|
||||
|
||||
var lastSeekPlaybackTime: String {
|
||||
guard let time = lastSeekTime else { return 0.formattedAsPlaybackTime(allowZero: true, forceHours: forceHours) ?? Self.timePlaceholder }
|
||||
return time.seconds.formattedAsPlaybackTime(allowZero: true, forceHours: forceHours) ?? Self.timePlaceholder
|
||||
}
|
||||
|
||||
var restoreSeekPlaybackTime: String {
|
||||
guard let time = restoreSeekTime else { return Self.timePlaceholder }
|
||||
return time.seconds.formattedAsPlaybackTime(allowZero: true, forceHours: forceHours) ?? Self.timePlaceholder
|
||||
}
|
||||
|
||||
var gestureSeekDestinationTime: Double {
|
||||
min(duration.seconds, max(0, gestureStart + gestureSeek))
|
||||
}
|
||||
|
||||
var gestureSeekDestinationPlaybackTime: String {
|
||||
guard gestureSeek != 0 else { return Self.timePlaceholder }
|
||||
return gestureSeekDestinationTime.formattedAsPlaybackTime(allowZero: true, forceHours: forceHours) ?? Self.timePlaceholder
|
||||
}
|
||||
|
||||
func onSeekGestureStart(completionHandler: (() -> Void)? = nil) {
|
||||
player.backend.getTimeUpdates()
|
||||
player.backend.updateControls {
|
||||
self.gestureStart = self.currentTime.seconds
|
||||
completionHandler?()
|
||||
}
|
||||
}
|
||||
|
||||
func onSeekGestureEnd() {
|
||||
player.backend.updateControls()
|
||||
player.backend.seek(to: gestureSeekDestinationTime, seekType: .userInteracted)
|
||||
}
|
||||
|
||||
func registerSeek(at time: CMTime, type: SeekType, restore restoreTime: CMTime? = nil) {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
withAnimation {
|
||||
self?.lastSeekTime = time
|
||||
self?.lastSeekType = type
|
||||
self?.restoreSeekTime = restoreTime
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func restoreTime() {
|
||||
guard let time = restoreSeekTime else { return }
|
||||
switch lastSeekType {
|
||||
case .segmentSkip:
|
||||
player.restoreLastSkippedSegment()
|
||||
default:
|
||||
player?.backend.seek(to: time, seekType: .userInteracted)
|
||||
}
|
||||
}
|
||||
|
||||
func resetSeek() {
|
||||
withAnimation {
|
||||
lastSeekTime = nil
|
||||
lastSeekType = nil
|
||||
}
|
||||
}
|
||||
|
||||
func reset() {
|
||||
currentTime = .zero
|
||||
duration = .zero
|
||||
resetSeek()
|
||||
gestureSeek = 0
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user