Playback state improvements

This commit is contained in:
Arkadiusz Fal 2021-08-23 23:31:51 +02:00
parent f80b61f9c7
commit 151121aa31
11 changed files with 55 additions and 27 deletions

View File

@ -1,2 +1 @@
5

View File

@ -3,6 +3,7 @@ parent_config: https://raw.githubusercontent.com/sindresorhus/swiftlint-config/m
disabled_rules:
- identifier_name
- opening_brace
- number_separator
- multiline_arguments
excluded:

View File

@ -22,4 +22,9 @@ final class PlaybackState: ObservableObject {
return size.width / size.height
}
func reset() {
stream = nil
time = nil
}
}

View File

@ -19,14 +19,14 @@ final class PlayerState: ObservableObject {
private(set) var currentRate: Float = 0.0
static let availableRates: [Double] = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2]
var playbackState: PlaybackState?
var playbackState: PlaybackState
var timeObserver: Any?
let maxResolution: Stream.Resolution?
var playingOutsideViewController = false
init(_ video: Video? = nil, playbackState: PlaybackState? = nil, maxResolution: Stream.Resolution? = nil) {
init(_ video: Video? = nil, playbackState: PlaybackState, maxResolution: Stream.Resolution? = nil) {
self.video = video
self.playbackState = playbackState
self.maxResolution = maxResolution
@ -41,6 +41,8 @@ final class PlayerState: ObservableObject {
return
}
playbackState.reset()
loadExtendedVideoDetails(video) { video in
self.video = video
self.playVideo(video)
@ -98,12 +100,16 @@ final class PlayerState: ObservableObject {
}
fileprivate func playStream(_ stream: Stream) {
guard player != nil else {
return
}
logger.warning("loading \(stream.description) to player")
DispatchQueue.main.async {
self.saveTime()
self.player?.replaceCurrentItem(with: self.playerItemWithMetadata(for: stream))
self.playbackState?.stream = stream
self.playbackState.stream = stream
if self.timeObserver == nil {
self.addTimeObserver()
}
@ -259,7 +265,7 @@ final class PlayerState: ObservableObject {
self.player.rate = self.currentRate
}
self.playbackState?.time = self.player.currentTime()
self.playbackState.time = self.player.currentTime()
}
}

View File

@ -2,6 +2,7 @@ import SwiftUI
struct ContentView: View {
@StateObject private var navigationState = NavigationState()
@StateObject private var playbackState = PlaybackState()
@StateObject private var searchState = SearchState()
#if os(iOS)
@ -37,6 +38,7 @@ struct ContentView: View {
}
#endif
.environmentObject(navigationState)
.environmentObject(playbackState)
.environmentObject(searchState)
}
}

View File

@ -2,25 +2,32 @@ import Foundation
import SwiftUI
struct PlaybackBar: View {
@Environment(\.dismiss) private var dismiss
@ObservedObject var playbackState: PlaybackState
let video: Video
@Environment(\.dismiss) private var dismiss
@EnvironmentObject private var playbackState: PlaybackState
var body: some View {
HStack {
closeButton
.frame(minWidth: 0, maxWidth: 60, alignment: .leading)
.frame(width: 60, alignment: .leading)
Text(playbackFinishAtString)
.foregroundColor(.gray)
.font(.caption2)
.frame(minWidth: 0, maxWidth: .infinity)
.frame(minWidth: 60, maxWidth: .infinity)
Text(currentStreamString)
.foregroundColor(.gray)
.font(.caption2)
.frame(minWidth: 0, maxWidth: 60, alignment: .trailing)
VStack {
if playbackState.stream != nil {
Text(currentStreamString)
} else {
Image(systemName: "bolt.horizontal.fill")
}
}
.foregroundColor(.gray)
.font(.caption2)
.frame(width: 60, alignment: .trailing)
.fixedSize(horizontal: true, vertical: true)
}
.padding(4)
.background(.black)
@ -37,6 +44,10 @@ struct PlaybackBar: View {
let remainingSeconds = video.length - playbackState.time!.seconds
if remainingSeconds < 60 {
return "less than a minute"
}
let timeFinishAt = Date.now.addingTimeInterval(remainingSeconds)
let timeFinishAtString = timeFinishAt.formatted(date: .omitted, time: .shortened)

View File

@ -1,14 +1,15 @@
import SwiftUI
struct Player: UIViewControllerRepresentable {
@ObservedObject var playbackState: PlaybackState
@EnvironmentObject<PlaybackState> private var playbackState
var video: Video?
func makeUIViewController(context _: Context) -> PlayerViewController {
let controller = PlayerViewController()
controller.playbackState = playbackState
controller.video = video
controller.playbackState = playbackState
return controller
}

View File

@ -34,8 +34,7 @@ final class PlayerViewController: UIViewController {
}
func loadPlayer() {
playerState = PlayerState()
playerState.playbackState = playbackState
playerState = PlayerState(playbackState: playbackState)
guard !playerLoaded else {
return

View File

@ -13,11 +13,10 @@ struct VideoPlayerView: View {
}
@EnvironmentObject<NavigationState> private var navigationState
@EnvironmentObject<PlaybackState> private var playbackState
@ObservedObject private var store = Store<Video>()
@ObservedObject private var playbackState = PlaybackState()
#if os(iOS)
@Environment(\.verticalSizeClass) private var verticalSizeClass
#endif
@ -36,19 +35,21 @@ struct VideoPlayerView: View {
var body: some View {
VStack(spacing: 0) {
#if os(tvOS)
Player(playbackState: playbackState, video: video)
Player(video: video)
.environmentObject(playbackState)
#else
GeometryReader { geometry in
VStack(spacing: 0) {
#if os(iOS)
if verticalSizeClass == .regular {
PlaybackBar(playbackState: playbackState, video: video)
PlaybackBar(video: video)
}
#elseif os(macOS)
PlaybackBar(playbackState: playbackState, video: video)
PlaybackBar(video: video)
#endif
Player(playbackState: playbackState, video: video)
Player(video: video)
.environmentObject(playbackState)
.modifier(VideoPlayerSizeModifier(geometry: geometry, aspectRatio: playbackState.aspectRatio))
}
.background(.black)

View File

@ -1,14 +1,15 @@
import SwiftUI
struct Player: NSViewControllerRepresentable {
@ObservedObject var playbackState: PlaybackState
@EnvironmentObject<PlaybackState> private var playbackState
var video: Video!
func makeNSViewController(context _: Context) -> PlayerViewController {
let controller = PlayerViewController()
controller.playbackState = playbackState
controller.video = video
controller.playbackState = playbackState
return controller
}

View File

@ -3,6 +3,7 @@ import SwiftUI
struct TVNavigationView: View {
@EnvironmentObject<NavigationState> private var navigationState
@EnvironmentObject<PlaybackState> private var playbackState
@State private var showingOptions = false
@ -47,6 +48,7 @@ struct TVNavigationView: View {
.fullScreenCover(isPresented: $navigationState.showingVideo) {
if let video = navigationState.video {
VideoPlayerView(video)
.environmentObject(playbackState)
}
}
.onPlayPauseCommand { showingOptions.toggle() }