confirm close tfor tvos
This commit is contained in:
parent
2d7cad8cec
commit
25b4e382f2
|
@ -19,6 +19,7 @@ struct SettingsView: View {
|
|||
@Default(.videoPlayerJumpForward) var jumpForwardLength
|
||||
@Default(.videoPlayerJumpBackward) var jumpBackwardLength
|
||||
@Default(.downActionShowsMenu) var downActionShowsMenu
|
||||
@Default(.confirmClose) var confirmClose
|
||||
|
||||
var body: some View {
|
||||
GeometryReader { reader in
|
||||
|
@ -76,6 +77,8 @@ struct SettingsView: View {
|
|||
|
||||
Toggle("Press Down for Menu", isOn: $downActionShowsMenu)
|
||||
|
||||
Toggle("Confirm Close", isOn: $confirmClose)
|
||||
|
||||
Button {
|
||||
settingsRouter.route(to: \.overlaySettings)
|
||||
} label: {
|
||||
|
|
|
@ -29,6 +29,7 @@ class VLCPlayerViewController: UIViewController {
|
|||
private var lastProgressReportTicks: Int64 = 0
|
||||
private var viewModelListeners = Set<AnyCancellable>()
|
||||
private var overlayDismissTimer: Timer?
|
||||
private var confirmCloseOverlayDismissTimer: Timer?
|
||||
|
||||
private var currentPlayerTicks: Int64 {
|
||||
return Int64(vlcMediaPlayer.time.intValue) * 100_000
|
||||
|
@ -42,11 +43,16 @@ class VLCPlayerViewController: UIViewController {
|
|||
return currentOverlayContentHostingController?.view.alpha ?? 0 > 0
|
||||
}
|
||||
|
||||
private var displayingConfirmClose: Bool {
|
||||
return currentConfirmCloseHostingController?.view.alpha ?? 0 > 0
|
||||
}
|
||||
|
||||
private lazy var videoContentView = makeVideoContentView()
|
||||
private lazy var jumpBackwardOverlayView = makeJumpBackwardOverlayView()
|
||||
private lazy var jumpForwardOverlayView = makeJumpForwardOverlayView()
|
||||
private var currentOverlayHostingController: UIHostingController<tvOSVLCOverlay>?
|
||||
private var currentOverlayContentHostingController: UIHostingController<SmallMediaStreamSelectionView>?
|
||||
private var currentConfirmCloseHostingController: UIHostingController<ConfirmCloseOverlay>?
|
||||
|
||||
// MARK: init
|
||||
|
||||
|
@ -192,10 +198,16 @@ class VLCPlayerViewController: UIViewController {
|
|||
switch(buttonPress) {
|
||||
case .menu: () // Captured by other gesture
|
||||
case .playPause:
|
||||
hideConfirmCloseOverlay()
|
||||
|
||||
didSelectMain()
|
||||
case .select:
|
||||
hideConfirmCloseOverlay()
|
||||
|
||||
didGenerallyTap()
|
||||
case .upArrow:
|
||||
hideConfirmCloseOverlay()
|
||||
|
||||
if displayingContentOverlay {
|
||||
hideOverlayContent()
|
||||
|
||||
|
@ -203,16 +215,22 @@ class VLCPlayerViewController: UIViewController {
|
|||
restartOverlayDismissTimer()
|
||||
}
|
||||
case .downArrow:
|
||||
hideConfirmCloseOverlay()
|
||||
|
||||
if Defaults[.downActionShowsMenu] {
|
||||
if !displayingContentOverlay {
|
||||
didSelectMenu()
|
||||
}
|
||||
}
|
||||
case .leftArrow:
|
||||
hideConfirmCloseOverlay()
|
||||
|
||||
if !displayingContentOverlay {
|
||||
didSelectBackward()
|
||||
}
|
||||
case .rightArrow:
|
||||
hideConfirmCloseOverlay()
|
||||
|
||||
if !displayingContentOverlay {
|
||||
didSelectForward()
|
||||
}
|
||||
|
@ -229,6 +247,7 @@ class VLCPlayerViewController: UIViewController {
|
|||
view.addGestureRecognizer(pressRecognizer)
|
||||
}
|
||||
|
||||
// MARK: didPressMenu
|
||||
@objc private func didPressMenu() {
|
||||
if displayingOverlay {
|
||||
hideOverlay()
|
||||
|
@ -237,6 +256,11 @@ class VLCPlayerViewController: UIViewController {
|
|||
|
||||
showOverlay()
|
||||
restartOverlayDismissTimer()
|
||||
} else if viewModel.confirmClose && !displayingConfirmClose {
|
||||
|
||||
showConfirmCloseOverlay()
|
||||
restartConfirmCloseDismissTimer()
|
||||
|
||||
} else {
|
||||
vlcMediaPlayer.pause()
|
||||
|
||||
|
@ -255,7 +279,7 @@ class VLCPlayerViewController: UIViewController {
|
|||
|
||||
// TODO: Look at injecting viewModel into the environment so it updates the current overlay
|
||||
|
||||
// Overlay
|
||||
// Main overlay
|
||||
if let currentOverlayHostingController = currentOverlayHostingController {
|
||||
// UX fade-out
|
||||
UIView.animate(withDuration: 0.5) {
|
||||
|
@ -295,7 +319,7 @@ class VLCPlayerViewController: UIViewController {
|
|||
|
||||
self.currentOverlayHostingController = newOverlayHostingController
|
||||
|
||||
// OverlayContent
|
||||
// Media Stream selection
|
||||
if let currentOverlayContentHostingController = currentOverlayContentHostingController {
|
||||
currentOverlayContentHostingController.view.isHidden = true
|
||||
|
||||
|
@ -303,26 +327,9 @@ class VLCPlayerViewController: UIViewController {
|
|||
currentOverlayContentHostingController.removeFromParent()
|
||||
}
|
||||
|
||||
// let newSmallMenuOverlayView = SmallMediaStreamSelectionView(viewModel: viewModel,
|
||||
// title: "Subtitles",
|
||||
// items: viewModel.subtitleStreams) { selectedMediaStream in
|
||||
// self.didSelectSubtitleStream(index: selectedMediaStream.index ?? -1)
|
||||
// }
|
||||
// let newSmallMenuOverlayView = SmallMediaStreamSelectionView(viewModel: viewModel,
|
||||
// items: viewModel.subtitleStreams,
|
||||
// selectedIndex: viewModel.selectedSubtitleStreamIndex,
|
||||
// title: "Subtitles") { selectedMediaStream in
|
||||
// DispatchQueue.main.async {
|
||||
// self.viewModel.selectedSubtitleStreamIndex = selectedMediaStream.index ?? -1
|
||||
// self.didSelectSubtitleStream(index: selectedMediaStream.index ?? -1)
|
||||
// }
|
||||
// }
|
||||
|
||||
let newSmallMenuOverlayView = SmallMediaStreamSelectionView(viewModel: viewModel)
|
||||
|
||||
let newOverlayContentHostingController = UIHostingController(rootView: newSmallMenuOverlayView)
|
||||
// let newOverlayContentView = tvOSOverlayContentView(viewModel: viewModel)
|
||||
// let newOverlayContentHostingController = UIHostingController(rootView: newOverlayContentView)
|
||||
|
||||
newOverlayContentHostingController.view.translatesAutoresizingMaskIntoConstraints = false
|
||||
newOverlayContentHostingController.view.backgroundColor = UIColor.clear
|
||||
|
@ -341,6 +348,36 @@ class VLCPlayerViewController: UIViewController {
|
|||
])
|
||||
|
||||
self.currentOverlayContentHostingController = newOverlayContentHostingController
|
||||
|
||||
// Confirm close
|
||||
if let currentConfirmCloseHostingController = currentConfirmCloseHostingController {
|
||||
currentConfirmCloseHostingController.view.isHidden = true
|
||||
|
||||
currentConfirmCloseHostingController.view.removeFromSuperview()
|
||||
currentConfirmCloseHostingController.removeFromParent()
|
||||
}
|
||||
|
||||
let newConfirmCloseOverlay = ConfirmCloseOverlay()
|
||||
|
||||
let newConfirmCloseHostingController = UIHostingController(rootView: newConfirmCloseOverlay)
|
||||
|
||||
newConfirmCloseHostingController.view.translatesAutoresizingMaskIntoConstraints = false
|
||||
newConfirmCloseHostingController.view.backgroundColor = UIColor.clear
|
||||
|
||||
newConfirmCloseHostingController.view.alpha = 0
|
||||
|
||||
addChild(newConfirmCloseHostingController)
|
||||
view.addSubview(newConfirmCloseHostingController.view)
|
||||
newConfirmCloseHostingController.didMove(toParent: self)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
newConfirmCloseHostingController.view.topAnchor.constraint(equalTo: videoContentView.topAnchor),
|
||||
newConfirmCloseHostingController.view.bottomAnchor.constraint(equalTo: videoContentView.bottomAnchor),
|
||||
newConfirmCloseHostingController.view.leftAnchor.constraint(equalTo: videoContentView.leftAnchor),
|
||||
newConfirmCloseHostingController.view.rightAnchor.constraint(equalTo: videoContentView.rightAnchor)
|
||||
])
|
||||
|
||||
self.currentConfirmCloseHostingController = newConfirmCloseHostingController
|
||||
|
||||
// There is a behavior when setting this that the navigation bar
|
||||
// on the current navigation controller pops up, re-hide it
|
||||
|
@ -543,6 +580,26 @@ extension VLCPlayerViewController {
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: Show/Hide Confirm close
|
||||
extension VLCPlayerViewController {
|
||||
|
||||
private func showConfirmCloseOverlay() {
|
||||
guard let currentConfirmCloseHostingController = currentConfirmCloseHostingController else { return }
|
||||
|
||||
UIView.animate(withDuration: 0.2) {
|
||||
currentConfirmCloseHostingController.view.alpha = 1
|
||||
}
|
||||
}
|
||||
|
||||
private func hideConfirmCloseOverlay() {
|
||||
guard let currentConfirmCloseHostingController = currentConfirmCloseHostingController else { return }
|
||||
|
||||
UIView.animate(withDuration: 0.5) {
|
||||
currentConfirmCloseHostingController.view.alpha = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: OverlayTimer
|
||||
extension VLCPlayerViewController {
|
||||
|
||||
|
@ -552,11 +609,28 @@ extension VLCPlayerViewController {
|
|||
}
|
||||
|
||||
@objc private func dismissTimerFired() {
|
||||
self.hideOverlay()
|
||||
hideOverlay()
|
||||
}
|
||||
|
||||
private func stopOverlayDismissTimer() {
|
||||
self.overlayDismissTimer?.invalidate()
|
||||
overlayDismissTimer?.invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Confirm Close Overlay Timer
|
||||
extension VLCPlayerViewController {
|
||||
|
||||
private func restartConfirmCloseDismissTimer() {
|
||||
self.confirmCloseOverlayDismissTimer?.invalidate()
|
||||
self.confirmCloseOverlayDismissTimer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(confirmCloseTimerFired), userInfo: nil, repeats: false)
|
||||
}
|
||||
|
||||
@objc private func confirmCloseTimerFired() {
|
||||
hideConfirmCloseOverlay()
|
||||
}
|
||||
|
||||
private func stopConfirmCloseDismissTimer() {
|
||||
confirmCloseOverlayDismissTimer?.invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
/*
|
||||
* SwiftFin is subject to the terms of the Mozilla Public
|
||||
* License, v2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright 2021 Aiden Vigue & Jellyfin Contributors
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ConfirmCloseOverlay: View {
|
||||
var body: some View {
|
||||
VStack {
|
||||
HStack {
|
||||
Image(systemName: "chevron.left.circle.fill")
|
||||
.font(.system(size: 96))
|
||||
.padding(3)
|
||||
.background(Color.black.opacity(0.4).mask(Circle()))
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
|
||||
struct ConfirmCloseOverlay_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ZStack {
|
||||
Color.red.ignoresSafeArea()
|
||||
|
||||
ConfirmCloseOverlay()
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -385,6 +385,7 @@
|
|||
E1E5D54C2783E27200692DFE /* ExperimentalSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E5D54B2783E27200692DFE /* ExperimentalSettingsView.swift */; };
|
||||
E1E5D54F2783E67100692DFE /* OverlaySettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E5D54E2783E67100692DFE /* OverlaySettingsView.swift */; };
|
||||
E1E5D5512783E67700692DFE /* ExperimentalSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E5D5502783E67700692DFE /* ExperimentalSettingsView.swift */; };
|
||||
E1E5D553278419D900692DFE /* ConfirmCloseOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E5D552278419D900692DFE /* ConfirmCloseOverlay.swift */; };
|
||||
E1F0204E26CCCA74001C1C3B /* VideoPlayerJumpLength.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1F0204D26CCCA74001C1C3B /* VideoPlayerJumpLength.swift */; };
|
||||
E1F0204F26CCCA74001C1C3B /* VideoPlayerJumpLength.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1F0204D26CCCA74001C1C3B /* VideoPlayerJumpLength.swift */; };
|
||||
E1FA2F7427818A8800B4C270 /* SmallMenuOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1FA2F7327818A8800B4C270 /* SmallMenuOverlay.swift */; };
|
||||
|
@ -670,6 +671,7 @@
|
|||
E1E5D54B2783E27200692DFE /* ExperimentalSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExperimentalSettingsView.swift; sourceTree = "<group>"; };
|
||||
E1E5D54E2783E67100692DFE /* OverlaySettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverlaySettingsView.swift; sourceTree = "<group>"; };
|
||||
E1E5D5502783E67700692DFE /* ExperimentalSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExperimentalSettingsView.swift; sourceTree = "<group>"; };
|
||||
E1E5D552278419D900692DFE /* ConfirmCloseOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmCloseOverlay.swift; sourceTree = "<group>"; };
|
||||
E1F0204D26CCCA74001C1C3B /* VideoPlayerJumpLength.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayerJumpLength.swift; sourceTree = "<group>"; };
|
||||
E1FA2F7327818A8800B4C270 /* SmallMenuOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmallMenuOverlay.swift; sourceTree = "<group>"; };
|
||||
E1FCD08726C35A0D007C8DCF /* NetworkError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkError.swift; sourceTree = "<group>"; };
|
||||
|
@ -1332,6 +1334,7 @@
|
|||
E17885A7278130690094FBCF /* tvOSOverlay */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E1E5D552278419D900692DFE /* ConfirmCloseOverlay.swift */,
|
||||
E1FA2F7327818A8800B4C270 /* SmallMenuOverlay.swift */,
|
||||
E178859F2780F55C0094FBCF /* tvOSVLCOverlay.swift */,
|
||||
);
|
||||
|
@ -1983,6 +1986,7 @@
|
|||
53ABFDEE26799DCD00886593 /* ImageView.swift in Sources */,
|
||||
62E632E4267D3BA60063E547 /* MovieItemViewModel.swift in Sources */,
|
||||
53649AB2269D019100A2D8B7 /* LogManager.swift in Sources */,
|
||||
E1E5D553278419D900692DFE /* ConfirmCloseOverlay.swift in Sources */,
|
||||
E13DD3D6271693CD009D4DAF /* SwiftfinStoreDefaults.swift in Sources */,
|
||||
E193D549271941CC00900D82 /* UserSignInView.swift in Sources */,
|
||||
535870AA2669D8AE00D05A09 /* BlurHashDecode.swift in Sources */,
|
||||
|
|
|
@ -59,4 +59,5 @@ extension Defaults.Keys {
|
|||
|
||||
// tvos specific
|
||||
static let downActionShowsMenu = Key<Bool>("downActionShowsMenu", default: true, suite: SwiftfinStore.Defaults.generalSuite)
|
||||
static let confirmClose = Key<Bool>("confirmClose", default: false, suite: SwiftfinStore.Defaults.generalSuite)
|
||||
}
|
||||
|
|
|
@ -92,6 +92,9 @@ final class VideoPlayerViewModel: ViewModel {
|
|||
// MARK: Experimental
|
||||
let syncSubtitleStateWithAdjacent: Bool
|
||||
|
||||
// MARK: tvOS
|
||||
let confirmClose: Bool
|
||||
|
||||
// Full response kept for convenience
|
||||
let response: PlaybackInfoResponse
|
||||
|
||||
|
@ -161,6 +164,8 @@ final class VideoPlayerViewModel: ViewModel {
|
|||
|
||||
self.syncSubtitleStateWithAdjacent = Defaults[.Experimental.syncSubtitleStateWithAdjacent]
|
||||
|
||||
self.confirmClose = Defaults[.confirmClose]
|
||||
|
||||
super.init()
|
||||
|
||||
self.sliderPercentage = (item.userData?.playedPercentage ?? 0) / 100
|
||||
|
@ -355,7 +360,7 @@ extension VideoPlayerViewModel {
|
|||
.sink { completion in
|
||||
self.handleAPIRequestError(completion: completion)
|
||||
} receiveValue: { _ in
|
||||
print("Playback start report sent!")
|
||||
LogManager.shared.log.debug("Start report sent for item: \(self.item.id ?? "No ID")")
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
@ -391,7 +396,7 @@ extension VideoPlayerViewModel {
|
|||
.sink { completion in
|
||||
self.handleAPIRequestError(completion: completion)
|
||||
} receiveValue: { _ in
|
||||
print("Pause report sent!")
|
||||
LogManager.shared.log.debug("Pause report sent for item: \(self.item.id ?? "No ID")")
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
@ -434,9 +439,11 @@ extension VideoPlayerViewModel {
|
|||
.sink { completion in
|
||||
self.handleAPIRequestError(completion: completion)
|
||||
} receiveValue: { _ in
|
||||
print("Playback progress sent!")
|
||||
LogManager.shared.log.debug("Playback progress sent for item: \(self.item.id ?? "No ID")")
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
self.lastProgressReport = nil
|
||||
}
|
||||
|
||||
// MARK: sendStopReport
|
||||
|
@ -458,7 +465,7 @@ extension VideoPlayerViewModel {
|
|||
.sink { completion in
|
||||
self.handleAPIRequestError(completion: completion)
|
||||
} receiveValue: { _ in
|
||||
print("Playback stop report sent!")
|
||||
LogManager.shared.log.debug("Stop report sent for item: \(self.item.id ?? "No ID")")
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue