From a5fabe3224a02cf6e98718d415b875e7fab34b44 Mon Sep 17 00:00:00 2001 From: PangMo5 Date: Sat, 29 Jan 2022 06:17:58 +0900 Subject: [PATCH] add keyCommands to VLCPlayerViewController --- Shared/Generated/Strings.swift | 12 ++ Shared/Objects/PlaybackSpeed.swift | 42 +++++++ .../VideoPlayer/VLCPlayerViewController.swift | 106 ++++++++++++------ Translations/en.lproj/Localizable.strings | Bin 12028 -> 12384 bytes 4 files changed, 123 insertions(+), 37 deletions(-) diff --git a/Shared/Generated/Strings.swift b/Shared/Generated/Strings.swift index 854d717b7..1ae16f2d0 100644 --- a/Shared/Generated/Strings.swift +++ b/Shared/Generated/Strings.swift @@ -54,6 +54,8 @@ internal enum L10n { internal static var chapters: String { return L10n.tr("Localizable", "chapters") } /// Cinematic Views internal static var cinematicViews: String { return L10n.tr("Localizable", "cinematicViews") } + /// Close + internal static var close: String { return L10n.tr("Localizable", "close") } /// Closed Captions internal static var closedCaptions: String { return L10n.tr("Localizable", "closedCaptions") } /// Compact @@ -122,8 +124,12 @@ internal enum L10n { internal static var information: String { return L10n.tr("Localizable", "information") } /// Items internal static var items: String { return L10n.tr("Localizable", "items") } + /// Jump Backward + internal static var jumpBackward: String { return L10n.tr("Localizable", "jumpBackward") } /// Jump Backward Length internal static var jumpBackwardLength: String { return L10n.tr("Localizable", "jumpBackwardLength") } + /// Jump Forward + internal static var jumpForward: String { return L10n.tr("Localizable", "jumpForward") } /// Jump Forward Length internal static var jumpForwardLength: String { return L10n.tr("Localizable", "jumpForwardLength") } /// Jump Gestures Enabled @@ -176,6 +182,8 @@ internal enum L10n { internal static var networkTimedOut: String { return L10n.tr("Localizable", "networkTimedOut") } /// Next internal static var next: String { return L10n.tr("Localizable", "next") } + /// Next Item + internal static var nextItem: String { return L10n.tr("Localizable", "nextItem") } /// Next Up internal static var nextUp: String { return L10n.tr("Localizable", "nextUp") } /// No Cast devices found.. @@ -226,6 +234,8 @@ internal enum L10n { internal static var password: String { return L10n.tr("Localizable", "password") } /// Play internal static var play: String { return L10n.tr("Localizable", "play") } + /// Play / Pause + internal static var playAndPause: String { return L10n.tr("Localizable", "playAndPause") } /// Playback settings internal static var playbackSettings: String { return L10n.tr("Localizable", "playbackSettings") } /// Playback Speed @@ -242,6 +252,8 @@ internal enum L10n { internal static var present: String { return L10n.tr("Localizable", "present") } /// Press Down for Menu internal static var pressDownForMenu: String { return L10n.tr("Localizable", "pressDownForMenu") } + /// Previous Item + internal static var previousItem: String { return L10n.tr("Localizable", "previousItem") } /// Programs internal static var programs: String { return L10n.tr("Localizable", "programs") } /// Rated diff --git a/Shared/Objects/PlaybackSpeed.swift b/Shared/Objects/PlaybackSpeed.swift index 989217239..35624b721 100644 --- a/Shared/Objects/PlaybackSpeed.swift +++ b/Shared/Objects/PlaybackSpeed.swift @@ -38,4 +38,46 @@ enum PlaybackSpeed: Double, CaseIterable { return "2x" } } + + var previous: PlaybackSpeed? { + switch self { + case .quarter: + return nil + case .half: + return .quarter + case .threeQuarter: + return .half + case .one: + return .threeQuarter + case .oneQuarter: + return .one + case .oneHalf: + return .oneQuarter + case .oneThreeQuarter: + return .oneHalf + case .two: + return .oneThreeQuarter + } + } + + var next: PlaybackSpeed? { + switch self { + case .quarter: + return .half + case .half: + return .threeQuarter + case .threeQuarter: + return .one + case .one: + return .oneQuarter + case .oneQuarter: + return .oneHalf + case .oneHalf: + return .oneThreeQuarter + case .oneThreeQuarter: + return .two + case .two: + return nil + } + } } diff --git a/Swiftfin/Views/VideoPlayer/VLCPlayerViewController.swift b/Swiftfin/Views/VideoPlayer/VLCPlayerViewController.swift index ea58aaccf..61ef19340 100644 --- a/Swiftfin/Views/VideoPlayer/VLCPlayerViewController.swift +++ b/Swiftfin/Views/VideoPlayer/VLCPlayerViewController.swift @@ -19,7 +19,6 @@ import UIKit // TODO: Look at making the VLC player layer a view class VLCPlayerViewController: UIViewController { - // MARK: variables private var viewModel: VideoPlayerViewModel @@ -50,10 +49,36 @@ class VLCPlayerViewController: UIViewController { private var currentJumpBackwardOverlayView: UIImageView? private var currentJumpForwardOverlayView: UIImageView? + override var keyCommands: [UIKeyCommand]? { + var commands = [ + UIKeyCommand(title: L10n.playAndPause, action: #selector(didSelectMain), input: " "), + UIKeyCommand(title: L10n.jumpForward, action: #selector(didSelectForward), input: UIKeyCommand.inputRightArrow), + UIKeyCommand(title: L10n.jumpBackward, action: #selector(didSelectBackward), input: UIKeyCommand.inputLeftArrow), + UIKeyCommand(title: L10n.nextItem, action: #selector(didSelectPlayNextItem), input: UIKeyCommand.inputRightArrow, + modifierFlags: .command), + UIKeyCommand(title: L10n.previousItem, action: #selector(didSelectPlayPreviousItem), input: UIKeyCommand.inputLeftArrow, + modifierFlags: .command), + UIKeyCommand(title: L10n.close, action: #selector(didSelectClose), input: UIKeyCommand.inputEscape), + ] + if let previous = viewModel.playbackSpeed.previous { + commands.append(.init(title: "\(L10n.playbackSpeed) \(previous.displayTitle)", + action: #selector(didSelectPreviousPlaybackSpeed), input: "[", modifierFlags: .command)) + } + if let next = viewModel.playbackSpeed.next { + commands.append(.init(title: "\(L10n.playbackSpeed) \(next.displayTitle)", action: #selector(didSelectNextPlaybackSpeed), + input: "]", modifierFlags: .command)) + } + if viewModel.playbackSpeed != .one { + commands.append(.init(title: "\(L10n.playbackSpeed) \(PlaybackSpeed.one.displayTitle)", + action: #selector(didSelectNormalPlaybackSpeed), input: "\\", modifierFlags: .command)) + } + commands.forEach { $0.wantsPriorityOverSystemBehavior = true } + return commands + } + // MARK: init init(viewModel: VideoPlayerViewModel) { - self.viewModel = viewModel self.vlcMediaPlayer = VLCMediaPlayer() @@ -190,17 +215,17 @@ class VLCPlayerViewController: UIViewController { @objc private func didTap() { - self.didGenerallyTap() + didGenerallyTap() } @objc private func didRightSwipe() { - self.didSelectForward() + didSelectForward() } @objc private func didLeftSwipe() { - self.didSelectBackward() + didSelectBackward() } @objc @@ -208,10 +233,10 @@ class VLCPlayerViewController: UIViewController { if gestureRecognizer.state == .began || gestureRecognizer.state == .changed { pinchScale = gestureRecognizer.scale } else { - if pinchScale > 1 && !isScreenFilled { + if pinchScale > 1, !isScreenFilled { isScreenFilled.toggle() fillScreen() - } else if pinchScale < 1 && isScreenFilled { + } else if pinchScale < 1, isScreenFilled { isScreenFilled.toggle() shrinkScreen() } @@ -221,7 +246,6 @@ class VLCPlayerViewController: UIViewController { // MARK: setupOverlayHostingController private func setupOverlayHostingController(viewModel: VideoPlayerViewModel) { - // TODO: Look at injecting viewModel into the environment so it updates the current overlay if let currentOverlayHostingController = currentOverlayHostingController { // UX fade-out @@ -260,7 +284,7 @@ class VLCPlayerViewController: UIViewController { newOverlayHostingController.view.alpha = 1 } - self.currentOverlayHostingController = newOverlayHostingController + currentOverlayHostingController = newOverlayHostingController if let currentChapterOverlayHostingController = currentChapterOverlayHostingController { UIView.animate(withDuration: 0.5) { @@ -292,14 +316,13 @@ class VLCPlayerViewController: UIViewController { newChapterOverlayHostingController.view.rightAnchor.constraint(equalTo: videoContentView.rightAnchor), ]) - self.currentChapterOverlayHostingController = newChapterOverlayHostingController + currentChapterOverlayHostingController = newChapterOverlayHostingController // There is a weird behavior when after setting the new overlays that the navigation bar pops up, re-hide it - self.navigationController?.isNavigationBarHidden = true + navigationController?.isNavigationBarHidden = true } private func refreshJumpBackwardOverlayView(with jumpBackwardLength: VideoPlayerJumpLength) { - if let currentJumpBackwardOverlayView = currentJumpBackwardOverlayView { currentJumpBackwardOverlayView.removeFromSuperview() } @@ -324,7 +347,6 @@ class VLCPlayerViewController: UIViewController { } private func refreshJumpForwardOverlayView(with jumpForwardLength: VideoPlayerJumpLength) { - if let currentJumpForwardOverlayView = currentJumpForwardOverlayView { currentJumpForwardOverlayView.removeFromSuperview() } @@ -352,13 +374,11 @@ class VLCPlayerViewController: UIViewController { // MARK: setupMediaPlayer extension VLCPlayerViewController { - /// Main function that handles setting up the media player with the current VideoPlayerViewModel /// and also takes the role of setting the 'viewModel' property with the given viewModel /// /// Use case for this is setting new media within the same VLCPlayerViewController func setupMediaPlayer(newViewModel: VideoPlayerViewModel) { - // remove old player if vlcMediaPlayer.media != nil { @@ -454,7 +474,6 @@ extension VLCPlayerViewController { // MARK: setupViewModelListeners private func setupViewModelListeners(viewModel: VideoPlayerViewModel) { - viewModel.$playbackSpeed.sink { newSpeed in self.vlcMediaPlayer.rate = Float(newSpeed.rawValue) }.store(in: &viewModelListeners) @@ -508,7 +527,6 @@ extension VLCPlayerViewController { // MARK: Show/Hide Overlay extension VLCPlayerViewController { - private func showOverlay() { guard let overlayHostingController = currentOverlayHostingController else { return } @@ -545,7 +563,6 @@ extension VLCPlayerViewController { // MARK: Show/Hide Jump extension VLCPlayerViewController { - private func flashJumpBackwardOverlay() { guard !displayingOverlay, let currentJumpBackwardOverlayView = currentJumpBackwardOverlayView else { return } @@ -590,7 +607,6 @@ extension VLCPlayerViewController { // MARK: Hide/Show Chapters extension VLCPlayerViewController { - private func showChaptersOverlay() { guard let overlayHostingController = currentChapterOverlayHostingController else { return } @@ -615,40 +631,37 @@ extension VLCPlayerViewController { // MARK: OverlayTimer extension VLCPlayerViewController { - private func restartOverlayDismissTimer(interval: Double = 3) { - self.overlayDismissTimer?.invalidate() - self.overlayDismissTimer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(dismissTimerFired), - userInfo: nil, repeats: false) + overlayDismissTimer?.invalidate() + overlayDismissTimer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(dismissTimerFired), + userInfo: nil, repeats: false) } @objc private func dismissTimerFired() { - self.hideOverlay() + hideOverlay() } private func stopOverlayDismissTimer() { - self.overlayDismissTimer?.invalidate() + overlayDismissTimer?.invalidate() } } // MARK: VLCMediaPlayerDelegate extension VLCPlayerViewController: VLCMediaPlayerDelegate { - // MARK: mediaPlayerStateChanged func mediaPlayerStateChanged(_ aNotification: Notification!) { - // Don't show buffering if paused, usually here while scrubbing - if vlcMediaPlayer.state == .buffering && viewModel.playerState == .paused { + if vlcMediaPlayer.state == .buffering, viewModel.playerState == .paused { return } viewModel.playerState = vlcMediaPlayer.state if vlcMediaPlayer.state == VLCMediaPlayerState.ended { - if viewModel.autoplayEnabled && viewModel.nextItemVideoPlayerViewModel != nil { + if viewModel.autoplayEnabled, viewModel.nextItemVideoPlayerViewModel != nil { didSelectPlayNextItem() } else { didSelectClose() @@ -659,7 +672,6 @@ extension VLCPlayerViewController: VLCMediaPlayerDelegate { // MARK: mediaPlayerTimeChanged func mediaPlayerTimeChanged(_ aNotification: Notification!) { - if !viewModel.sliderIsScrubbing { viewModel.sliderPercentage = Double(vlcMediaPlayer.position) } @@ -671,8 +683,8 @@ extension VLCPlayerViewController: VLCMediaPlayerDelegate { } // 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) } @@ -696,7 +708,6 @@ extension VLCPlayerViewController: VLCMediaPlayerDelegate { // MARK: PlayerOverlayDelegate and more extension VLCPlayerViewController: PlayerOverlayDelegate { - func didSelectAudioStream(index: Int) { vlcMediaPlayer.currentAudioTrackIndex = Int32(index) @@ -715,6 +726,7 @@ extension VLCPlayerViewController: PlayerOverlayDelegate { lastProgressReportTicks = currentPlayerTicks } + @objc func didSelectClose() { vlcMediaPlayer.stop() @@ -741,8 +753,8 @@ extension VLCPlayerViewController: PlayerOverlayDelegate { restartOverlayDismissTimer() } + @objc func didSelectBackward() { - flashJumpBackwardOverlay() vlcMediaPlayer.jumpBackward(viewModel.jumpBackwardLength.rawValue) @@ -756,8 +768,8 @@ extension VLCPlayerViewController: PlayerOverlayDelegate { lastProgressReportTicks = currentPlayerTicks } + @objc func didSelectForward() { - flashJumpFowardOverlay() vlcMediaPlayer.jumpForward(viewModel.jumpForwardLength.rawValue) @@ -771,8 +783,8 @@ extension VLCPlayerViewController: PlayerOverlayDelegate { lastProgressReportTicks = currentPlayerTicks } + @objc func didSelectMain() { - switch viewModel.playerState { case .buffering: vlcMediaPlayer.play() @@ -809,6 +821,7 @@ extension VLCPlayerViewController: PlayerOverlayDelegate { lastProgressReportTicks = currentPlayerTicks } + @objc func didSelectPlayPreviousItem() { if let previousItemVideoPlayerViewModel = viewModel.previousItemVideoPlayerViewModel { setupMediaPlayer(newViewModel: previousItemVideoPlayerViewModel) @@ -816,6 +829,7 @@ extension VLCPlayerViewController: PlayerOverlayDelegate { } } + @objc func didSelectPlayNextItem() { if let nextItemVideoPlayerViewModel = viewModel.nextItemVideoPlayerViewModel { setupMediaPlayer(newViewModel: nextItemVideoPlayerViewModel) @@ -823,6 +837,25 @@ extension VLCPlayerViewController: PlayerOverlayDelegate { } } + @objc + func didSelectPreviousPlaybackSpeed() { + if let previousPlaybackSpeed = viewModel.playbackSpeed.previous { + viewModel.playbackSpeed = previousPlaybackSpeed + } + } + + @objc + func didSelectNextPlaybackSpeed() { + if let nextPlaybackSpeed = viewModel.playbackSpeed.next { + viewModel.playbackSpeed = nextPlaybackSpeed + } + } + + @objc + func didSelectNormalPlaybackSpeed() { + viewModel.playbackSpeed = .one + } + func didSelectChapters() { if displayingChapterOverlay { hideChaptersOverlay() @@ -847,7 +880,6 @@ extension VLCPlayerViewController: PlayerOverlayDelegate { } func didSelectScreenFill() { - isScreenFilled.toggle() if isScreenFilled { diff --git a/Translations/en.lproj/Localizable.strings b/Translations/en.lproj/Localizable.strings index abc407bafe5986dd4a07c08bb684c2aab3e0a87f..a76a6d2e763dc16e522d487d8b6648e9048b9792 100644 GIT binary patch delta 175 zcmewp`ygS%A3aGWh608hhD3%+21kZGh7^VXAiI>Im?3rYLm5$CeFg<2k#;%x$(!Vq zCO?u>0Ma6oPC&KE4A~6jK)ML1SBb%zfeT0`PcGCHb%M47)lsCfjE^R f7bvd4U<<@b41Q1<1td9$Nd=Q@Wt1ncl92-d(a