tvos begin final work
This commit is contained in:
parent
5b451ceaaa
commit
47249c2edd
|
@ -12,9 +12,6 @@ import Foundation
|
||||||
protocol PlayerOverlayDelegate {
|
protocol PlayerOverlayDelegate {
|
||||||
|
|
||||||
func didSelectClose()
|
func didSelectClose()
|
||||||
func didSelectGoogleCast()
|
|
||||||
func didSelectAirplay()
|
|
||||||
func didSelectSubtitles()
|
|
||||||
func didSelectMenu()
|
func didSelectMenu()
|
||||||
func didDeselectMenu()
|
func didDeselectMenu()
|
||||||
|
|
||||||
|
@ -30,8 +27,6 @@ protocol PlayerOverlayDelegate {
|
||||||
func didSelectAudioStream(index: Int)
|
func didSelectAudioStream(index: Int)
|
||||||
func didSelectSubtitleStream(index: Int)
|
func didSelectSubtitleStream(index: Int)
|
||||||
|
|
||||||
func didSelectPreviousItem()
|
func didSelectPlayPreviousItem()
|
||||||
func didSelectNextItem()
|
func didSelectPlayNextItem()
|
||||||
|
|
||||||
func didFocusOnButton()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ class VLCPlayerViewController: UIViewController {
|
||||||
private var vlcMediaPlayer = VLCMediaPlayer()
|
private var vlcMediaPlayer = VLCMediaPlayer()
|
||||||
private var lastPlayerTicks: Int64 = 0
|
private var lastPlayerTicks: Int64 = 0
|
||||||
private var lastProgressReportTicks: Int64 = 0
|
private var lastProgressReportTicks: Int64 = 0
|
||||||
private var viewModelReactCancellables = Set<AnyCancellable>()
|
private var viewModelListeners = Set<AnyCancellable>()
|
||||||
private var overlayDismissTimer: Timer?
|
private var overlayDismissTimer: Timer?
|
||||||
|
|
||||||
private var currentPlayerTicks: Int64 {
|
private var currentPlayerTicks: Int64 {
|
||||||
|
@ -42,14 +42,6 @@ class VLCPlayerViewController: UIViewController {
|
||||||
return currentOverlayContentHostingController?.view.alpha ?? 0 > 0
|
return currentOverlayContentHostingController?.view.alpha ?? 0 > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
private var jumpForwardLength: VideoPlayerJumpLength {
|
|
||||||
return Defaults[.videoPlayerJumpForward]
|
|
||||||
}
|
|
||||||
|
|
||||||
private var jumpBackwardLength: VideoPlayerJumpLength {
|
|
||||||
return Defaults[.videoPlayerJumpBackward]
|
|
||||||
}
|
|
||||||
|
|
||||||
private lazy var videoContentView = makeVideoContentView()
|
private lazy var videoContentView = makeVideoContentView()
|
||||||
private lazy var jumpBackwardOverlayView = makeJumpBackwardOverlayView()
|
private lazy var jumpBackwardOverlayView = makeJumpBackwardOverlayView()
|
||||||
private lazy var jumpForwardOverlayView = makeJumpForwardOverlayView()
|
private lazy var jumpForwardOverlayView = makeJumpForwardOverlayView()
|
||||||
|
@ -170,7 +162,7 @@ class VLCPlayerViewController: UIViewController {
|
||||||
|
|
||||||
private func makeJumpBackwardOverlayView() -> UIImageView {
|
private func makeJumpBackwardOverlayView() -> UIImageView {
|
||||||
let symbolConfig = UIImage.SymbolConfiguration(pointSize: 72)
|
let symbolConfig = UIImage.SymbolConfiguration(pointSize: 72)
|
||||||
let forwardSymbolImage = UIImage(systemName: jumpBackwardLength.backwardImageLabel, withConfiguration: symbolConfig)
|
let forwardSymbolImage = UIImage(systemName: viewModel.jumpBackwardLength.backwardImageLabel, withConfiguration: symbolConfig)
|
||||||
let imageView = UIImageView(image: forwardSymbolImage)
|
let imageView = UIImageView(image: forwardSymbolImage)
|
||||||
imageView.translatesAutoresizingMaskIntoConstraints = false
|
imageView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
|
||||||
|
@ -179,7 +171,7 @@ class VLCPlayerViewController: UIViewController {
|
||||||
|
|
||||||
private func makeJumpForwardOverlayView() -> UIImageView {
|
private func makeJumpForwardOverlayView() -> UIImageView {
|
||||||
let symbolConfig = UIImage.SymbolConfiguration(pointSize: 72)
|
let symbolConfig = UIImage.SymbolConfiguration(pointSize: 72)
|
||||||
let forwardSymbolImage = UIImage(systemName: jumpForwardLength.forwardImageLabel, withConfiguration: symbolConfig)
|
let forwardSymbolImage = UIImage(systemName: viewModel.jumpForwardLength.forwardImageLabel, withConfiguration: symbolConfig)
|
||||||
let imageView = UIImageView(image: forwardSymbolImage)
|
let imageView = UIImageView(image: forwardSymbolImage)
|
||||||
imageView.translatesAutoresizingMaskIntoConstraints = false
|
imageView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
|
||||||
|
@ -262,7 +254,6 @@ class VLCPlayerViewController: UIViewController {
|
||||||
|
|
||||||
currentOverlayHostingController.view.removeFromSuperview()
|
currentOverlayHostingController.view.removeFromSuperview()
|
||||||
currentOverlayHostingController.removeFromParent()
|
currentOverlayHostingController.removeFromParent()
|
||||||
// self.currentOverlayHostingController = nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,7 +337,7 @@ extension VLCPlayerViewController {
|
||||||
|
|
||||||
// Stop current media if there is one
|
// Stop current media if there is one
|
||||||
if vlcMediaPlayer.media != nil {
|
if vlcMediaPlayer.media != nil {
|
||||||
viewModelReactCancellables.forEach({ $0.cancel() })
|
viewModelListeners.forEach({ $0.cancel() })
|
||||||
|
|
||||||
vlcMediaPlayer.stop()
|
vlcMediaPlayer.stop()
|
||||||
viewModel.sendStopReport()
|
viewModel.sendStopReport()
|
||||||
|
@ -368,7 +359,7 @@ extension VLCPlayerViewController {
|
||||||
newViewModel.getAdjacentEpisodes()
|
newViewModel.getAdjacentEpisodes()
|
||||||
newViewModel.playerOverlayDelegate = self
|
newViewModel.playerOverlayDelegate = self
|
||||||
|
|
||||||
let startPercentage = viewModel.item.userData?.playedPercentage ?? 0
|
let startPercentage = newViewModel.item.userData?.playedPercentage ?? 0
|
||||||
|
|
||||||
if startPercentage > 0 {
|
if startPercentage > 0 {
|
||||||
newViewModel.sliderPercentage = startPercentage / 100
|
newViewModel.sliderPercentage = startPercentage / 100
|
||||||
|
@ -393,7 +384,7 @@ extension VLCPlayerViewController {
|
||||||
private func setupViewModelListeners(viewModel: VideoPlayerViewModel) {
|
private func setupViewModelListeners(viewModel: VideoPlayerViewModel) {
|
||||||
viewModel.$playbackSpeed.sink { newSpeed in
|
viewModel.$playbackSpeed.sink { newSpeed in
|
||||||
self.vlcMediaPlayer.rate = Float(newSpeed.rawValue)
|
self.vlcMediaPlayer.rate = Float(newSpeed.rawValue)
|
||||||
}.store(in: &viewModelReactCancellables)
|
}.store(in: &viewModelListeners)
|
||||||
|
|
||||||
viewModel.$sliderIsScrubbing.sink { sliderIsScrubbing in
|
viewModel.$sliderIsScrubbing.sink { sliderIsScrubbing in
|
||||||
if sliderIsScrubbing {
|
if sliderIsScrubbing {
|
||||||
|
@ -401,15 +392,19 @@ extension VLCPlayerViewController {
|
||||||
} else {
|
} else {
|
||||||
self.didEndScrubbing()
|
self.didEndScrubbing()
|
||||||
}
|
}
|
||||||
}.store(in: &viewModelReactCancellables)
|
}.store(in: &viewModelListeners)
|
||||||
|
|
||||||
viewModel.$selectedAudioStreamIndex.sink { newAudioStreamIndex in
|
viewModel.$selectedAudioStreamIndex.sink { newAudioStreamIndex in
|
||||||
self.didSelectAudioStream(index: newAudioStreamIndex)
|
self.didSelectAudioStream(index: newAudioStreamIndex)
|
||||||
}.store(in: &viewModelReactCancellables)
|
}.store(in: &viewModelListeners)
|
||||||
|
|
||||||
viewModel.$selectedSubtitleStreamIndex.sink { newSubtitleStreamIndex in
|
viewModel.$selectedSubtitleStreamIndex.sink { newSubtitleStreamIndex in
|
||||||
self.didSelectSubtitleStream(index: newSubtitleStreamIndex)
|
self.didSelectSubtitleStream(index: newSubtitleStreamIndex)
|
||||||
}.store(in: &viewModelReactCancellables)
|
}.store(in: &viewModelListeners)
|
||||||
|
|
||||||
|
viewModel.$subtitlesEnabled.sink { newSubtitlesEnabled in
|
||||||
|
self.didToggleSubtitles(newValue: newSubtitlesEnabled)
|
||||||
|
}.store(in: &viewModelListeners)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setMediaPlayerTimeAtCurrentSlider() {
|
func setMediaPlayerTimeAtCurrentSlider() {
|
||||||
|
@ -554,8 +549,8 @@ extension VLCPlayerViewController: VLCMediaPlayerDelegate {
|
||||||
viewModel.playerState = vlcMediaPlayer.state
|
viewModel.playerState = vlcMediaPlayer.state
|
||||||
|
|
||||||
if vlcMediaPlayer.state == VLCMediaPlayerState.ended {
|
if vlcMediaPlayer.state == VLCMediaPlayerState.ended {
|
||||||
if viewModel.autoPlayNextItem && viewModel.shouldShowAutoPlayNextItem && viewModel.nextItemVideoPlayerViewModel != nil {
|
if viewModel.autoplayEnabled && viewModel.nextItemVideoPlayerViewModel != nil {
|
||||||
didSelectNextItem()
|
didSelectPlayNextItem()
|
||||||
} else {
|
} else {
|
||||||
didSelectClose()
|
didSelectClose()
|
||||||
}
|
}
|
||||||
|
@ -565,9 +560,8 @@ extension VLCPlayerViewController: VLCMediaPlayerDelegate {
|
||||||
// MARK: mediaPlayerTimeChanged
|
// MARK: mediaPlayerTimeChanged
|
||||||
func mediaPlayerTimeChanged(_ aNotification: Notification!) {
|
func mediaPlayerTimeChanged(_ aNotification: Notification!) {
|
||||||
|
|
||||||
guard !viewModel.sliderIsScrubbing else {
|
if !viewModel.sliderIsScrubbing {
|
||||||
lastPlayerTicks = currentPlayerTicks
|
viewModel.sliderPercentage = Double(vlcMediaPlayer.position)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.sliderPercentage = Double(vlcMediaPlayer.position)
|
viewModel.sliderPercentage = Double(vlcMediaPlayer.position)
|
||||||
|
@ -581,6 +575,9 @@ extension VLCPlayerViewController: VLCMediaPlayerDelegate {
|
||||||
// If needing to fix subtitle streams during playback
|
// If needing to fix subtitle streams during playback
|
||||||
if vlcMediaPlayer.currentVideoSubTitleIndex != viewModel.selectedSubtitleStreamIndex && viewModel.subtitlesEnabled {
|
if vlcMediaPlayer.currentVideoSubTitleIndex != viewModel.selectedSubtitleStreamIndex && viewModel.subtitlesEnabled {
|
||||||
didSelectSubtitleStream(index: viewModel.selectedSubtitleStreamIndex)
|
didSelectSubtitleStream(index: viewModel.selectedSubtitleStreamIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
if vlcMediaPlayer.currentAudioTrackIndex != viewModel.selectedAudioStreamIndex {
|
||||||
didSelectAudioStream(index: viewModel.selectedAudioStreamIndex)
|
didSelectAudioStream(index: viewModel.selectedAudioStreamIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -606,12 +603,11 @@ extension VLCPlayerViewController: PlayerOverlayDelegate {
|
||||||
lastProgressReportTicks = currentPlayerTicks
|
lastProgressReportTicks = currentPlayerTicks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Do not call when setting to index -1
|
||||||
func didSelectSubtitleStream(index: Int) {
|
func didSelectSubtitleStream(index: Int) {
|
||||||
if viewModel.subtitlesEnabled {
|
|
||||||
vlcMediaPlayer.currentVideoSubTitleIndex = Int32(index)
|
viewModel.subtitlesEnabled = true
|
||||||
} else {
|
vlcMediaPlayer.currentVideoSubTitleIndex = Int32(index)
|
||||||
vlcMediaPlayer.currentVideoSubTitleIndex = -1
|
|
||||||
}
|
|
||||||
|
|
||||||
viewModel.sendProgressReport()
|
viewModel.sendProgressReport()
|
||||||
|
|
||||||
|
@ -626,19 +622,8 @@ extension VLCPlayerViewController: PlayerOverlayDelegate {
|
||||||
dismiss(animated: true, completion: nil)
|
dismiss(animated: true, completion: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func didSelectGoogleCast() {
|
func didToggleSubtitles(newValue: Bool) {
|
||||||
print("didSelectCast")
|
if newValue {
|
||||||
}
|
|
||||||
|
|
||||||
func didSelectAirplay() {
|
|
||||||
print("didSelectAirplay")
|
|
||||||
}
|
|
||||||
|
|
||||||
func didSelectSubtitles() {
|
|
||||||
|
|
||||||
viewModel.subtitlesEnabled = !viewModel.subtitlesEnabled
|
|
||||||
|
|
||||||
if viewModel.subtitlesEnabled {
|
|
||||||
vlcMediaPlayer.currentVideoSubTitleIndex = Int32(viewModel.selectedSubtitleStreamIndex)
|
vlcMediaPlayer.currentVideoSubTitleIndex = Int32(viewModel.selectedSubtitleStreamIndex)
|
||||||
} else {
|
} else {
|
||||||
vlcMediaPlayer.currentVideoSubTitleIndex = -1
|
vlcMediaPlayer.currentVideoSubTitleIndex = -1
|
||||||
|
@ -648,38 +633,41 @@ extension VLCPlayerViewController: PlayerOverlayDelegate {
|
||||||
// TODO: Implement properly in overlays
|
// TODO: Implement properly in overlays
|
||||||
func didSelectMenu() {
|
func didSelectMenu() {
|
||||||
stopOverlayDismissTimer()
|
stopOverlayDismissTimer()
|
||||||
|
|
||||||
hideOverlay()
|
|
||||||
showOverlayContent()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement properly in overlays
|
// TODO: Implement properly in overlays
|
||||||
func didDeselectMenu() {
|
func didDeselectMenu() {
|
||||||
|
restartOverlayDismissTimer()
|
||||||
}
|
}
|
||||||
|
|
||||||
func didSelectBackward() {
|
func didSelectBackward() {
|
||||||
|
|
||||||
flashJumpBackwardOverlay()
|
flashJumpBackwardOverlay()
|
||||||
|
|
||||||
vlcMediaPlayer.jumpBackward(jumpBackwardLength.rawValue)
|
vlcMediaPlayer.jumpBackward(viewModel.jumpBackwardLength.rawValue)
|
||||||
|
|
||||||
restartOverlayDismissTimer()
|
if displayingOverlay {
|
||||||
|
restartOverlayDismissTimer()
|
||||||
|
}
|
||||||
|
|
||||||
viewModel.sendProgressReport()
|
viewModel.sendProgressReport()
|
||||||
|
|
||||||
self.lastProgressReportTicks = currentPlayerTicks
|
lastProgressReportTicks = currentPlayerTicks
|
||||||
}
|
}
|
||||||
|
|
||||||
func didSelectForward() {
|
func didSelectForward() {
|
||||||
|
|
||||||
flashJumpFowardOverlay()
|
flashJumpFowardOverlay()
|
||||||
|
|
||||||
vlcMediaPlayer.jumpForward(jumpForwardLength.rawValue)
|
vlcMediaPlayer.jumpForward(viewModel.jumpForwardLength.rawValue)
|
||||||
|
|
||||||
restartOverlayDismissTimer()
|
if displayingOverlay {
|
||||||
|
restartOverlayDismissTimer()
|
||||||
|
}
|
||||||
|
|
||||||
viewModel.sendProgressReport()
|
viewModel.sendProgressReport()
|
||||||
|
|
||||||
self.lastProgressReportTicks = currentPlayerTicks
|
lastProgressReportTicks = currentPlayerTicks
|
||||||
}
|
}
|
||||||
|
|
||||||
func didSelectMain() {
|
func didSelectMain() {
|
||||||
|
@ -691,8 +679,7 @@ extension VLCPlayerViewController: PlayerOverlayDelegate {
|
||||||
case .playing:
|
case .playing:
|
||||||
viewModel.sendPauseReport(paused: true)
|
viewModel.sendPauseReport(paused: true)
|
||||||
vlcMediaPlayer.pause()
|
vlcMediaPlayer.pause()
|
||||||
showOverlay()
|
restartOverlayDismissTimer(interval: 5)
|
||||||
restartOverlayDismissTimer(interval: 10)
|
|
||||||
case .paused:
|
case .paused:
|
||||||
viewModel.sendPauseReport(paused: false)
|
viewModel.sendPauseReport(paused: false)
|
||||||
vlcMediaPlayer.play()
|
vlcMediaPlayer.play()
|
||||||
|
@ -718,20 +705,20 @@ extension VLCPlayerViewController: PlayerOverlayDelegate {
|
||||||
|
|
||||||
viewModel.sendProgressReport()
|
viewModel.sendProgressReport()
|
||||||
|
|
||||||
self.lastProgressReportTicks = currentPlayerTicks
|
lastProgressReportTicks = currentPlayerTicks
|
||||||
}
|
}
|
||||||
|
|
||||||
func didSelectPreviousItem() {
|
func didSelectPlayPreviousItem() {
|
||||||
setupMediaPlayer(newViewModel: viewModel.previousItemVideoPlayerViewModel!)
|
if let previousItemVideoPlayerViewModel = viewModel.previousItemVideoPlayerViewModel {
|
||||||
startPlayback()
|
setupMediaPlayer(newViewModel: previousItemVideoPlayerViewModel)
|
||||||
|
startPlayback()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func didSelectNextItem() {
|
func didSelectPlayNextItem() {
|
||||||
setupMediaPlayer(newViewModel: viewModel.nextItemVideoPlayerViewModel!)
|
if let nextItemVideoPlayerViewModel = viewModel.nextItemVideoPlayerViewModel {
|
||||||
startPlayback()
|
setupMediaPlayer(newViewModel: nextItemVideoPlayerViewModel)
|
||||||
}
|
startPlayback()
|
||||||
|
}
|
||||||
func didFocusOnButton() {
|
|
||||||
restartOverlayDismissTimer(interval: 8)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,15 +12,16 @@ import SwiftUI
|
||||||
|
|
||||||
struct SmallMediaStreamSelectionView: View {
|
struct SmallMediaStreamSelectionView: View {
|
||||||
|
|
||||||
@State var selectedItem: MediaStream?
|
@Binding var selectedItem: MediaStream?
|
||||||
|
private let title: String
|
||||||
private var items: [MediaStream]
|
private var items: [MediaStream]
|
||||||
private var selectedAction: (MediaStream) -> Void
|
private var selectedAction: (MediaStream) -> Void
|
||||||
|
|
||||||
init(items: [MediaStream], selectedItem: MediaStream? = nil, selectedAction: @escaping (MediaStream) -> Void) {
|
// init(items: [MediaStream], selectedItem: MediaStream?, selectedAction: @escaping (MediaStream) -> Void) {
|
||||||
self.items = items
|
// self.items = items
|
||||||
self.selectedItem = selectedItem
|
// self.selectedItem = selectedItem
|
||||||
self.selectedAction = selectedAction
|
// self.selectedAction = selectedAction
|
||||||
}
|
// }
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack(alignment: .bottom) {
|
ZStack(alignment: .bottom) {
|
||||||
|
@ -35,7 +36,7 @@ struct SmallMediaStreamSelectionView: View {
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
HStack {
|
HStack {
|
||||||
Text("Subtitles")
|
Text(title)
|
||||||
.font(.title3)
|
.font(.title3)
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
|
@ -44,7 +45,7 @@ struct SmallMediaStreamSelectionView: View {
|
||||||
HStack {
|
HStack {
|
||||||
ForEach(items, id: \.self) { item in
|
ForEach(items, id: \.self) { item in
|
||||||
Button {
|
Button {
|
||||||
// self.selectedItem = item
|
self.selectedAction(item)
|
||||||
} label: {
|
} label: {
|
||||||
if item == selectedItem {
|
if item == selectedItem {
|
||||||
Label(item.displayTitle ?? "No Title", systemImage: "checkmark")
|
Label(item.displayTitle ?? "No Title", systemImage: "checkmark")
|
||||||
|
|
|
@ -59,31 +59,30 @@ struct tvOSOverlayContentView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tvOSOverlayContentView_Previews: PreviewProvider {
|
struct tvOSOverlayContentView_Previews: PreviewProvider {
|
||||||
|
|
||||||
|
static let videoPlayerViewModel = VideoPlayerViewModel(item: BaseItemDto(),
|
||||||
|
title: "Glorious Purpose",
|
||||||
|
subtitle: "Loki - S1E1",
|
||||||
|
streamURL: URL(string: "www.apple.com")!,
|
||||||
|
hlsURL: URL(string: "www.apple.com")!,
|
||||||
|
response: PlaybackInfoResponse(),
|
||||||
|
audioStreams: [MediaStream(displayTitle: "English", index: -1)],
|
||||||
|
subtitleStreams: [MediaStream(displayTitle: "None", index: -1)],
|
||||||
|
selectedAudioStreamIndex: -1,
|
||||||
|
selectedSubtitleStreamIndex: -1,
|
||||||
|
subtitlesEnabled: true,
|
||||||
|
autoplayEnabled: false,
|
||||||
|
overlayType: .compact,
|
||||||
|
shouldShowPlayPreviousItem: true,
|
||||||
|
shouldShowPlayNextItem: true,
|
||||||
|
shouldShowAutoPlayNextItem: true)
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
Color.red
|
Color.red
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
|
|
||||||
tvOSOverlayContentView(viewModel: VideoPlayerViewModel(item: BaseItemDto(runTimeTicks: 720 * 10_000_000),
|
tvOSOverlayContentView(viewModel: videoPlayerViewModel)
|
||||||
title: "Glorious Purpose",
|
|
||||||
subtitle: "Loki - S1E1",
|
|
||||||
streamURL: URL(string: "www.apple.com")!,
|
|
||||||
hlsURL: URL(string: "www.apple.com")!,
|
|
||||||
response: PlaybackInfoResponse(),
|
|
||||||
audioStreams: [MediaStream(displayTitle: "English", index: -1)],
|
|
||||||
subtitleStreams: [MediaStream(displayTitle: "None", index: -1)],
|
|
||||||
defaultAudioStreamIndex: -1,
|
|
||||||
defaultSubtitleStreamIndex: -1,
|
|
||||||
playerState: .error,
|
|
||||||
shouldShowGoogleCast: false,
|
|
||||||
shouldShowAirplay: false,
|
|
||||||
subtitlesEnabled: true,
|
|
||||||
sliderPercentage: 0.432,
|
|
||||||
selectedAudioStreamIndex: -1,
|
|
||||||
selectedSubtitleStreamIndex: -1,
|
|
||||||
showAdjacentItems: true,
|
|
||||||
shouldShowAutoPlayNextItem: true,
|
|
||||||
autoPlayNextItem: true))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,16 +55,19 @@ struct tvOSVLCOverlay: View {
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
if viewModel.showAdjacentItems {
|
|
||||||
|
if viewModel.shouldShowPlayPreviousItem {
|
||||||
SFSymbolButton(systemName: "chevron.left.circle", action: {
|
SFSymbolButton(systemName: "chevron.left.circle", action: {
|
||||||
viewModel.playerOverlayDelegate?.didSelectPreviousItem()
|
viewModel.playerOverlayDelegate?.didSelectPlayPreviousItem()
|
||||||
})
|
})
|
||||||
.frame(maxWidth: 30, maxHeight: 30)
|
.frame(maxWidth: 30, maxHeight: 30)
|
||||||
.disabled(viewModel.previousItemVideoPlayerViewModel == nil)
|
.disabled(viewModel.previousItemVideoPlayerViewModel == nil)
|
||||||
.foregroundColor(viewModel.nextItemVideoPlayerViewModel == nil ? .gray : .white)
|
.foregroundColor(viewModel.nextItemVideoPlayerViewModel == nil ? .gray : .white)
|
||||||
|
}
|
||||||
|
|
||||||
|
if viewModel.shouldShowPlayNextItem {
|
||||||
SFSymbolButton(systemName: "chevron.right.circle", action: {
|
SFSymbolButton(systemName: "chevron.right.circle", action: {
|
||||||
viewModel.playerOverlayDelegate?.didSelectNextItem()
|
viewModel.playerOverlayDelegate?.didSelectPlayNextItem()
|
||||||
})
|
})
|
||||||
.frame(maxWidth: 30, maxHeight: 30)
|
.frame(maxWidth: 30, maxHeight: 30)
|
||||||
.disabled(viewModel.nextItemVideoPlayerViewModel == nil)
|
.disabled(viewModel.nextItemVideoPlayerViewModel == nil)
|
||||||
|
@ -74,12 +77,12 @@ struct tvOSVLCOverlay: View {
|
||||||
if !viewModel.subtitleStreams.isEmpty {
|
if !viewModel.subtitleStreams.isEmpty {
|
||||||
if viewModel.subtitlesEnabled {
|
if viewModel.subtitlesEnabled {
|
||||||
SFSymbolButton(systemName: "captions.bubble.fill") {
|
SFSymbolButton(systemName: "captions.bubble.fill") {
|
||||||
viewModel.playerOverlayDelegate?.didSelectSubtitles()
|
viewModel.subtitlesEnabled.toggle()
|
||||||
}
|
}
|
||||||
.frame(maxWidth: 30, maxHeight: 30)
|
.frame(maxWidth: 30, maxHeight: 30)
|
||||||
} else {
|
} else {
|
||||||
SFSymbolButton(systemName: "captions.bubble") {
|
SFSymbolButton(systemName: "captions.bubble") {
|
||||||
viewModel.playerOverlayDelegate?.didSelectSubtitles()
|
viewModel.subtitlesEnabled.toggle()
|
||||||
}
|
}
|
||||||
.frame(maxWidth: 30, maxHeight: 30)
|
.frame(maxWidth: 30, maxHeight: 30)
|
||||||
}
|
}
|
||||||
|
@ -121,32 +124,30 @@ struct tvOSVLCOverlay: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tvOSVLCOverlay_Previews: PreviewProvider {
|
struct tvOSVLCOverlay_Previews: PreviewProvider {
|
||||||
|
|
||||||
|
static let videoPlayerViewModel = VideoPlayerViewModel(item: BaseItemDto(),
|
||||||
|
title: "Glorious Purpose",
|
||||||
|
subtitle: "Loki - S1E1",
|
||||||
|
streamURL: URL(string: "www.apple.com")!,
|
||||||
|
hlsURL: URL(string: "www.apple.com")!,
|
||||||
|
response: PlaybackInfoResponse(),
|
||||||
|
audioStreams: [MediaStream(displayTitle: "English", index: -1)],
|
||||||
|
subtitleStreams: [MediaStream(displayTitle: "None", index: -1)],
|
||||||
|
selectedAudioStreamIndex: -1,
|
||||||
|
selectedSubtitleStreamIndex: -1,
|
||||||
|
subtitlesEnabled: true,
|
||||||
|
autoplayEnabled: false,
|
||||||
|
overlayType: .compact,
|
||||||
|
shouldShowPlayPreviousItem: true,
|
||||||
|
shouldShowPlayNextItem: true,
|
||||||
|
shouldShowAutoPlayNextItem: true)
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
Color.red
|
Color.red
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
|
|
||||||
tvOSVLCOverlay(viewModel: VideoPlayerViewModel(item: BaseItemDto(runTimeTicks: 720 * 10_000_000),
|
tvOSVLCOverlay(viewModel: videoPlayerViewModel)
|
||||||
title: "Glorious Purpose",
|
|
||||||
subtitle: "Loki - S1E1",
|
|
||||||
streamURL: URL(string: "www.apple.com")!,
|
|
||||||
hlsURL: URL(string: "www.apple.com")!,
|
|
||||||
response: PlaybackInfoResponse(),
|
|
||||||
audioStreams: [MediaStream(displayTitle: "English", index: -1)],
|
|
||||||
subtitleStreams: [MediaStream(displayTitle: "None", index: -1)],
|
|
||||||
defaultAudioStreamIndex: -1,
|
|
||||||
defaultSubtitleStreamIndex: -1,
|
|
||||||
playerState: .error,
|
|
||||||
shouldShowGoogleCast: false,
|
|
||||||
shouldShowAirplay: false,
|
|
||||||
subtitlesEnabled: true,
|
|
||||||
sliderPercentage: 0.432,
|
|
||||||
selectedAudioStreamIndex: -1,
|
|
||||||
selectedSubtitleStreamIndex: -1,
|
|
||||||
showAdjacentItems: true,
|
|
||||||
shouldShowAutoPlayNextItem: true,
|
|
||||||
autoPlayNextItem: true))
|
|
||||||
}
|
}
|
||||||
.previewInterfaceOrientation(.landscapeLeft)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,7 +95,7 @@ struct VLCPlayerOverlayView: View {
|
||||||
if viewModel.autoplayEnabled {
|
if viewModel.autoplayEnabled {
|
||||||
Image(systemName: "play.circle.fill")
|
Image(systemName: "play.circle.fill")
|
||||||
} else {
|
} else {
|
||||||
Image(systemName: "play.circle")
|
Image(systemName: "stop.circle")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -266,7 +266,7 @@ class VLCPlayerViewController: UIViewController {
|
||||||
view.addSubview(newJumpForwardImageView)
|
view.addSubview(newJumpForwardImageView)
|
||||||
|
|
||||||
NSLayoutConstraint.activate([
|
NSLayoutConstraint.activate([
|
||||||
newJumpForwardImageView.leftAnchor.constraint(equalTo: view.rightAnchor, constant: -150),
|
newJumpForwardImageView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -150),
|
||||||
newJumpForwardImageView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
|
newJumpForwardImageView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ final class VideoPlayerCoordinator: NavigationCoordinatable {
|
||||||
|
|
||||||
@Root var start = makeStart
|
@Root var start = makeStart
|
||||||
|
|
||||||
@Default(.nativeVideoPlayer) var nativeVideoPlayer
|
|
||||||
let viewModel: VideoPlayerViewModel
|
let viewModel: VideoPlayerViewModel
|
||||||
|
|
||||||
init(viewModel: VideoPlayerViewModel) {
|
init(viewModel: VideoPlayerViewModel) {
|
||||||
|
@ -27,9 +26,6 @@ final class VideoPlayerCoordinator: NavigationCoordinatable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder func makeStart() -> some View {
|
@ViewBuilder func makeStart() -> some View {
|
||||||
// NativePlayerView(viewModel: viewModel)
|
|
||||||
// .navigationBarHidden(true)
|
|
||||||
// .ignoresSafeArea()
|
|
||||||
VLCPlayerView(viewModel: viewModel)
|
VLCPlayerView(viewModel: viewModel)
|
||||||
.navigationBarHidden(true)
|
.navigationBarHidden(true)
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
|
|
Loading…
Reference in New Issue