diff --git a/JellyfinPlayer tvOS/App/JellyfinPlayer_tvOSApp.swift b/JellyfinPlayer tvOS/App/JellyfinPlayer_tvOSApp.swift index db58374a..2f1ff9e7 100644 --- a/JellyfinPlayer tvOS/App/JellyfinPlayer_tvOSApp.swift +++ b/JellyfinPlayer tvOS/App/JellyfinPlayer_tvOSApp.swift @@ -14,7 +14,6 @@ struct JellyfinPlayer_tvOSApp: App { var body: some Scene { WindowGroup { MainCoordinator().view() - .ignoresSafeArea(.all, edges: .all) } } } diff --git a/JellyfinPlayer tvOS/Views/PlainNavigationLinkButton.swift b/JellyfinPlayer tvOS/Components/PlainNavigationLinkButton.swift similarity index 58% rename from JellyfinPlayer tvOS/Views/PlainNavigationLinkButton.swift rename to JellyfinPlayer tvOS/Components/PlainNavigationLinkButton.swift index 2a458505..1d871577 100644 --- a/JellyfinPlayer tvOS/Views/PlainNavigationLinkButton.swift +++ b/JellyfinPlayer tvOS/Components/PlainNavigationLinkButton.swift @@ -1,3 +1,12 @@ +// + /* + * 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 PlainNavigationLinkButtonStyle: ButtonStyle { diff --git a/JellyfinPlayer tvOS/Views/MainTabView.swift b/JellyfinPlayer tvOS/Views/MainTabView.swift deleted file mode 100644 index 77dc3cfc..00000000 --- a/JellyfinPlayer tvOS/Views/MainTabView.swift +++ /dev/null @@ -1,77 +0,0 @@ -// - /* - * 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 Foundation -import SwiftUI - -struct MainTabView: View { - @State private var tabSelection: Tab = .home - @StateObject private var viewModel = MainTabViewModel() - @State private var backdropAnim: Bool = true - @State private var lastBackdropAnim: Bool = false - - var body: some View { - ZStack { - // please do not touch my magical crossfading. i will wave my magical github wand and cry - if viewModel.lastBackgroundURL != nil { - ImageView(src: viewModel.lastBackgroundURL!, bh: viewModel.backgroundBlurHash) - .frame(minWidth: 100, maxWidth: .infinity, minHeight: 100, maxHeight: .infinity) - .opacity(lastBackdropAnim ? 0.4 : 0) - .ignoresSafeArea() - } - if viewModel.backgroundURL != nil { - ImageView(src: viewModel.backgroundURL!, bh: viewModel.backgroundBlurHash) - .frame(minWidth: 100, maxWidth: .infinity, minHeight: 100, maxHeight: .infinity) - .opacity(backdropAnim ? 0.4 : 0) - .onChange(of: viewModel.backgroundURL) { _ in - lastBackdropAnim = true - backdropAnim = false - withAnimation(.linear(duration: 0.33)) { - lastBackdropAnim = false - backdropAnim = true - } - } - .ignoresSafeArea() - } - - TabView(selection: $tabSelection) { - HomeView() - .offset(y: -1) // don't remove this. it breaks tabview on 4K displays. - .tabItem { - Text("Home") - Image(systemName: "house") - } - .tag(Tab.home) - - LibraryListView() - .tabItem { - Text("All Media") - Image(systemName: "folder") - } - .tag(Tab.allMedia) - - SettingsView(viewModel: SettingsViewModel()) - .offset(y: -1) // don't remove this. it breaks tabview on 4K displays. - .tabItem { - Text("Settings") - Image(systemName: "gear") - } - .tag(Tab.settings) - } - } - } -} - -extension MainTabView { - enum Tab: String { - case home - case allMedia - case settings - } -} diff --git a/JellyfinPlayer tvOS/Views/SettingsView.swift b/JellyfinPlayer tvOS/Views/SettingsView.swift index 19a25174..7442eeeb 100644 --- a/JellyfinPlayer tvOS/Views/SettingsView.swift +++ b/JellyfinPlayer tvOS/Views/SettingsView.swift @@ -11,8 +11,7 @@ import Defaults import JellyfinAPI struct SettingsView: View { - @Environment(\.managedObjectContext) private var viewContext - + @ObservedObject var viewModel: SettingsViewModel @Default(.inNetworkBandwidth) var inNetworkStreamBitrate @@ -20,11 +19,6 @@ struct SettingsView: View { @Default(.isAutoSelectSubtitles) var isAutoSelectSubtitles @Default(.autoSelectSubtitlesLangCode) var autoSelectSubtitlesLangcode @Default(.autoSelectAudioLangCode) var autoSelectAudioLangcode - @State private var username: String = "" - - func onAppear() { - username = SessionManager.main.currentLogin.user.username - } var body: some View { Form { @@ -64,7 +58,7 @@ struct SettingsView: View { Section(header: Text(SessionManager.main.currentLogin.server.name)) { HStack { - Text("Signed in as \(username)").foregroundColor(.primary) + Text("Signed in as \(SessionManager.main.currentLogin.user.username)").foregroundColor(.primary) Spacer() Button { SwiftfinNotificationCenter.main.post(name: SwiftfinNotificationCenter.Keys.didSignOut, object: nil) @@ -78,7 +72,7 @@ struct SettingsView: View { Text("Sign out").font(.callout) } } - }.onAppear(perform: onAppear) + } .padding(.leading, 90) .padding(.trailing, 90) } diff --git a/JellyfinPlayer tvOS/Views/SplashView.swift b/JellyfinPlayer tvOS/Views/SplashView.swift deleted file mode 100644 index 234da126..00000000 --- a/JellyfinPlayer tvOS/Views/SplashView.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -/* - * 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 SplashView: View { - - @StateObject var viewModel = SplashViewModel() - - var body: some View { - Group { - if SessionManager.main.currentLogin == nil { - NavigationView { - ConnectToServerView() - } - .navigationViewStyle(StackNavigationViewStyle()) - } else { - NavigationView { - MainTabView() - } - .ignoresSafeArea() - } - } - } -} diff --git a/JellyfinPlayer.xcodeproj/project.pbxproj b/JellyfinPlayer.xcodeproj/project.pbxproj index 4612e0a2..45627dcb 100644 --- a/JellyfinPlayer.xcodeproj/project.pbxproj +++ b/JellyfinPlayer.xcodeproj/project.pbxproj @@ -24,7 +24,6 @@ 5310695D2684E7EE00CFFDBA /* VideoPlayer.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 531069562684E7EE00CFFDBA /* VideoPlayer.storyboard */; }; 53116A17268B919A003024C9 /* SeriesItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53116A16268B919A003024C9 /* SeriesItemView.swift */; }; 53116A19268B947A003024C9 /* PlainLinkButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53116A18268B947A003024C9 /* PlainLinkButton.swift */; }; - 531690E5267ABD5C005D8AB9 /* MainTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 531690E4267ABD5C005D8AB9 /* MainTabView.swift */; }; 531690E7267ABD79005D8AB9 /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 531690E6267ABD79005D8AB9 /* HomeView.swift */; }; 531690ED267ABF46005D8AB9 /* ContinueWatchingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 531690EB267ABF46005D8AB9 /* ContinueWatchingView.swift */; }; 531690F0267ABF72005D8AB9 /* NextUpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 531690EE267ABF72005D8AB9 /* NextUpView.swift */; }; @@ -57,7 +56,6 @@ 5358706A2669D21700D05A09 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 535870692669D21700D05A09 /* Preview Assets.xcassets */; }; 5358707E2669D64F00D05A09 /* bitrates.json in Resources */ = {isa = PBXBuildFile; fileRef = AE8C3158265D6F90008AA076 /* bitrates.json */; }; 535870912669D7A800D05A09 /* Introspect in Frameworks */ = {isa = PBXBuildFile; productRef = 535870902669D7A800D05A09 /* Introspect */; }; - 5358709B2669D7A800D05A09 /* NukeUI in Frameworks */ = {isa = PBXBuildFile; productRef = 5358709A2669D7A800D05A09 /* NukeUI */; }; 535870A52669D8AE00D05A09 /* ParallaxHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6225FCCA2663841E00E067F6 /* ParallaxHeader.swift */; }; 535870A62669D8AE00D05A09 /* LazyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621338B22660A07800A81A2A /* LazyView.swift */; }; 535870A72669D8AE00D05A09 /* MultiSelectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53E4E648263F725B00F67C6B /* MultiSelectorView.swift */; }; @@ -137,12 +135,10 @@ 53A431BF266B0FFE0016769F /* JellyfinAPI in Frameworks */ = {isa = PBXBuildFile; productRef = 53A431BE266B0FFE0016769F /* JellyfinAPI */; }; 53A83C33268A309300DF3D92 /* LibraryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53A83C32268A309300DF3D92 /* LibraryView.swift */; }; 53ABFDDC267972BF00886593 /* TVServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53ABFDDB267972BF00886593 /* TVServices.framework */; }; - 53ABFDDE267974E300886593 /* SplashView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53ABFDDD267974E300886593 /* SplashView.swift */; }; 53ABFDE4267974EF00886593 /* LibraryListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB5742678C33500530A6E /* LibraryListViewModel.swift */; }; 53ABFDE5267974EF00886593 /* ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB57B2678CE1000530A6E /* ViewModel.swift */; }; 53ABFDE6267974EF00886593 /* SettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5321753A2671BCFC005491E6 /* SettingsViewModel.swift */; }; 53ABFDE7267974EF00886593 /* ConnectToServerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB5762678C34300530A6E /* ConnectToServerViewModel.swift */; }; - 53ABFDE8267974EF00886593 /* SplashViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB5692678B71200530A6E /* SplashViewModel.swift */; }; 53ABFDE9267974EF00886593 /* HomeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB5722678C32A00530A6E /* HomeViewModel.swift */; }; 53ABFDEB2679753200886593 /* ConnectToServerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53ABFDEA2679753200886593 /* ConnectToServerView.swift */; }; 53ABFDED26799D7700886593 /* ActivityIndicator in Frameworks */ = {isa = PBXBuildFile; productRef = 53ABFDEC26799D7700886593 /* ActivityIndicator */; }; @@ -154,7 +150,6 @@ 53E4E649263F725B00F67C6B /* MultiSelectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53E4E648263F725B00F67C6B /* MultiSelectorView.swift */; }; 53EC6E1E267E80AC006DD26A /* Pods_JellyfinPlayer_tvOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EBFE1F64394BCC2EFFF1610D /* Pods_JellyfinPlayer_tvOS.framework */; }; 53EC6E21267E80B1006DD26A /* Pods_JellyfinPlayer_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F905C1D3D3A0C9E13E7A0BC /* Pods_JellyfinPlayer_iOS.framework */; }; - 53EC6E25267EB10F006DD26A /* SwiftyJSON in Frameworks */ = {isa = PBXBuildFile; productRef = 53EC6E24267EB10F006DD26A /* SwiftyJSON */; }; 53EE24E6265060780068F029 /* LibrarySearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53EE24E5265060780068F029 /* LibrarySearchView.swift */; }; 53F8377D265FF67C00F456B3 /* VideoPlayerSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53F8377C265FF67C00F456B3 /* VideoPlayerSettingsView.swift */; }; 53F866442687A45F00DCD1D7 /* PortraitItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53F866432687A45F00DCD1D7 /* PortraitItemView.swift */; }; @@ -162,7 +157,6 @@ 62133890265F83A900A81A2A /* LibraryListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6213388F265F83A900A81A2A /* LibraryListView.swift */; }; 621338932660107500A81A2A /* StringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621338922660107500A81A2A /* StringExtensions.swift */; }; 621338B32660A07800A81A2A /* LazyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621338B22660A07800A81A2A /* LazyView.swift */; }; - 621C638026672A30004216EA /* NukeUI in Frameworks */ = {isa = PBXBuildFile; productRef = 621C637F26672A30004216EA /* NukeUI */; }; 6220D0AD26D5EABB00B8E046 /* ViewExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6220D0AC26D5EABB00B8E046 /* ViewExtensions.swift */; }; 6220D0AE26D5EABB00B8E046 /* ViewExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6220D0AC26D5EABB00B8E046 /* ViewExtensions.swift */; }; 6220D0AF26D5EABE00B8E046 /* ViewExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6220D0AC26D5EABB00B8E046 /* ViewExtensions.swift */; }; @@ -176,15 +170,11 @@ 6220D0CC26D640C400B8E046 /* AppURLHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6220D0CB26D640C400B8E046 /* AppURLHandler.swift */; }; 6225FCCB2663841E00E067F6 /* ParallaxHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6225FCCA2663841E00E067F6 /* ParallaxHeader.swift */; }; 624C21752685CF60007F1390 /* SearchablePickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 624C21742685CF60007F1390 /* SearchablePickerView.swift */; }; - 625CB5682678B6FB00530A6E /* SplashView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB5672678B6FB00530A6E /* SplashView.swift */; }; - 625CB56A2678B71200530A6E /* SplashViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB5692678B71200530A6E /* SplashViewModel.swift */; }; 625CB56F2678C23300530A6E /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB56E2678C23300530A6E /* HomeView.swift */; }; 625CB5732678C32A00530A6E /* HomeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB5722678C32A00530A6E /* HomeViewModel.swift */; }; 625CB5752678C33500530A6E /* LibraryListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB5742678C33500530A6E /* LibraryListViewModel.swift */; }; 625CB5772678C34300530A6E /* ConnectToServerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB5762678C34300530A6E /* ConnectToServerViewModel.swift */; }; 625CB57A2678C4A400530A6E /* ActivityIndicator in Frameworks */ = {isa = PBXBuildFile; productRef = 625CB5792678C4A400530A6E /* ActivityIndicator */; }; - 6260FFF926A09754003FA968 /* CombineExt in Frameworks */ = {isa = PBXBuildFile; productRef = 6260FFF826A09754003FA968 /* CombineExt */; }; - 6261A0E026A0AB710072EF1C /* CombineExt in Frameworks */ = {isa = PBXBuildFile; productRef = 6261A0DF26A0AB710072EF1C /* CombineExt */; }; 62671DB327159C1800199D95 /* ItemCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6220D0BF26D61C5000B8E046 /* ItemCoordinator.swift */; }; 6267B3D626710B8900A7371D /* CollectionExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6267B3D526710B8900A7371D /* CollectionExtensions.swift */; }; 6267B3D726710B9700A7371D /* CollectionExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6267B3D526710B8900A7371D /* CollectionExtensions.swift */; }; @@ -196,7 +186,6 @@ 628B95272670CABD0091AF3B /* NextUpWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 628B95262670CABD0091AF3B /* NextUpWidget.swift */; }; 628B95292670CABE0091AF3B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 628B95282670CABE0091AF3B /* Assets.xcassets */; }; 628B952D2670CABE0091AF3B /* WidgetExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 628B95202670CABD0091AF3B /* WidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - 628B95332670CAEA0091AF3B /* NukeUI in Frameworks */ = {isa = PBXBuildFile; productRef = 628B95322670CAEA0091AF3B /* NukeUI */; }; 628B95352670CAEA0091AF3B /* JellyfinAPI in Frameworks */ = {isa = PBXBuildFile; productRef = 628B95342670CAEA0091AF3B /* JellyfinAPI */; }; 628B95372670CB800091AF3B /* JellyfinWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 628B95362670CB800091AF3B /* JellyfinWidget.swift */; }; 628B953C2670D2430091AF3B /* StringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621338922660107500A81A2A /* StringExtensions.swift */; }; @@ -238,6 +227,9 @@ E11B1B6D2718CD68006DA3E8 /* JellyfinAPIError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11B1B6B2718CD68006DA3E8 /* JellyfinAPIError.swift */; }; E11B1B6E2718CDBA006DA3E8 /* JellyfinAPIError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11B1B6B2718CD68006DA3E8 /* JellyfinAPIError.swift */; }; E12186DE2718F1C50010884C /* Defaults in Frameworks */ = {isa = PBXBuildFile; productRef = E12186DD2718F1C50010884C /* Defaults */; }; + E1218C9A271A26BA00EA0737 /* Nuke in Frameworks */ = {isa = PBXBuildFile; productRef = E1218C99271A26BA00EA0737 /* Nuke */; }; + E1218C9C271A26C400EA0737 /* Nuke in Frameworks */ = {isa = PBXBuildFile; productRef = E1218C9B271A26C400EA0737 /* Nuke */; }; + E1267D3E271A1F46003C492E /* PreferenceUIHostingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1267D3D271A1F46003C492E /* PreferenceUIHostingController.swift */; }; E131691726C583BC0074BFEE /* LogConstructor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E131691626C583BC0074BFEE /* LogConstructor.swift */; }; E131691826C583BC0074BFEE /* LogConstructor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E131691626C583BC0074BFEE /* LogConstructor.swift */; }; E131691926C583BC0074BFEE /* LogConstructor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E131691626C583BC0074BFEE /* LogConstructor.swift */; }; @@ -316,6 +308,8 @@ E1AD105C26D9ABDD003E4A08 /* PillHStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AD105B26D9ABDD003E4A08 /* PillHStackView.swift */; }; E1AD105F26D9ADDD003E4A08 /* NameGUIDPairExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AD105E26D9ADDD003E4A08 /* NameGUIDPairExtensions.swift */; }; E1AD106226D9B7CD003E4A08 /* ItemPortraitHeaderOverlayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AD106126D9B7CD003E4A08 /* ItemPortraitHeaderOverlayView.swift */; }; + E1B6DCE8271A23780015B715 /* CombineExt in Frameworks */ = {isa = PBXBuildFile; productRef = E1B6DCE7271A23780015B715 /* CombineExt */; }; + E1B6DCEA271A23880015B715 /* SwiftyJSON in Frameworks */ = {isa = PBXBuildFile; productRef = E1B6DCE9271A23880015B715 /* SwiftyJSON */; }; E1D4BF7C2719D05000A11E64 /* BasicAppSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D4BF7B2719D05000A11E64 /* BasicAppSettingsView.swift */; }; E1D4BF7E2719D1DD00A11E64 /* BasicAppSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D4BF7D2719D1DC00A11E64 /* BasicAppSettingsViewModel.swift */; }; E1D4BF7F2719D1DD00A11E64 /* BasicAppSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D4BF7D2719D1DC00A11E64 /* BasicAppSettingsViewModel.swift */; }; @@ -389,12 +383,10 @@ 531069562684E7EE00CFFDBA /* VideoPlayer.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = VideoPlayer.storyboard; sourceTree = ""; }; 53116A16268B919A003024C9 /* SeriesItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeriesItemView.swift; sourceTree = ""; }; 53116A18268B947A003024C9 /* PlainLinkButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlainLinkButton.swift; sourceTree = ""; }; - 531690E4267ABD5C005D8AB9 /* MainTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabView.swift; sourceTree = ""; }; 531690E6267ABD79005D8AB9 /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = ""; }; 531690EB267ABF46005D8AB9 /* ContinueWatchingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContinueWatchingView.swift; sourceTree = ""; }; 531690EE267ABF72005D8AB9 /* NextUpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextUpView.swift; sourceTree = ""; }; 531690F6267ACC00005D8AB9 /* LandscapeItemElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LandscapeItemElement.swift; sourceTree = ""; }; - 531690F8267AD135005D8AB9 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 531690F9267AD6EC005D8AB9 /* PlainNavigationLinkButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlainNavigationLinkButton.swift; sourceTree = ""; }; 53192D5C265AA78A008A4215 /* DeviceProfileBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceProfileBuilder.swift; sourceTree = ""; }; 531AC8BE26750DE20091C7EB /* ImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageView.swift; sourceTree = ""; }; @@ -466,7 +458,6 @@ 539B2DA4263BA5B8007FF1A4 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; 53A83C32268A309300DF3D92 /* LibraryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryView.swift; sourceTree = ""; }; 53ABFDDB267972BF00886593 /* TVServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TVServices.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS15.0.sdk/System/Library/Frameworks/TVServices.framework; sourceTree = DEVELOPER_DIR; }; - 53ABFDDD267974E300886593 /* SplashView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashView.swift; sourceTree = ""; }; 53ABFDEA2679753200886593 /* ConnectToServerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectToServerView.swift; sourceTree = ""; }; 53AD124C2670278D0094A276 /* JellyfinPlayer.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = JellyfinPlayer.entitlements; sourceTree = ""; }; 53CD2A3F268A49C2002ABD4E /* ItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemView.swift; sourceTree = ""; }; @@ -493,8 +484,6 @@ 6220D0CB26D640C400B8E046 /* AppURLHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppURLHandler.swift; sourceTree = ""; }; 6225FCCA2663841E00E067F6 /* ParallaxHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParallaxHeader.swift; sourceTree = ""; }; 624C21742685CF60007F1390 /* SearchablePickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchablePickerView.swift; sourceTree = ""; }; - 625CB5672678B6FB00530A6E /* SplashView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashView.swift; sourceTree = ""; }; - 625CB5692678B71200530A6E /* SplashViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashViewModel.swift; sourceTree = ""; }; 625CB56E2678C23300530A6E /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = ""; }; 625CB5722678C32A00530A6E /* HomeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewModel.swift; sourceTree = ""; }; 625CB5742678C33500530A6E /* LibraryListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryListViewModel.swift; sourceTree = ""; }; @@ -535,6 +524,7 @@ DE5004F745B19E28744A7DE7 /* Pods-JellyfinPlayer tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JellyfinPlayer tvOS.debug.xcconfig"; path = "Target Support Files/Pods-JellyfinPlayer tvOS/Pods-JellyfinPlayer tvOS.debug.xcconfig"; sourceTree = ""; }; E100720626BDABC100CE3E31 /* MediaPlayButtonRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPlayButtonRowView.swift; sourceTree = ""; }; E11B1B6B2718CD68006DA3E8 /* JellyfinAPIError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JellyfinAPIError.swift; sourceTree = ""; }; + E1267D3D271A1F46003C492E /* PreferenceUIHostingController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferenceUIHostingController.swift; sourceTree = ""; }; E131691626C583BC0074BFEE /* LogConstructor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogConstructor.swift; sourceTree = ""; }; E13DD3BC27163C63009D4DAF /* EmailHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailHelper.swift; sourceTree = ""; }; E13DD3BE27163DD7009D4DAF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -598,11 +588,9 @@ 6220D0C926D63F3700B8E046 /* Stinsen in Frameworks */, 53A431BF266B0FFE0016769F /* JellyfinAPI in Frameworks */, 535870912669D7A800D05A09 /* Introspect in Frameworks */, - 6261A0E026A0AB710072EF1C /* CombineExt in Frameworks */, 536D3D84267BEA550004248C /* ParallaxView in Frameworks */, 53ABFDDC267972BF00886593 /* TVServices.framework in Frameworks */, E13DD3CD27164CA7009D4DAF /* CoreStore in Frameworks */, - 5358709B2669D7A800D05A09 /* NukeUI in Frameworks */, E12186DE2718F1C50010884C /* Defaults in Frameworks */, 53ABFDED26799D7700886593 /* ActivityIndicator in Frameworks */, ); @@ -615,13 +603,13 @@ E13DD3D327168E65009D4DAF /* Defaults in Frameworks */, 53649AAD269CFAEA00A2D8B7 /* Puppy in Frameworks */, 62C29E9C26D0FE4200C1D2E7 /* Stinsen in Frameworks */, - 53EC6E25267EB10F006DD26A /* SwiftyJSON in Frameworks */, 53EC6E21267E80B1006DD26A /* Pods_JellyfinPlayer_iOS.framework in Frameworks */, + E1218C9A271A26BA00EA0737 /* Nuke in Frameworks */, + E1B6DCEA271A23880015B715 /* SwiftyJSON in Frameworks */, 53352571265EA0A0006CCA86 /* Introspect in Frameworks */, E13DD3C62716499E009D4DAF /* CoreStore in Frameworks */, - 621C638026672A30004216EA /* NukeUI in Frameworks */, 625CB57A2678C4A400530A6E /* ActivityIndicator in Frameworks */, - 6260FFF926A09754003FA968 /* CombineExt in Frameworks */, + E1B6DCE8271A23780015B715 /* CombineExt in Frameworks */, 53A431BD266B0FF20016769F /* JellyfinAPI in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -630,7 +618,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 628B95332670CAEA0091AF3B /* NukeUI in Frameworks */, 628B95242670CABD0091AF3B /* SwiftUI.framework in Frameworks */, 531ABF6C2671F5CC00C0FE20 /* WidgetKit.framework in Frameworks */, E13DD3DD27175CE3009D4DAF /* Defaults in Frameworks */, @@ -638,6 +625,7 @@ 536D3D7D267BD5F90004248C /* ActivityIndicator in Frameworks */, E13DD3CF27164E1F009D4DAF /* CoreStore in Frameworks */, 628B95352670CAEA0091AF3B /* JellyfinAPI in Frameworks */, + E1218C9C271A26C400EA0737 /* Nuke in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -687,7 +675,6 @@ E173DA5326D050F500CC4EB7 /* ServerDetailViewModel.swift */, E13DD3E027176BD3009D4DAF /* ServerListViewModel.swift */, 5321753A2671BCFC005491E6 /* SettingsViewModel.swift */, - 625CB5692678B71200530A6E /* SplashViewModel.swift */, E13DD3F82717E961009D4DAF /* UserListViewModel.swift */, E13DD3EB27178A54009D4DAF /* UserSignInViewModel.swift */, 09389CC626819B4500AE350E /* VideoPlayerModel.swift */, @@ -748,11 +735,9 @@ children = ( E12186DF2718F2030010884C /* App */, 535870662669D21700D05A09 /* Assets.xcassets */, - E193D4DD27193DC400900D82 /* Coordinators */, 536D3D77267BB9650004248C /* Components */, 535870702669D21700D05A09 /* Info.plist */, 535870682669D21700D05A09 /* Preview Content */, - 531690F8267AD135005D8AB9 /* README.md */, E12186E02718F23B0010884C /* Views */, ); path = "JellyfinPlayer tvOS"; @@ -804,11 +789,12 @@ isa = PBXGroup; children = ( 531690F6267ACC00005D8AB9 /* LandscapeItemElement.swift */, + E100720626BDABC100CE3E31 /* MediaPlayButtonRowView.swift */, + 53272531268BF09D0035FBF1 /* MediaViewActionButton.swift */, + 53116A18268B947A003024C9 /* PlainLinkButton.swift */, + 531690F9267AD6EC005D8AB9 /* PlainNavigationLinkButton.swift */, 536D3D80267BDFC60004248C /* PortraitItemElement.swift */, 536D3D87267C17350004248C /* PublicUserButton.swift */, - 53116A18268B947A003024C9 /* PlainLinkButton.swift */, - 53272531268BF09D0035FBF1 /* MediaViewActionButton.swift */, - E100720626BDABC100CE3E31 /* MediaPlayButtonRowView.swift */, ); path = Components; sourceTree = ""; @@ -1126,13 +1112,10 @@ C4E508172703E8190045C9AB /* LibraryListView.swift */, C4E5081C2703F8370045C9AB /* LibrarySearchView.swift */, 53A83C32268A309300DF3D92 /* LibraryView.swift */, - 531690E4267ABD5C005D8AB9 /* MainTabView.swift */, 531690EE267ABF72005D8AB9 /* NextUpView.swift */, - 531690F9267AD6EC005D8AB9 /* PlainNavigationLinkButton.swift */, E193D54F2719430400900D82 /* ServerDetailView.swift */, E193D54A271941D300900D82 /* ServerListView.swift */, 5398514426B64DA100101B49 /* SettingsView.swift */, - 53ABFDDD267974E300886593 /* SplashView.swift */, E193D546271941C500900D82 /* UserListView.swift */, E193D548271941CC00900D82 /* UserSignInView.swift */, 5310694F2684E7EE00CFFDBA /* VideoPlayer */, @@ -1143,9 +1126,10 @@ E13DD3BB27163C3E009D4DAF /* App */ = { isa = PBXGroup; children = ( - 5377CBF4263B596A003A4E83 /* JellyfinPlayerApp.swift */, E13DD3BE27163DD7009D4DAF /* AppDelegate.swift */, E13DD3BC27163C63009D4DAF /* EmailHelper.swift */, + 5377CBF4263B596A003A4E83 /* JellyfinPlayerApp.swift */, + E1267D3D271A1F46003C492E /* PreferenceUIHostingController.swift */, ); path = App; sourceTree = ""; @@ -1177,7 +1161,6 @@ E173DA4F26D048D600CC4EB7 /* ServerDetailView.swift */, E13DD3E427177D15009D4DAF /* ServerListView.swift */, 539B2DA4263BA5B8007FF1A4 /* SettingsView.swift */, - 625CB5672678B6FB00530A6E /* SplashView.swift */, E13DD3FB2717EAE8009D4DAF /* UserListView.swift */, E13DD3F4271793BB009D4DAF /* UserSignInView.swift */, E193D5452719418B00900D82 /* VideoPlayer */, @@ -1214,13 +1197,6 @@ path = Landscape; sourceTree = ""; }; - E193D4DD27193DC400900D82 /* Coordinators */ = { - isa = PBXGroup; - children = ( - ); - path = Coordinators; - sourceTree = ""; - }; E193D5412719404B00900D82 /* MainCoordinator */ = { isa = PBXGroup; children = ( @@ -1311,12 +1287,10 @@ name = "JellyfinPlayer tvOS"; packageProductDependencies = ( 535870902669D7A800D05A09 /* Introspect */, - 5358709A2669D7A800D05A09 /* NukeUI */, 53A431BE266B0FFE0016769F /* JellyfinAPI */, 53ABFDEC26799D7700886593 /* ActivityIndicator */, 536D3D83267BEA550004248C /* ParallaxView */, 53649AAE269CFAF600A2D8B7 /* Puppy */, - 6261A0DF26A0AB710072EF1C /* CombineExt */, 6220D0C826D63F3700B8E046 /* Stinsen */, E13DD3CC27164CA7009D4DAF /* CoreStore */, E12186DD2718F1C50010884C /* Defaults */, @@ -1346,15 +1320,15 @@ name = "JellyfinPlayer iOS"; packageProductDependencies = ( 53352570265EA0A0006CCA86 /* Introspect */, - 621C637F26672A30004216EA /* NukeUI */, 53A431BC266B0FF20016769F /* JellyfinAPI */, 625CB5792678C4A400530A6E /* ActivityIndicator */, - 53EC6E24267EB10F006DD26A /* SwiftyJSON */, 53649AAC269CFAEA00A2D8B7 /* Puppy */, - 6260FFF826A09754003FA968 /* CombineExt */, 62C29E9B26D0FE4200C1D2E7 /* Stinsen */, E13DD3C52716499E009D4DAF /* CoreStore */, E13DD3D227168E65009D4DAF /* Defaults */, + E1B6DCE7271A23780015B715 /* CombineExt */, + E1B6DCE9271A23880015B715 /* SwiftyJSON */, + E1218C99271A26BA00EA0737 /* Nuke */, ); productName = JellyfinPlayer; productReference = 5377CBF1263B596A003A4E83 /* JellyfinPlayer iOS.app */; @@ -1374,12 +1348,12 @@ ); name = WidgetExtension; packageProductDependencies = ( - 628B95322670CAEA0091AF3B /* NukeUI */, 628B95342670CAEA0091AF3B /* JellyfinAPI */, 536D3D7C267BD5F90004248C /* ActivityIndicator */, 53649AB4269D423A00A2D8B7 /* Puppy */, E13DD3CE27164E1F009D4DAF /* CoreStore */, E13DD3DC27175CE3009D4DAF /* Defaults */, + E1218C9B271A26C400EA0737 /* Nuke */, ); productName = WidgetExtensionExtension; productReference = 628B95202670CABD0091AF3B /* WidgetExtension.appex */; @@ -1433,16 +1407,16 @@ mainGroup = 5377CBE8263B596A003A4E83; packageReferences = ( 5335256F265EA0A0006CCA86 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */, - 621C637E26672A30004216EA /* XCRemoteSwiftPackageReference "NukeUI" */, 53A431BB266B0FF20016769F /* XCRemoteSwiftPackageReference "jellyfin-sdk-swift" */, 625CB5782678C4A400530A6E /* XCRemoteSwiftPackageReference "ActivityIndicator" */, 536D3D82267BEA550004248C /* XCRemoteSwiftPackageReference "ParallaxView" */, - 53EC6E23267EB10F006DD26A /* XCRemoteSwiftPackageReference "SwiftyJSON" */, 53649AAB269CFAEA00A2D8B7 /* XCRemoteSwiftPackageReference "Puppy" */, - 6260FFF726A09754003FA968 /* XCRemoteSwiftPackageReference "CombineExt" */, 62C29E9A26D0FE4100C1D2E7 /* XCRemoteSwiftPackageReference "stinsen" */, E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */, E13DD3D127168E65009D4DAF /* XCRemoteSwiftPackageReference "Defaults" */, + E1267D42271A212C003C492E /* XCRemoteSwiftPackageReference "CombineExt" */, + E1C16B89271A2180009A5D25 /* XCRemoteSwiftPackageReference "SwiftyJSON" */, + E1218C98271A26BA00EA0737 /* XCRemoteSwiftPackageReference "Nuke" */, ); productRefGroup = 5377CBF2263B596A003A4E83 /* Products */; projectDirPath = ""; @@ -1653,8 +1627,6 @@ 531690E7267ABD79005D8AB9 /* HomeView.swift in Sources */, E1D4BF8B2719D3D000A11E64 /* BasicAppSettingsCoordinator.swift in Sources */, E13DD3FA2717E961009D4DAF /* UserListViewModel.swift in Sources */, - 53ABFDDE267974E300886593 /* SplashView.swift in Sources */, - 53ABFDE8267974EF00886593 /* SplashViewModel.swift in Sources */, 62E632DE267D2E170063E547 /* LatestMediaViewModel.swift in Sources */, E1FCD09726C47118007C8DCF /* ErrorMessage.swift in Sources */, E193D53527193F8100900D82 /* ItemCoordinator.swift in Sources */, @@ -1704,7 +1676,6 @@ E1AD104E26D96CE3003E4A08 /* BaseItemDtoExtensions.swift in Sources */, 62E632DD267D2E130063E547 /* LibrarySearchViewModel.swift in Sources */, 536D3D81267BDFC60004248C /* PortraitItemElement.swift in Sources */, - 531690E5267ABD5C005D8AB9 /* MainTabView.swift in Sources */, 5310695B2684E7EE00CFFDBA /* AudioView.swift in Sources */, 5398514726B64E4100101B49 /* SearchBarView.swift in Sources */, 091B5A8D268315D400D78B61 /* ServerDiscovery.swift in Sources */, @@ -1797,7 +1768,6 @@ 625CB56F2678C23300530A6E /* HomeView.swift in Sources */, E173DA5226D04AAF00CC4EB7 /* ColorExtension.swift in Sources */, 53892770263C25230035E14B /* NextUpView.swift in Sources */, - 625CB5682678B6FB00530A6E /* SplashView.swift in Sources */, 62ECA01826FA685A00E8EBB7 /* DeepLink.swift in Sources */, 535BAEA5264A151C005FA86D /* VideoPlayer.swift in Sources */, 62E632E6267D3F5B0063E547 /* EpisodeItemViewModel.swift in Sources */, @@ -1815,7 +1785,6 @@ 53649AB1269CFB1900A2D8B7 /* LogManager.swift in Sources */, E13DD3E127176BD3009D4DAF /* ServerListViewModel.swift in Sources */, 62E632E9267D3FF50063E547 /* SeasonItemViewModel.swift in Sources */, - 625CB56A2678B71200530A6E /* SplashViewModel.swift in Sources */, 62E632F3267D54030063E547 /* ItemViewModel.swift in Sources */, E13DD3FC2717EAE8009D4DAF /* UserListView.swift in Sources */, 6220D0CC26D640C400B8E046 /* AppURLHandler.swift in Sources */, @@ -1852,6 +1821,7 @@ 535870AD2669D8DD00D05A09 /* Typings.swift in Sources */, E1AD105F26D9ADDD003E4A08 /* NameGUIDPairExtensions.swift in Sources */, E13DD3D5271693CD009D4DAF /* SwiftfinStoreDefaults.swift in Sources */, + E1267D3E271A1F46003C492E /* PreferenceUIHostingController.swift in Sources */, 6220D0BA26D6092100B8E046 /* FilterCoordinator.swift in Sources */, 6267B3DA2671138200A7371D /* ImageExtensions.swift in Sources */, 62EC353426766B03000E9F2D /* DeviceRotationViewModifier.swift in Sources */, @@ -2420,22 +2390,6 @@ kind = branch; }; }; - 53EC6E23267EB10F006DD26A /* XCRemoteSwiftPackageReference "SwiftyJSON" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/SwiftyJSON/SwiftyJSON"; - requirement = { - branch = master; - kind = branch; - }; - }; - 621C637E26672A30004216EA /* XCRemoteSwiftPackageReference "NukeUI" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/kean/NukeUI"; - requirement = { - kind = exactVersion; - version = 0.3.0; - }; - }; 625CB5782678C4A400530A6E /* XCRemoteSwiftPackageReference "ActivityIndicator" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/duyquang91/ActivityIndicator"; @@ -2444,14 +2398,6 @@ minimumVersion = 1.1.0; }; }; - 6260FFF726A09754003FA968 /* XCRemoteSwiftPackageReference "CombineExt" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/acvigue/CombineExt"; - requirement = { - branch = main; - kind = branch; - }; - }; 62C29E9A26D0FE4100C1D2E7 /* XCRemoteSwiftPackageReference "stinsen" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/rundfunk47/stinsen"; @@ -2460,12 +2406,28 @@ minimumVersion = 2.0.2; }; }; + E1218C98271A26BA00EA0737 /* XCRemoteSwiftPackageReference "Nuke" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/kean/Nuke"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 9.0.0; + }; + }; + E1267D42271A212C003C492E /* XCRemoteSwiftPackageReference "CombineExt" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/CombineCommunity/CombineExt"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.0; + }; + }; E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/JohnEstropia/CoreStore.git"; requirement = { - kind = exactVersion; - version = 8.1.0; + kind = upToNextMajorVersion; + minimumVersion = 8.1.0; }; }; E13DD3D127168E65009D4DAF /* XCRemoteSwiftPackageReference "Defaults" */ = { @@ -2476,6 +2438,14 @@ minimumVersion = 6.0.0; }; }; + E1C16B89271A2180009A5D25 /* XCRemoteSwiftPackageReference "SwiftyJSON" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/SwiftyJSON/SwiftyJSON"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 5.0.0; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -2489,11 +2459,6 @@ package = 5335256F265EA0A0006CCA86 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */; productName = Introspect; }; - 5358709A2669D7A800D05A09 /* NukeUI */ = { - isa = XCSwiftPackageProductDependency; - package = 621C637E26672A30004216EA /* XCRemoteSwiftPackageReference "NukeUI" */; - productName = NukeUI; - }; 53649AAC269CFAEA00A2D8B7 /* Puppy */ = { isa = XCSwiftPackageProductDependency; package = 53649AAB269CFAEA00A2D8B7 /* XCRemoteSwiftPackageReference "Puppy" */; @@ -2534,16 +2499,6 @@ package = 625CB5782678C4A400530A6E /* XCRemoteSwiftPackageReference "ActivityIndicator" */; productName = ActivityIndicator; }; - 53EC6E24267EB10F006DD26A /* SwiftyJSON */ = { - isa = XCSwiftPackageProductDependency; - package = 53EC6E23267EB10F006DD26A /* XCRemoteSwiftPackageReference "SwiftyJSON" */; - productName = SwiftyJSON; - }; - 621C637F26672A30004216EA /* NukeUI */ = { - isa = XCSwiftPackageProductDependency; - package = 621C637E26672A30004216EA /* XCRemoteSwiftPackageReference "NukeUI" */; - productName = NukeUI; - }; 6220D0C826D63F3700B8E046 /* Stinsen */ = { isa = XCSwiftPackageProductDependency; package = 62C29E9A26D0FE4100C1D2E7 /* XCRemoteSwiftPackageReference "stinsen" */; @@ -2554,21 +2509,6 @@ package = 625CB5782678C4A400530A6E /* XCRemoteSwiftPackageReference "ActivityIndicator" */; productName = ActivityIndicator; }; - 6260FFF826A09754003FA968 /* CombineExt */ = { - isa = XCSwiftPackageProductDependency; - package = 6260FFF726A09754003FA968 /* XCRemoteSwiftPackageReference "CombineExt" */; - productName = CombineExt; - }; - 6261A0DF26A0AB710072EF1C /* CombineExt */ = { - isa = XCSwiftPackageProductDependency; - package = 6260FFF726A09754003FA968 /* XCRemoteSwiftPackageReference "CombineExt" */; - productName = CombineExt; - }; - 628B95322670CAEA0091AF3B /* NukeUI */ = { - isa = XCSwiftPackageProductDependency; - package = 621C637E26672A30004216EA /* XCRemoteSwiftPackageReference "NukeUI" */; - productName = NukeUI; - }; 628B95342670CAEA0091AF3B /* JellyfinAPI */ = { isa = XCSwiftPackageProductDependency; package = 53A431BB266B0FF20016769F /* XCRemoteSwiftPackageReference "jellyfin-sdk-swift" */; @@ -2584,6 +2524,16 @@ package = E13DD3D127168E65009D4DAF /* XCRemoteSwiftPackageReference "Defaults" */; productName = Defaults; }; + E1218C99271A26BA00EA0737 /* Nuke */ = { + isa = XCSwiftPackageProductDependency; + package = E1218C98271A26BA00EA0737 /* XCRemoteSwiftPackageReference "Nuke" */; + productName = Nuke; + }; + E1218C9B271A26C400EA0737 /* Nuke */ = { + isa = XCSwiftPackageProductDependency; + package = E1218C98271A26BA00EA0737 /* XCRemoteSwiftPackageReference "Nuke" */; + productName = Nuke; + }; E13DD3C52716499E009D4DAF /* CoreStore */ = { isa = XCSwiftPackageProductDependency; package = E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */; @@ -2609,6 +2559,16 @@ package = E13DD3D127168E65009D4DAF /* XCRemoteSwiftPackageReference "Defaults" */; productName = Defaults; }; + E1B6DCE7271A23780015B715 /* CombineExt */ = { + isa = XCSwiftPackageProductDependency; + package = E1267D42271A212C003C492E /* XCRemoteSwiftPackageReference "CombineExt" */; + productName = CombineExt; + }; + E1B6DCE9271A23880015B715 /* SwiftyJSON */ = { + isa = XCSwiftPackageProductDependency; + package = E1C16B89271A2180009A5D25 /* XCRemoteSwiftPackageReference "SwiftyJSON" */; + productName = SwiftyJSON; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 5377CBE9263B596A003A4E83 /* Project object */; diff --git a/JellyfinPlayer.xcworkspace/xcshareddata/swiftpm/Package.resolved b/JellyfinPlayer.xcworkspace/xcshareddata/swiftpm/Package.resolved index bfb7d2f1..1edb1d0f 100644 --- a/JellyfinPlayer.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/JellyfinPlayer.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -20,21 +20,12 @@ } }, { - "package": "combine-schedulers", - "repositoryURL": "https://github.com/pointfreeco/combine-schedulers", + "package": "CombineExt", + "repositoryURL": "https://github.com/CombineCommunity/CombineExt", "state": { "branch": null, - "revision": "6bde3b0063ba8e7537b43744948535ca7e9e0dad", - "version": "0.5.2" - } - }, - { - "package": "CombineExt", - "repositoryURL": "https://github.com/acvigue/CombineExt", - "state": { - "branch": "main", - "revision": "f629c5b052d1cb5d03e10890deccc50e4c649e68", - "version": null + "revision": "0880829102152185190064fd17847a7c681d2127", + "version": "1.5.1" } }, { @@ -55,15 +46,6 @@ "version": "6.0.0" } }, - { - "package": "Gifu", - "repositoryURL": "https://github.com/kaishin/Gifu", - "state": { - "branch": null, - "revision": "51f2eab32903e336f590c013267cfa4d7f8b06c4", - "version": "3.3.1" - } - }, { "package": "JellyfinAPI", "repositoryURL": "https://github.com/jellyfin/jellyfin-sdk-swift", @@ -75,20 +57,11 @@ }, { "package": "Nuke", - "repositoryURL": "https://github.com/kean/Nuke.git", + "repositoryURL": "https://github.com/kean/Nuke", "state": { "branch": null, - "revision": "0db18dd34998cca18e9a28bcee136f84518007a0", - "version": "10.4.1" - } - }, - { - "package": "NukeUI", - "repositoryURL": "https://github.com/kean/NukeUI", - "state": { - "branch": null, - "revision": "d2580b8d22b29c6244418d8e4b568f3162191460", - "version": "0.3.0" + "revision": "7f73ceaeacd5df75a7994cd82e165ad9ff1815db", + "version": "9.6.1" } }, { @@ -139,19 +112,10 @@ { "package": "SwiftyJSON", "repositoryURL": "https://github.com/SwiftyJSON/SwiftyJSON", - "state": { - "branch": "master", - "revision": "b3dcd7dbd0d488e1a7077cb33b00f2083e382f07", - "version": null - } - }, - { - "package": "xctest-dynamic-overlay", - "repositoryURL": "https://github.com/pointfreeco/xctest-dynamic-overlay", "state": { "branch": null, - "revision": "50a70a9d3583fe228ce672e8923010c8df2deddd", - "version": "0.2.1" + "revision": "b3dcd7dbd0d488e1a7077cb33b00f2083e382f07", + "version": "5.0.1" } } ] diff --git a/JellyfinPlayer/App/AppDelegate.swift b/JellyfinPlayer/App/AppDelegate.swift index c696bf56..1da457bf 100644 --- a/JellyfinPlayer/App/AppDelegate.swift +++ b/JellyfinPlayer/App/AppDelegate.swift @@ -17,10 +17,16 @@ class AppDelegate: NSObject, UIApplicationDelegate { // Lazily initialize datastack let _ = SwiftfinStore.dataStack + setupAppearance() + return true } func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { AppDelegate.orientationLock } + + private func setupAppearance() { +// UIApplication.shared.windows.first?.overrideUserInterfaceStyle = appAppearance.style + } } diff --git a/JellyfinPlayer/App/JellyfinPlayerApp.swift b/JellyfinPlayer/App/JellyfinPlayerApp.swift index 99e0f929..8810e4ce 100644 --- a/JellyfinPlayer/App/JellyfinPlayerApp.swift +++ b/JellyfinPlayer/App/JellyfinPlayerApp.swift @@ -10,19 +10,29 @@ import MessageUI import Stinsen import SwiftUI -extension UIDevice { - var hasNotch: Bool { - let bottom = UIApplication.shared.windows.filter { $0.isKeyWindow }.first?.safeAreaInsets.bottom ?? 0 - return bottom > 0 - } -} - -extension View { - func withHostingWindow(_ callback: @escaping (UIWindow?) -> Void) -> some View { - background(HostingWindowFinder(callback: callback)) +// MARK: JellyfinPlayerApp +@main +struct JellyfinPlayerApp: App { + @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate + @Default(.appAppearance) var appAppearance + + var body: some Scene { + WindowGroup { + EmptyView() + .withHostingWindow { window in + window?.rootViewController = PreferenceUIHostingController(wrappedView: MainCoordinator().view()) + } + .onShake { + EmailHelper.shared.sendLogs(logURL: LogManager.shared.logFileURL()) + } + .onOpenURL { url in + AppURLHandler.shared.processDeepLink(url: url) + } + } } } +// MARK: Hosting Window struct HostingWindowFinder: UIViewRepresentable { var callback: (UIWindow?) -> Void @@ -37,134 +47,8 @@ struct HostingWindowFinder: UIViewRepresentable { func updateUIView(_ uiView: UIView, context: Context) {} } -struct PrefersHomeIndicatorAutoHiddenPreferenceKey: PreferenceKey { - typealias Value = Bool - - static var defaultValue: Value = false - - static func reduce(value: inout Value, nextValue: () -> Value) { - value = nextValue() || value - } -} - -struct ViewPreferenceKey: PreferenceKey { - typealias Value = UIUserInterfaceStyle - - static var defaultValue: UIUserInterfaceStyle = .unspecified - - static func reduce(value: inout UIUserInterfaceStyle, nextValue: () -> UIUserInterfaceStyle) { - value = nextValue() - } -} - -struct SupportedOrientationsPreferenceKey: PreferenceKey { - typealias Value = UIInterfaceOrientationMask - static var defaultValue: UIInterfaceOrientationMask = .allButUpsideDown - - static func reduce(value: inout UIInterfaceOrientationMask, nextValue: () -> UIInterfaceOrientationMask) { - // use the most restrictive set from the stack - value.formIntersection(nextValue()) - } -} - -class PreferenceUIHostingController: UIHostingController { - init(wrappedView: V) { - let box = Box() - super.init(rootView: AnyView(wrappedView - .onPreferenceChange(PrefersHomeIndicatorAutoHiddenPreferenceKey.self) { - box.value?._prefersHomeIndicatorAutoHidden = $0 - }.onPreferenceChange(SupportedOrientationsPreferenceKey.self) { - box.value?._orientations = $0 - }.onPreferenceChange(ViewPreferenceKey.self) { - box.value?._viewPreference = $0 - })) - box.value = self - } - - @objc dynamic required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - super.modalPresentationStyle = .fullScreen - } - - private class Box { - weak var value: PreferenceUIHostingController? - init() {} - } - - // MARK: Prefers Home Indicator Auto Hidden - - public var _prefersHomeIndicatorAutoHidden = false { - didSet { setNeedsUpdateOfHomeIndicatorAutoHidden() } - } - - override var prefersHomeIndicatorAutoHidden: Bool { - _prefersHomeIndicatorAutoHidden - } - - // MARK: Lock orientation - - public var _orientations: UIInterfaceOrientationMask = .allButUpsideDown { - didSet { - if _orientations == .landscape { - let value = UIInterfaceOrientation.landscapeRight.rawValue - UIDevice.current.setValue(value, forKey: "orientation") - UIViewController.attemptRotationToDeviceOrientation() - } - } - } - - override var supportedInterfaceOrientations: UIInterfaceOrientationMask { - _orientations - } - - public var _viewPreference: UIUserInterfaceStyle = .unspecified { - didSet { - overrideUserInterfaceStyle = _viewPreference - } - } -} - extension View { - // Controls the application's preferred home indicator auto-hiding when this view is shown. - func prefersHomeIndicatorAutoHidden(_ value: Bool) -> some View { - preference(key: PrefersHomeIndicatorAutoHiddenPreferenceKey.self, value: value) - } - - func supportedOrientations(_ supportedOrientations: UIInterfaceOrientationMask) -> some View { - // When rendered, export the requested orientations upward to Root - preference(key: SupportedOrientationsPreferenceKey.self, value: supportedOrientations) - } - - func overrideViewPreference(_ viewPreference: UIUserInterfaceStyle) -> some View { - // When rendered, export the requested orientations upward to Root - preference(key: ViewPreferenceKey.self, value: viewPreference) - } -} - -@main -struct JellyfinPlayerApp: App { - @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate - @Default(.appAppearance) var appAppearance - - var body: some Scene { - WindowGroup { - EmptyView() - .onAppear { - setupAppearance() - } - .withHostingWindow { window in - window?.rootViewController = PreferenceUIHostingController(wrappedView: MainCoordinator().view()) - } - .onShake { - EmailHelper.shared.sendLogs(logURL: LogManager.shared.logFileURL()) - } - .onOpenURL { url in - AppURLHandler.shared.processDeepLink(url: url) - } - } - } - - private func setupAppearance() { - UIApplication.shared.windows.first?.overrideUserInterfaceStyle = appAppearance.style + func withHostingWindow(_ callback: @escaping (UIWindow?) -> Void) -> some View { + background(HostingWindowFinder(callback: callback)) } } diff --git a/JellyfinPlayer/App/PreferenceUIHostingController.swift b/JellyfinPlayer/App/PreferenceUIHostingController.swift new file mode 100644 index 00000000..d6146c75 --- /dev/null +++ b/JellyfinPlayer/App/PreferenceUIHostingController.swift @@ -0,0 +1,118 @@ +// + /* + * 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 UIKit +import SwiftUI + +// MARK: PreferenceUIHostingController +class PreferenceUIHostingController: UIHostingController { + init(wrappedView: V) { + let box = Box() + super.init(rootView: AnyView(wrappedView + .onPreferenceChange(PrefersHomeIndicatorAutoHiddenPreferenceKey.self) { + box.value?._prefersHomeIndicatorAutoHidden = $0 + }.onPreferenceChange(SupportedOrientationsPreferenceKey.self) { + box.value?._orientations = $0 + }.onPreferenceChange(ViewPreferenceKey.self) { + box.value?._viewPreference = $0 + })) + box.value = self + } + + @objc dynamic required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + super.modalPresentationStyle = .fullScreen + } + + private class Box { + weak var value: PreferenceUIHostingController? + init() {} + } + + // MARK: Prefers Home Indicator Auto Hidden + + public var _prefersHomeIndicatorAutoHidden = false { + didSet { setNeedsUpdateOfHomeIndicatorAutoHidden() } + } + + override var prefersHomeIndicatorAutoHidden: Bool { + _prefersHomeIndicatorAutoHidden + } + + // MARK: Lock orientation + + public var _orientations: UIInterfaceOrientationMask = .allButUpsideDown { + didSet { + if _orientations == .landscape { + let value = UIInterfaceOrientation.landscapeRight.rawValue + UIDevice.current.setValue(value, forKey: "orientation") + UIViewController.attemptRotationToDeviceOrientation() + } + } + } + + override var supportedInterfaceOrientations: UIInterfaceOrientationMask { + _orientations + } + + public var _viewPreference: UIUserInterfaceStyle = .unspecified { + didSet { + overrideUserInterfaceStyle = _viewPreference + } + } +} + +// MARK: Preference Keys +struct PrefersHomeIndicatorAutoHiddenPreferenceKey: PreferenceKey { + typealias Value = Bool + + static var defaultValue: Value = false + + static func reduce(value: inout Value, nextValue: () -> Value) { + value = nextValue() || value + } +} + +struct ViewPreferenceKey: PreferenceKey { + typealias Value = UIUserInterfaceStyle + + static var defaultValue: UIUserInterfaceStyle = .unspecified + + static func reduce(value: inout UIUserInterfaceStyle, nextValue: () -> UIUserInterfaceStyle) { + value = nextValue() + } +} + +struct SupportedOrientationsPreferenceKey: PreferenceKey { + typealias Value = UIInterfaceOrientationMask + static var defaultValue: UIInterfaceOrientationMask = .allButUpsideDown + + static func reduce(value: inout UIInterfaceOrientationMask, nextValue: () -> UIInterfaceOrientationMask) { + // use the most restrictive set from the stack + value.formIntersection(nextValue()) + } +} + +// MARK: Preference Key View Extension +extension View { + // Controls the application's preferred home indicator auto-hiding when this view is shown. + func prefersHomeIndicatorAutoHidden(_ value: Bool) -> some View { + preference(key: PrefersHomeIndicatorAutoHiddenPreferenceKey.self, value: value) + } + + func supportedOrientations(_ supportedOrientations: UIInterfaceOrientationMask) -> some View { + // When rendered, export the requested orientations upward to Root + preference(key: SupportedOrientationsPreferenceKey.self, value: supportedOrientations) + } + + func overrideViewPreference(_ viewPreference: UIUserInterfaceStyle) -> some View { + // When rendered, export the requested orientations upward to Root + preference(key: ViewPreferenceKey.self, value: viewPreference) + } +} diff --git a/JellyfinPlayer/Views/SplashView.swift b/JellyfinPlayer/Views/SplashView.swift deleted file mode 100644 index fd099537..00000000 --- a/JellyfinPlayer/Views/SplashView.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -/* - * 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 Stinsen -import SwiftUI - -struct SplashView: View { - @EnvironmentObject var mainRouter: MainCoordinator.Router - @StateObject var viewModel = SplashViewModel() - - var body: some View { - ProgressView() - .onReceive(viewModel.$isLoggedIn) { flag in - if flag { - mainRouter.root(\.mainTab) - } else { - mainRouter.root(\.serverList) - } - } - } -} diff --git a/Shared/ViewModels/ConnectToServerViewModel.swift b/Shared/ViewModels/ConnectToServerViewModel.swift index ac03ec61..85dfc7a9 100644 --- a/Shared/ViewModels/ConnectToServerViewModel.swift +++ b/Shared/ViewModels/ConnectToServerViewModel.swift @@ -53,7 +53,7 @@ final class ConnectToServerViewModel: ViewModel { discoveredServers.removeAll() searching = true - // Timeout after 5 seconds + // Timeout after 3 seconds DispatchQueue.main.asyncAfter(deadline: .now() + 3) { self.searching = false } diff --git a/Shared/ViewModels/SplashViewModel.swift b/Shared/ViewModels/SplashViewModel.swift deleted file mode 100644 index 22d2c308..00000000 --- a/Shared/ViewModels/SplashViewModel.swift +++ /dev/null @@ -1,51 +0,0 @@ -// - /* - * 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 Foundation -import Combine -import Nuke -import UIKit - -#if !os(tvOS) -import WidgetKit -#endif - -// TODO: Remove SplashViewModel - -final class SplashViewModel: ViewModel { - - @Published var isLoggedIn: Bool = false - - override init() { - isLoggedIn = SessionManager.main.currentLogin != nil - super.init() - - ImageCache.shared.costLimit = 125 * 1024 * 1024 // 125MB memory - DataLoader.sharedUrlCache.diskCapacity = 1000 * 1024 * 1024 // 1000MB disk - - #if !os(tvOS) - WidgetCenter.shared.reloadAllTimelines() - UIScrollView.appearance().keyboardDismissMode = .onDrag - #endif - - let nc = NotificationCenter.default - nc.addObserver(self, selector: #selector(didLogIn), name: Notification.Name("didSignIn"), object: nil) - nc.addObserver(self, selector: #selector(didLogOut), name: Notification.Name("didSignOut"), object: nil) - } - - @objc func didLogIn() { - LogManager.shared.log.info("Received `didSignIn` from NSNotificationCenter.") - isLoggedIn = true - } - - @objc func didLogOut() { - LogManager.shared.log.info("Received `didSignOut` from NSNotificationCenter.") - isLoggedIn = false - } -} diff --git a/Shared/Views/ImageView.swift b/Shared/Views/ImageView.swift index 1acfc099..10044b21 100644 --- a/Shared/Views/ImageView.swift +++ b/Shared/Views/ImageView.swift @@ -8,7 +8,6 @@ */ import SwiftUI -import NukeUI struct ImageView: View { private let source: URL @@ -20,21 +19,35 @@ struct ImageView: View { self.blurhash = bh self.failureInitials = failureInitials } + + @ViewBuilder + private var placeholderImage: some View { + Image(uiImage: UIImage(blurHash: blurhash, size: CGSize(width: 8, height: 8)) ?? UIImage(blurHash: "001fC^", size: CGSize(width: 8, height: 8))!) + .resizable() + } + + @ViewBuilder + private var failureImage: some View { + ZStack { + Rectangle() + .foregroundColor(Color.systemFill) + + Text(failureInitials) + .font(.largeTitle) + .foregroundColor(.secondary) + } + } var body: some View { - LazyImage(source: source) - .placeholder { - Image(uiImage: UIImage(blurHash: blurhash, size: CGSize(width: 8, height: 8)) ?? UIImage(blurHash: "001fC^", size: CGSize(width: 8, height: 8))!) - .resizable() - } - .failure { - ZStack { - Rectangle() - .foregroundColor(Color.systemFill) - - Text(failureInitials) - .font(.largeTitle) - .foregroundColor(.secondary) + AsyncImage(url: source) { phase in + if let image = phase.image { + image + .resizable() + .aspectRatio(contentMode: .fill) + } else if phase.error != nil { + failureImage + } else { + placeholderImage } } }