From b7d393ed3bcfdb90a731ed5a5d1ca3fb84217e76 Mon Sep 17 00:00:00 2001 From: MrTimscampi Date: Tue, 25 May 2021 21:41:41 +0200 Subject: [PATCH] Refactor SettingsView Reworks the file to fit better with MVVM and loads bitrates from a JSON file for easier changes --- JellyfinPlayer.xcodeproj/project.pbxproj | 51 ++++++++++++++++++- JellyfinPlayer/ContentView.swift | 2 +- JellyfinPlayer/Models/SettingsModel.swift | 20 ++++++++ JellyfinPlayer/Resources/bitrates.json | 46 +++++++++++++++++ .../ViewModels/SettingsViewModel.swift | 27 ++++++++++ JellyfinPlayer/{ => Views}/SettingsView.swift | 42 +++------------ 6 files changed, 151 insertions(+), 37 deletions(-) create mode 100644 JellyfinPlayer/Models/SettingsModel.swift create mode 100644 JellyfinPlayer/Resources/bitrates.json create mode 100644 JellyfinPlayer/ViewModels/SettingsViewModel.swift rename JellyfinPlayer/{ => Views}/SettingsView.swift (67%) diff --git a/JellyfinPlayer.xcodeproj/project.pbxproj b/JellyfinPlayer.xcodeproj/project.pbxproj index b9aace8d..a536b2a2 100644 --- a/JellyfinPlayer.xcodeproj/project.pbxproj +++ b/JellyfinPlayer.xcodeproj/project.pbxproj @@ -44,6 +44,9 @@ 53E4E649263F725B00F67C6B /* MultiSelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53E4E648263F725B00F67C6B /* MultiSelector.swift */; }; 53EE24E6265060780068F029 /* LibrarySearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53EE24E5265060780068F029 /* LibrarySearchView.swift */; }; 53FF7F2A263CF3F500585C35 /* LatestMediaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53FF7F29263CF3F500585C35 /* LatestMediaView.swift */; }; + AE8C3154265D60BF008AA076 /* SettingsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE8C3153265D60BF008AA076 /* SettingsModel.swift */; }; + AE8C3156265D616A008AA076 /* SettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE8C3155265D616A008AA076 /* SettingsViewModel.swift */; }; + AE8C3159265D6F90008AA076 /* bitrates.json in Resources */ = {isa = PBXBuildFile; fileRef = AE8C3158265D6F90008AA076 /* bitrates.json */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -102,6 +105,9 @@ 53E4E648263F725B00F67C6B /* MultiSelector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiSelector.swift; sourceTree = ""; }; 53EE24E5265060780068F029 /* LibrarySearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibrarySearchView.swift; sourceTree = ""; }; 53FF7F29263CF3F500585C35 /* LatestMediaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LatestMediaView.swift; sourceTree = ""; }; + AE8C3153265D60BF008AA076 /* SettingsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsModel.swift; sourceTree = ""; }; + AE8C3155265D616A008AA076 /* SettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewModel.swift; sourceTree = ""; }; + AE8C3158265D6F90008AA076 /* bitrates.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = bitrates.json; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -146,6 +152,10 @@ 5377CBF3263B596A003A4E83 /* JellyfinPlayer */ = { isa = PBXGroup; children = ( + AE8C3157265D6F5E008AA076 /* Resources */, + AE8C3152265D607B008AA076 /* ViewModels */, + AE8C3151265D6075008AA076 /* Models */, + AE8C3150265D5FE1008AA076 /* Views */, 5377CBF4263B596A003A4E83 /* JellyfinPlayerApp.swift */, 5377CBF6263B596A003A4E83 /* ContentView.swift */, 5377CBF8263B596B003A4E83 /* Assets.xcassets */, @@ -154,7 +164,6 @@ 5377CBFF263B596B003A4E83 /* Model.xcdatamodeld */, 5377CBFA263B596B003A4E83 /* Preview Content */, 5338F74D263B61370014BF09 /* ConnectToServerView.swift */, - 539B2DA4263BA5B8007FF1A4 /* SettingsView.swift */, 5389276D263C25100035E14B /* ContinueWatchingView.swift */, 5389276F263C25230035E14B /* NextUpView.swift */, 53892771263C8C6F0035E14B /* LoadingView.swift */, @@ -195,6 +204,38 @@ name = Frameworks; sourceTree = ""; }; + AE8C3150265D5FE1008AA076 /* Views */ = { + isa = PBXGroup; + children = ( + 539B2DA4263BA5B8007FF1A4 /* SettingsView.swift */, + ); + path = Views; + sourceTree = ""; + }; + AE8C3151265D6075008AA076 /* Models */ = { + isa = PBXGroup; + children = ( + AE8C3153265D60BF008AA076 /* SettingsModel.swift */, + ); + path = Models; + sourceTree = ""; + }; + AE8C3152265D607B008AA076 /* ViewModels */ = { + isa = PBXGroup; + children = ( + AE8C3155265D616A008AA076 /* SettingsViewModel.swift */, + ); + path = ViewModels; + sourceTree = ""; + }; + AE8C3157265D6F5E008AA076 /* Resources */ = { + isa = PBXGroup; + children = ( + AE8C3158265D6F90008AA076 /* bitrates.json */, + ); + path = Resources; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -277,6 +318,7 @@ buildActionMask = 2147483647; files = ( 5377CBFC263B596B003A4E83 /* Preview Assets.xcassets in Resources */, + AE8C3159265D6F90008AA076 /* bitrates.json in Resources */, 5377CBF9263B596B003A4E83 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -316,6 +358,7 @@ 535BAE9F2649E569005FA86D /* ItemView.swift in Sources */, 53987CA426572C1300E7EA70 /* SeasonItemView.swift in Sources */, 53192D5D265AA78A008A4215 /* DeviceProfileBuilder.swift in Sources */, + AE8C3154265D60BF008AA076 /* SettingsModel.swift in Sources */, 53892770263C25230035E14B /* NextUpView.swift in Sources */, 535BAEA5264A151C005FA86D /* VLCPlayer.swift in Sources */, 5377CC01263B596B003A4E83 /* Model.xcdatamodeld in Sources */, @@ -330,6 +373,7 @@ 5389277C263CC3DB0035E14B /* BlurHashDecode.swift in Sources */, 53987CA626572F0700E7EA70 /* SeriesItemView.swift in Sources */, 539B2DA5263BA5B8007FF1A4 /* SettingsView.swift in Sources */, + AE8C3156265D616A008AA076 /* SettingsViewModel.swift in Sources */, 5338F74E263B61370014BF09 /* ConnectToServerView.swift in Sources */, 5377CBF5263B596A003A4E83 /* JellyfinPlayerApp.swift in Sources */, 53EE24E6265060780068F029 /* LibrarySearchView.swift in Sources */, @@ -377,6 +421,8 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + EXCLUDED_ARCHS = ""; + "EXCLUDED_ARCHS[sdk=*]" = ""; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -438,6 +484,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + EXCLUDED_ARCHS = ""; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -467,6 +514,7 @@ DEVELOPMENT_TEAM = 9R8RREG67J; ENABLE_BITCODE = NO; ENABLE_PREVIEWS = YES; + EXCLUDED_ARCHS = ""; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS", @@ -497,6 +545,7 @@ DEVELOPMENT_TEAM = 9R8RREG67J; ENABLE_BITCODE = NO; ENABLE_PREVIEWS = YES; + EXCLUDED_ARCHS = ""; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS", diff --git a/JellyfinPlayer/ContentView.swift b/JellyfinPlayer/ContentView.swift index 4ce6233c..56b8af4a 100644 --- a/JellyfinPlayer/ContentView.swift +++ b/JellyfinPlayer/ContentView.swift @@ -379,7 +379,7 @@ struct ContentView: View { Image(systemName: "gear") } } - }.fullScreenCover( isPresented: $showSettingsPopover) { SettingsView(close: $showSettingsPopover).environmentObject(globalData) } + }.fullScreenCover( isPresented: $showSettingsPopover) { SettingsView(viewModel: SettingsViewModel(), close: $showSettingsPopover).environmentObject(globalData) } } .navigationViewStyle(StackNavigationViewStyle()) .tabItem({ diff --git a/JellyfinPlayer/Models/SettingsModel.swift b/JellyfinPlayer/Models/SettingsModel.swift new file mode 100644 index 00000000..8646f1bd --- /dev/null +++ b/JellyfinPlayer/Models/SettingsModel.swift @@ -0,0 +1,20 @@ +// +// SettingsModel.swift +// JellyfinPlayer +// +// Created by Julien Machiels on 25/05/2021. +// + +import Foundation + +struct UserSettings: Decodable { + var LocalMaxBitrate: Int; + var RemoteMaxBitrate: Int; + var AutoSelectSubtitles: Bool; + var AutoSelectSubtitlesLangcode: String; +} + +struct Bitrates: Codable, Hashable { + public var name: String + public var value: Int +} diff --git a/JellyfinPlayer/Resources/bitrates.json b/JellyfinPlayer/Resources/bitrates.json new file mode 100644 index 00000000..4fddb7b6 --- /dev/null +++ b/JellyfinPlayer/Resources/bitrates.json @@ -0,0 +1,46 @@ +[ + { + "name": "1080p - 60 Mbps", + "value": 60000000 + }, + { + "name": "1080p - 40 Mbps", + "value": 40000000 + }, + { + "name": "1080p - 20 Mbps", + "value": 20000000 + }, + { + "name": "1080p - 15 Mbps", + "value": 15000000 + }, + { + "name": "1080p - 10 Mbps", + "value": 10000000 + }, + { + "name": "720p - 8 Mbps", + "value": 8000000 + }, + { + "name": "720p - 6 Mbps", + "value": 6000000 + }, + { + "name": "720p - 4 Mbps", + "value": 4000000 + }, + { + "name": "480p - 3 Mbps", + "value": 3000000 + }, + { + "name": "480p - 1.5 Mbps", + "value": 2000000 + }, + { + "name": "480p - 740 Kbps", + "value": 1000000 + } +] diff --git a/JellyfinPlayer/ViewModels/SettingsViewModel.swift b/JellyfinPlayer/ViewModels/SettingsViewModel.swift new file mode 100644 index 00000000..288eae87 --- /dev/null +++ b/JellyfinPlayer/ViewModels/SettingsViewModel.swift @@ -0,0 +1,27 @@ +// +// SettingsViewModel.swift +// JellyfinPlayer +// +// Created by Julien Machiels on 25/05/2021. +// + +import Foundation + +final class SettingsViewModel: ObservableObject { + var bitrates: [Bitrates] = [] + + init() { + let url = Bundle.main.url(forResource: "bitrates", withExtension: "json")! + + do { + let jsonData = try Data(contentsOf: url, options: .mappedIfSafe) + do { + self.bitrates = try JSONDecoder().decode([Bitrates].self, from: jsonData) + } catch { + print(error) + } + } catch { + print(error) + } + } +} diff --git a/JellyfinPlayer/SettingsView.swift b/JellyfinPlayer/Views/SettingsView.swift similarity index 67% rename from JellyfinPlayer/SettingsView.swift rename to JellyfinPlayer/Views/SettingsView.swift index 0360bcb7..f068cfae 100644 --- a/JellyfinPlayer/SettingsView.swift +++ b/JellyfinPlayer/Views/SettingsView.swift @@ -8,14 +8,9 @@ import SwiftUI import CoreData -struct UserSettings: Codable { - var LocalMaxBitrate: Int; - var RemoteMaxBitrate: Int; - var AutoSelectSubtitles: Bool; - var AutoSelectSubtitlesLangcode: String; -} - struct SettingsView: View { + @ObservedObject var viewModel: SettingsViewModel + @Binding var close: Bool; @Environment(\.managedObjectContext) private var viewContext @EnvironmentObject var globalData: GlobalData @@ -36,42 +31,18 @@ struct SettingsView: View { Form() { Section(header: Text("Playback settings")) { Picker("Default local playback bitrate", selection: $inNetworkStreamBitrate) { - Group { - Text("1080p - 60 Mbps").tag(60000000) - Text("1080p - 40 Mbps").tag(40000000) - Text("1080p - 20 Mbps").tag(20000000) - Text("1080p - 15 Mbps").tag(15000000) - Text("1080p - 10 Mbps").tag(10000000) + ForEach(self.viewModel.bitrates, id: \.self) { bitrate in + Text(bitrate.name).tag(bitrate.value) } - Group { - Text("720p - 8 Mbps").tag(8000000) - Text("720p - 6 Mbps").tag(6000000) - Text("720p - 4 Mbps").tag(4000000) - } - Text("480p - 3 Mbps").tag(3000000) - Text("480p - 1.5 Mbps").tag(2000000) - Text("480p - 740 Kbps").tag(1000000) }.onChange(of: inNetworkStreamBitrate) { _ in let defaults = UserDefaults.standard defaults.setValue(_inNetworkStreamBitrate.wrappedValue, forKey: "InNetworkBandwidth") } Picker("Default remote playback bitrate", selection: $outOfNetworkStreamBitrate) { - Group { - Text("1080p - 60 Mbps").tag(60000000) - Text("1080p - 40 Mbps").tag(40000000) - Text("1080p - 20 Mbps").tag(20000000) - Text("1080p - 15 Mbps").tag(15000000) - Text("1080p - 10 Mbps").tag(10000000) + ForEach(self.viewModel.bitrates, id: \.self) { bitrate in + Text(bitrate.name).tag(bitrate.value) } - Group { - Text("720p - 8 Mbps").tag(8000000) - Text("720p - 6 Mbps").tag(6000000) - Text("720p - 4 Mbps").tag(4000000) - } - Text("480p - 3 Mbps").tag(3000000) - Text("480p - 1.5 Mbps").tag(2000000) - Text("480p - 740 Kbps").tag(1000000) }.onChange(of: outOfNetworkStreamBitrate) { _ in let defaults = UserDefaults.standard defaults.setValue(_outOfNetworkStreamBitrate.wrappedValue, forKey: "OutOfNetworkBandwidth") @@ -103,6 +74,7 @@ struct SettingsView: View { globalData.authToken = "" globalData.authHeader = "" jsi.did = true + // TODO: This should redirect to the server selection screen exit(-1) } label: { Text("Log out")