Handle app phases (auto pause/play on enter background/active phase) (#831)
There's some leftover stuff like adding the `scenePhase` environment variable but I'll get that sometime.
This commit is contained in:
parent
69ddc2f628
commit
667d48b0e9
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// 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 (c) 2023 Jellyfin & Jellyfin Contributors
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ScenePhaseChangeModifier: ViewModifier {
|
||||
|
||||
@Environment(\.scenePhase)
|
||||
private var scenePhase
|
||||
|
||||
let phase: ScenePhase
|
||||
let action: () -> Void
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
content.onChange(of: scenePhase) { newValue in
|
||||
if newValue == phase {
|
||||
action()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -218,4 +218,8 @@ extension View {
|
|||
.ignoresSafeArea()
|
||||
}
|
||||
}
|
||||
|
||||
func onScenePhase(_ phase: ScenePhase, _ action: @escaping () -> Void) -> some View {
|
||||
modifier(ScenePhaseChangeModifier(phase: phase, action: action))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -194,6 +194,11 @@ extension Defaults.Keys {
|
|||
)
|
||||
static let subtitleSize: Key<Int> = .init("subtitleSize", default: 16, suite: .generalSuite)
|
||||
}
|
||||
|
||||
enum Transition {
|
||||
static let pauseOnBackground: Key<Bool> = .init("pauseOnBackground", default: false, suite: .generalSuite)
|
||||
static let playOnActive: Key<Bool> = .init("playOnActive", default: false, suite: .generalSuite)
|
||||
}
|
||||
}
|
||||
|
||||
// Experimental settings
|
||||
|
|
|
@ -21,6 +21,11 @@ struct VideoPlayerSettingsView: View {
|
|||
@Default(.VideoPlayer.resumeOffset)
|
||||
private var resumeOffset
|
||||
|
||||
@Default(.VideoPlayer.Transition.pauseOnBackground)
|
||||
private var pauseOnBackground
|
||||
@Default(.VideoPlayer.Transition.playOnActive)
|
||||
private var playOnActive
|
||||
|
||||
@EnvironmentObject
|
||||
private var router: VideoPlayerSettingsCoordinator.Router
|
||||
|
||||
|
@ -57,6 +62,12 @@ struct VideoPlayerSettingsView: View {
|
|||
} footer: {
|
||||
Text("Settings only affect some subtitle types")
|
||||
}
|
||||
|
||||
Section {
|
||||
|
||||
Toggle("Pause on background", isOn: $pauseOnBackground)
|
||||
Toggle("Play on active", isOn: $playOnActive)
|
||||
}
|
||||
}
|
||||
.navigationTitle("Video Player")
|
||||
.blurFullScreenCover(isPresented: $isPresentingResumeOffsetStepper) {
|
||||
|
|
|
@ -14,6 +14,9 @@ import SwiftUI
|
|||
|
||||
struct NativeVideoPlayer: View {
|
||||
|
||||
@Environment(\.scenePhase)
|
||||
var scenePhase
|
||||
|
||||
@EnvironmentObject
|
||||
private var router: VideoPlayerCoordinator.Router
|
||||
|
||||
|
|
|
@ -19,6 +19,9 @@ struct VideoPlayer: View {
|
|||
case smallMenu
|
||||
}
|
||||
|
||||
@Environment(\.scenePhase)
|
||||
private var scenePhase
|
||||
|
||||
@EnvironmentObject
|
||||
private var router: VideoPlayerCoordinator.Router
|
||||
|
||||
|
@ -100,6 +103,16 @@ struct VideoPlayer: View {
|
|||
guard !newValue else { return }
|
||||
videoPlayerManager.proxy.setTime(.seconds(currentProgressHandler.scrubbedSeconds))
|
||||
}
|
||||
.onScenePhase(.active) {
|
||||
if Defaults[.VideoPlayer.Transition.playOnActive] {
|
||||
videoPlayerManager.proxy.play()
|
||||
}
|
||||
}
|
||||
.onScenePhase(.background) {
|
||||
if Defaults[.VideoPlayer.Transition.pauseOnBackground] {
|
||||
videoPlayerManager.proxy.pause()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -727,6 +727,8 @@
|
|||
E1FE69A728C29B720021BC93 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1FE69A628C29B720021BC93 /* ProgressBar.swift */; };
|
||||
E1FE69A828C29B720021BC93 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1FE69A628C29B720021BC93 /* ProgressBar.swift */; };
|
||||
E1FE69AA28C29CC20021BC93 /* LandscapePosterProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1FE69A928C29CC20021BC93 /* LandscapePosterProgressBar.swift */; };
|
||||
E43918662AD5C8310045A18C /* ScenePhaseChangeModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = E43918652AD5C8310045A18C /* ScenePhaseChangeModifier.swift */; };
|
||||
E43918672AD5C8310045A18C /* ScenePhaseChangeModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = E43918652AD5C8310045A18C /* ScenePhaseChangeModifier.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
|
@ -1277,6 +1279,7 @@
|
|||
E1FCD09526C47118007C8DCF /* ErrorMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorMessage.swift; sourceTree = "<group>"; };
|
||||
E1FE69A628C29B720021BC93 /* ProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = "<group>"; };
|
||||
E1FE69A928C29CC20021BC93 /* LandscapePosterProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LandscapePosterProgressBar.swift; sourceTree = "<group>"; };
|
||||
E43918652AD5C8310045A18C /* ScenePhaseChangeModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScenePhaseChangeModifier.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -2244,6 +2247,7 @@
|
|||
E19E551E2897326C003CE330 /* BottomEdgeGradientModifier.swift */,
|
||||
E129428428F080B500796AC6 /* OnReceiveNotificationModifier.swift */,
|
||||
E11895A8289383BC0042947B /* ScrollViewOffsetModifier.swift */,
|
||||
E43918652AD5C8310045A18C /* ScenePhaseChangeModifier.swift */,
|
||||
);
|
||||
path = Modifiers;
|
||||
sourceTree = "<group>";
|
||||
|
@ -3173,6 +3177,7 @@
|
|||
E193D53927193F8E00900D82 /* SearchCoordinator.swift in Sources */,
|
||||
C4BE078C272844AF003F4AD1 /* LiveTVChannelsView.swift in Sources */,
|
||||
E148128928C154BF003B8787 /* ItemFilter.swift in Sources */,
|
||||
E43918672AD5C8310045A18C /* ScenePhaseChangeModifier.swift in Sources */,
|
||||
E154966F296CA2EF00C4EF88 /* LogManager.swift in Sources */,
|
||||
E1575E75293E77B5001665B1 /* LibraryViewType.swift in Sources */,
|
||||
E193D53427193F7F00900D82 /* HomeCoordinator.swift in Sources */,
|
||||
|
@ -3513,6 +3518,7 @@
|
|||
E1C8CE7C28FF015000DF5D7B /* TrailingTimestampType.swift in Sources */,
|
||||
E1FE69A728C29B720021BC93 /* ProgressBar.swift in Sources */,
|
||||
E13332912953B91000EE76AB /* DownloadTaskCoordinator.swift in Sources */,
|
||||
E43918662AD5C8310045A18C /* ScenePhaseChangeModifier.swift in Sources */,
|
||||
E1B33ED128EB860A0073B0FD /* LargePlaybackButtons.swift in Sources */,
|
||||
E1549664296CA2EF00C4EF88 /* SwiftfinStore.swift in Sources */,
|
||||
E113133228BDC72000930F75 /* FilterView.swift in Sources */,
|
||||
|
|
|
@ -54,6 +54,11 @@ struct VideoPlayerSettingsView: View {
|
|||
@Default(.VideoPlayer.Overlay.timestampType)
|
||||
private var timestampType
|
||||
|
||||
@Default(.VideoPlayer.Transition.pauseOnBackground)
|
||||
private var pauseOnBackground
|
||||
@Default(.VideoPlayer.Transition.playOnActive)
|
||||
private var playOnActive
|
||||
|
||||
@EnvironmentObject
|
||||
private var router: VideoPlayerSettingsCoordinator.Router
|
||||
|
||||
|
@ -149,6 +154,12 @@ struct VideoPlayerSettingsView: View {
|
|||
|
||||
EnumPicker(title: "Trailing Value", selection: $trailingTimestampType)
|
||||
}
|
||||
|
||||
Section("Transition") {
|
||||
|
||||
Toggle("Pause on background", isOn: $pauseOnBackground)
|
||||
Toggle("Play on active", isOn: $playOnActive)
|
||||
}
|
||||
}
|
||||
.navigationTitle("Video Player")
|
||||
.onChange(of: barActionButtons) { newValue in
|
||||
|
|
|
@ -14,6 +14,9 @@ import SwiftUI
|
|||
|
||||
struct NativeVideoPlayer: View {
|
||||
|
||||
@Environment(\.scenePhase)
|
||||
var scenePhase
|
||||
|
||||
@EnvironmentObject
|
||||
private var router: VideoPlayerCoordinator.Router
|
||||
|
||||
|
|
|
@ -24,6 +24,9 @@ struct VideoPlayer: View {
|
|||
case chapters
|
||||
}
|
||||
|
||||
@Environment(\.scenePhase)
|
||||
private var scenePhase
|
||||
|
||||
class GestureStateHandler {
|
||||
|
||||
var beganPanWithOverlay: Bool = false
|
||||
|
@ -241,6 +244,16 @@ struct VideoPlayer: View {
|
|||
audioOffset = 0
|
||||
subtitleOffset = 0
|
||||
}
|
||||
.onScenePhase(.active) {
|
||||
if Defaults[.VideoPlayer.Transition.playOnActive] {
|
||||
videoPlayerManager.proxy.play()
|
||||
}
|
||||
}
|
||||
.onScenePhase(.background) {
|
||||
if Defaults[.VideoPlayer.Transition.pauseOnBackground] {
|
||||
videoPlayerManager.proxy.pause()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue