Cleanup video player settings (#1084)

This commit is contained in:
Daniel Chick 2024-06-09 12:32:37 -05:00 committed by GitHub
parent 645eb6c516
commit 3128a78548
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 265 additions and 134 deletions

View File

@ -150,6 +150,11 @@
BD0BA22C2AD6503B00306A8D /* OnlineVideoPlayerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD0BA22A2AD6503B00306A8D /* OnlineVideoPlayerManager.swift */; };
BD0BA22E2AD6508C00306A8D /* DownloadVideoPlayerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD0BA22D2AD6508C00306A8D /* DownloadVideoPlayerManager.swift */; };
BD0BA22F2AD6508C00306A8D /* DownloadVideoPlayerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD0BA22D2AD6508C00306A8D /* DownloadVideoPlayerManager.swift */; };
BD3957752C112A330078CEF8 /* ButtonSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD3957742C112A330078CEF8 /* ButtonSection.swift */; };
BD3957772C112AD30078CEF8 /* SliderSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD3957762C112AD30078CEF8 /* SliderSection.swift */; };
BD3957792C113EC40078CEF8 /* SubtitleSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD3957782C113EC40078CEF8 /* SubtitleSection.swift */; };
BD39577C2C113FAA0078CEF8 /* TimestampSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD39577B2C113FAA0078CEF8 /* TimestampSection.swift */; };
BD39577E2C1140810078CEF8 /* TransitionSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD39577D2C1140810078CEF8 /* TransitionSection.swift */; };
C40CD926271F8D1E000FB198 /* ItemTypeLibraryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40CD924271F8D1E000FB198 /* ItemTypeLibraryViewModel.swift */; };
C44FA6E02AACD19C00EDEB56 /* LiveSmallPlaybackButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44FA6DE2AACD19C00EDEB56 /* LiveSmallPlaybackButton.swift */; };
C44FA6E12AACD19C00EDEB56 /* LiveLargePlaybackButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44FA6DF2AACD19C00EDEB56 /* LiveLargePlaybackButtons.swift */; };
@ -1047,6 +1052,11 @@
AE8C3158265D6F90008AA076 /* bitrates.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = bitrates.json; sourceTree = "<group>"; };
BD0BA22A2AD6503B00306A8D /* OnlineVideoPlayerManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnlineVideoPlayerManager.swift; sourceTree = "<group>"; };
BD0BA22D2AD6508C00306A8D /* DownloadVideoPlayerManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadVideoPlayerManager.swift; sourceTree = "<group>"; };
BD3957742C112A330078CEF8 /* ButtonSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonSection.swift; sourceTree = "<group>"; };
BD3957762C112AD30078CEF8 /* SliderSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SliderSection.swift; sourceTree = "<group>"; };
BD3957782C113EC40078CEF8 /* SubtitleSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubtitleSection.swift; sourceTree = "<group>"; };
BD39577B2C113FAA0078CEF8 /* TimestampSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimestampSection.swift; sourceTree = "<group>"; };
BD39577D2C1140810078CEF8 /* TransitionSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransitionSection.swift; sourceTree = "<group>"; };
C40CD924271F8D1E000FB198 /* ItemTypeLibraryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemTypeLibraryViewModel.swift; sourceTree = "<group>"; };
C44FA6DE2AACD19C00EDEB56 /* LiveSmallPlaybackButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LiveSmallPlaybackButton.swift; sourceTree = "<group>"; };
C44FA6DF2AACD19C00EDEB56 /* LiveLargePlaybackButtons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LiveLargePlaybackButtons.swift; sourceTree = "<group>"; };
@ -2194,6 +2204,18 @@
path = VideoPlayerManager;
sourceTree = "<group>";
};
BD39577A2C113F780078CEF8 /* Sections */ = {
isa = PBXGroup;
children = (
BD3957742C112A330078CEF8 /* ButtonSection.swift */,
BD3957762C112AD30078CEF8 /* SliderSection.swift */,
BD3957782C113EC40078CEF8 /* SubtitleSection.swift */,
BD39577B2C113FAA0078CEF8 /* TimestampSection.swift */,
BD39577D2C1140810078CEF8 /* TransitionSection.swift */,
);
path = Sections;
sourceTree = "<group>";
};
C44FA6DD2AACD15300EDEB56 /* PlaybackButtons */ = {
isa = PBXGroup;
children = (
@ -3241,6 +3263,7 @@
isa = PBXGroup;
children = (
E1BDF2E82951490400CC0294 /* ActionButtonSelectorView.swift */,
BD39577A2C113F780078CEF8 /* Sections */,
);
path = Components;
sourceTree = "<group>";
@ -4227,6 +4250,7 @@
E13DD3F227179378009D4DAF /* UserSignInCoordinator.swift in Sources */,
621338932660107500A81A2A /* String.swift in Sources */,
E17AC96F2954EE4B003D2BC2 /* DownloadListViewModel.swift in Sources */,
BD39577C2C113FAA0078CEF8 /* TimestampSection.swift in Sources */,
62C83B08288C6A630004ED0C /* FontPickerView.swift in Sources */,
E122A9132788EAAD0060FA63 /* MediaStream.swift in Sources */,
E1E9017F28DAB15F001B1594 /* BarActionButtons.swift in Sources */,
@ -4290,6 +4314,7 @@
E133328829538D8D00EE76AB /* Files.swift in Sources */,
C44FA6E12AACD19C00EDEB56 /* LiveLargePlaybackButtons.swift in Sources */,
E1401CA02937DFF500E8B599 /* AppIconSelectorView.swift in Sources */,
BD39577E2C1140810078CEF8 /* TransitionSection.swift in Sources */,
E1092F4C29106F9F00163F57 /* GestureAction.swift in Sources */,
E11BDF772B8513B40045C54A /* ItemGenre.swift in Sources */,
E16DEAC228EFCF590058F196 /* EnvironmentValue+Keys.swift in Sources */,
@ -4515,6 +4540,7 @@
BD0BA22B2AD6503B00306A8D /* OnlineVideoPlayerManager.swift in Sources */,
E14EA1672BF70F9C00DE757A /* SquareImageCropView.swift in Sources */,
E1BDF2F529524E6400CC0294 /* PlayNextItemActionButton.swift in Sources */,
BD3957772C112AD30078CEF8 /* SliderSection.swift in Sources */,
E18E01DD288747230022598C /* iPadOSSeriesItemContentView.swift in Sources */,
E14EA1692BF7330A00DE757A /* UserProfileImageViewModel.swift in Sources */,
E18ACA952A15A3E100BB4F35 /* (null) in Sources */,
@ -4557,6 +4583,7 @@
E18CE0B428A22EDA0092E7F1 /* RepeatingTimer.swift in Sources */,
E1D5C39628DF90C100CDBEFB /* Slider.swift in Sources */,
E187A60229AB28F0008387E6 /* RotateContentView.swift in Sources */,
BD3957792C113EC40078CEF8 /* SubtitleSection.swift in Sources */,
091B5A8A2683142E00D78B61 /* ServerDiscovery.swift in Sources */,
E1721FAE28FB801C00762992 /* SmallPlaybackButtons.swift in Sources */,
E1A7B1662B9ADAD300152546 /* ItemTypeLibraryViewModel.swift in Sources */,
@ -4592,6 +4619,7 @@
E11BDF972B865F550045C54A /* ItemTag.swift in Sources */,
E1D4BF8A2719D3D000A11E64 /* AppSettingsCoordinator.swift in Sources */,
E1D37F482B9C648E00343D2B /* MaxHeightText.swift in Sources */,
BD3957752C112A330078CEF8 /* ButtonSection.swift in Sources */,
E1ED91182B95993300802036 /* TitledLibraryParent.swift in Sources */,
E13DD3F92717E961009D4DAF /* SelectUserViewModel.swift in Sources */,
E1194F502BEB1E3000888DB6 /* StoredValues+Temp.swift in Sources */,

View File

@ -23,8 +23,7 @@ struct AboutAppView: View {
.aspectRatio(1, contentMode: .fit)
.frame(height: 150)
// App name, not to be localized
Text("Swiftfin")
Text(verbatim: "Swiftfin")
.fontWeight(.semibold)
.font(.title2)
}

View File

@ -37,6 +37,27 @@ struct ConnectToServerView: View {
private let timer = Timer.publish(every: 12, on: .main, in: .common).autoconnect()
private func handleConnection(_ event: ConnectToServerViewModel.Event) {
switch event {
case let .connected(server):
UIDevice.feedback(.success)
Notifications[.didConnectToServer].post(object: server)
router.popLast()
case let .duplicateServer(server):
UIDevice.feedback(.warning)
duplicateServer = server
isPresentingDuplicateServer = true
case let .error(eventError):
UIDevice.feedback(.error)
error = eventError
isPresentingError = true
isURLFocused = true
}
}
@ViewBuilder
private var connectSection: some View {
Section(L10n.connectToServer) {
@ -126,24 +147,7 @@ struct ConnectToServerView: View {
viewModel.send(.searchForServers)
}
.onReceive(viewModel.events) { event in
switch event {
case let .connected(server):
UIDevice.feedback(.success)
Notifications[.didConnectToServer].post(object: server)
router.popLast()
case let .duplicateServer(server):
UIDevice.feedback(.warning)
duplicateServer = server
isPresentingDuplicateServer = true
case let .error(eventError):
UIDevice.feedback(.error)
error = eventError
isPresentingError = true
isURLFocused = true
}
handleConnection(event)
}
.onReceive(timer) { _ in
guard viewModel.state != .connecting else { return }

View File

@ -0,0 +1,63 @@
//
// 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) 2024 Jellyfin & Jellyfin Contributors
//
import Defaults
import SwiftUI
extension VideoPlayerSettingsView {
struct ButtonSection: View {
@Default(.VideoPlayer.Overlay.playbackButtonType)
private var playbackButtonType
@Default(.VideoPlayer.showJumpButtons)
private var showJumpButtons
@Default(.VideoPlayer.barActionButtons)
private var barActionButtons
@Default(.VideoPlayer.menuActionButtons)
private var menuActionButtons
@Default(.VideoPlayer.autoPlayEnabled)
private var autoPlayEnabled
@EnvironmentObject
private var router: VideoPlayerSettingsCoordinator.Router
var body: some View {
Section(L10n.buttons) {
CaseIterablePicker(L10n.playbackButtons, selection: $playbackButtonType)
Toggle(isOn: $showJumpButtons) {
HStack {
Image(systemName: "goforward")
Text(L10n.jump)
}
}
ChevronButton(L10n.barButtons)
.onSelect {
router.route(to: \.actionButtonSelector, $barActionButtons)
}
ChevronButton(L10n.menuButtons)
.onSelect {
router.route(to: \.actionButtonSelector, $menuActionButtons)
}
}
.onChange(of: barActionButtons) { newValue in
autoPlayEnabled = newValue.contains(.autoPlay) || menuActionButtons.contains(.autoPlay)
}
.onChange(of: menuActionButtons) { newValue in
autoPlayEnabled = newValue.contains(.autoPlay) || barActionButtons.contains(.autoPlay)
}
}
}
}

View File

@ -0,0 +1,37 @@
//
// 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) 2024 Jellyfin & Jellyfin Contributors
//
import Defaults
import SwiftUI
extension VideoPlayerSettingsView {
struct SliderSection: View {
@Default(.VideoPlayer.Overlay.chapterSlider)
private var chapterSlider
@Default(.VideoPlayer.Overlay.sliderColor)
private var sliderColor
@Default(.VideoPlayer.Overlay.sliderType)
private var sliderType
var body: some View {
Section(L10n.slider) {
Toggle(L10n.chapterSlider, isOn: $chapterSlider)
ColorPicker(selection: $sliderColor, supportsOpacity: false) {
Text(L10n.sliderColor)
}
CaseIterablePicker(L10n.sliderType, selection: $sliderType)
}
}
}
}

View File

@ -0,0 +1,49 @@
//
// 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) 2024 Jellyfin & Jellyfin Contributors
//
import Defaults
import SwiftUI
extension VideoPlayerSettingsView {
struct SubtitleSection: View {
@Default(.VideoPlayer.Subtitle.subtitleFontName)
private var subtitleFontName
@Default(.VideoPlayer.Subtitle.subtitleSize)
private var subtitleSize
@Default(.VideoPlayer.Subtitle.subtitleColor)
private var subtitleColor
@EnvironmentObject
private var router: VideoPlayerSettingsCoordinator.Router
var body: some View {
Section {
ChevronButton(L10n.subtitleFont, subtitle: subtitleFontName)
.onSelect {
router.route(to: \.fontPicker, $subtitleFontName)
}
BasicStepper(
title: L10n.subtitleSize,
value: $subtitleSize,
range: 8 ... 24,
step: 1
)
ColorPicker(selection: $subtitleColor, supportsOpacity: false) {
Text(L10n.subtitleColor)
}
} header: {
Text(L10n.subtitle)
} footer: {
// TODO: better wording
Text("Settings only affect some subtitle types")
}
}
}
}

View File

@ -0,0 +1,33 @@
//
// 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) 2024 Jellyfin & Jellyfin Contributors
//
import Defaults
import SwiftUI
extension VideoPlayerSettingsView {
struct TimestampSection: View {
@Default(.VideoPlayer.Overlay.trailingTimestampType)
private var trailingTimestampType
@Default(.VideoPlayer.Overlay.showCurrentTimeWhileScrubbing)
private var showCurrentTimeWhileScrubbing
@Default(.VideoPlayer.Overlay.timestampType)
private var timestampType
var body: some View {
Section(L10n.timestamp) {
Toggle(L10n.scrubCurrentTime, isOn: $showCurrentTimeWhileScrubbing)
CaseIterablePicker(L10n.timestampType, selection: $timestampType)
CaseIterablePicker(L10n.trailingValue, selection: $trailingTimestampType)
}
}
}
}

View File

@ -0,0 +1,27 @@
//
// 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) 2024 Jellyfin & Jellyfin Contributors
//
import Defaults
import SwiftUI
extension VideoPlayerSettingsView {
struct TransitionSection: View {
@Default(.VideoPlayer.Transition.pauseOnBackground)
private var pauseOnBackground
@Default(.VideoPlayer.Transition.playOnActive)
private var playOnActive
var body: some View {
Section(L10n.transition) {
Toggle(L10n.pauseOnBackground, isOn: $pauseOnBackground)
Toggle(L10n.playOnActive, isOn: $playOnActive)
}
}
}
}

View File

@ -11,11 +11,6 @@ import SwiftUI
struct VideoPlayerSettingsView: View {
// TODO: Organize
@Default(.VideoPlayer.autoPlayEnabled)
private var autoPlayEnabled
@Default(.VideoPlayer.jumpBackwardLength)
private var jumpBackwardLength
@Default(.VideoPlayer.jumpForwardLength)
@ -23,42 +18,6 @@ struct VideoPlayerSettingsView: View {
@Default(.VideoPlayer.resumeOffset)
private var resumeOffset
@Default(.VideoPlayer.showJumpButtons)
private var showJumpButtons
@Default(.VideoPlayer.barActionButtons)
private var barActionButtons
@Default(.VideoPlayer.menuActionButtons)
private var menuActionButtons
@Default(.VideoPlayer.Subtitle.subtitleFontName)
private var subtitleFontName
@Default(.VideoPlayer.Subtitle.subtitleSize)
private var subtitleSize
@Default(.VideoPlayer.Subtitle.subtitleColor)
private var subtitleColor
@Default(.VideoPlayer.Overlay.chapterSlider)
private var chapterSlider
@Default(.VideoPlayer.Overlay.playbackButtonType)
private var playbackButtonType
@Default(.VideoPlayer.Overlay.sliderColor)
private var sliderColor
@Default(.VideoPlayer.Overlay.sliderType)
private var sliderType
@Default(.VideoPlayer.Overlay.trailingTimestampType)
private var trailingTimestampType
@Default(.VideoPlayer.Overlay.showCurrentTimeWhileScrubbing)
private var showCurrentTimeWhileScrubbing
@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
@ -89,84 +48,16 @@ struct VideoPlayerSettingsView: View {
Text(L10n.resumeOffsetDescription)
}
Section(L10n.buttons) {
ButtonSection()
CaseIterablePicker(L10n.playbackButtons, selection: $playbackButtonType)
SliderSection()
Toggle(isOn: $showJumpButtons) {
HStack {
Image(systemName: "goforward")
Text(L10n.jump)
}
}
SubtitleSection()
ChevronButton(L10n.barButtons)
.onSelect {
router.route(to: \.actionButtonSelector, $barActionButtons)
}
TimestampSection()
ChevronButton(L10n.menuButtons)
.onSelect {
router.route(to: \.actionButtonSelector, $menuActionButtons)
}
}
Section(L10n.slider) {
Toggle(L10n.chapterSlider, isOn: $chapterSlider)
ColorPicker(selection: $sliderColor, supportsOpacity: false) {
Text(L10n.sliderColor)
}
CaseIterablePicker(L10n.sliderType, selection: $sliderType)
}
Section {
ChevronButton(L10n.subtitleFont, subtitle: subtitleFontName)
.onSelect {
router.route(to: \.fontPicker, $subtitleFontName)
}
BasicStepper(
title: L10n.subtitleSize,
value: $subtitleSize,
range: 8 ... 24,
step: 1
)
ColorPicker(selection: $subtitleColor, supportsOpacity: false) {
Text(L10n.subtitleColor)
}
} header: {
Text(L10n.subtitle)
} footer: {
// TODO: better wording
Text("Settings only affect some subtitle types")
}
Section(L10n.timestamp) {
Toggle(L10n.scrubCurrentTime, isOn: $showCurrentTimeWhileScrubbing)
CaseIterablePicker(L10n.timestampType, selection: $timestampType)
CaseIterablePicker(L10n.trailingValue, selection: $trailingTimestampType)
}
Section(L10n.transition) {
Toggle(L10n.pauseOnBackground, isOn: $pauseOnBackground)
Toggle(L10n.playOnActive, isOn: $playOnActive)
}
TransitionSection()
}
.navigationTitle(L10n.videoPlayer)
.onChange(of: barActionButtons) { newValue in
autoPlayEnabled = newValue.contains(.autoPlay) || menuActionButtons.contains(.autoPlay)
}
.onChange(of: menuActionButtons) { newValue in
autoPlayEnabled = newValue.contains(.autoPlay) || barActionButtons.contains(.autoPlay)
}
}
}