diff --git a/JellyfinPlayer.xcodeproj/project.pbxproj b/JellyfinPlayer.xcodeproj/project.pbxproj index 512282c8..17dd0180 100644 --- a/JellyfinPlayer.xcodeproj/project.pbxproj +++ b/JellyfinPlayer.xcodeproj/project.pbxproj @@ -62,7 +62,6 @@ 5358708D2669D7A800D05A09 /* KeychainSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 5358708C2669D7A800D05A09 /* KeychainSwift */; }; 535870912669D7A800D05A09 /* Introspect in Frameworks */ = {isa = PBXBuildFile; productRef = 535870902669D7A800D05A09 /* Introspect */; }; 5358709B2669D7A800D05A09 /* NukeUI in Frameworks */ = {isa = PBXBuildFile; productRef = 5358709A2669D7A800D05A09 /* NukeUI */; }; - 535870A32669D89F00D05A09 /* Model.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 5377CBFF263B596B003A4E83 /* Model.xcdatamodeld */; }; 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 */; }; @@ -91,7 +90,6 @@ 5377CBF5263B596A003A4E83 /* JellyfinPlayerApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5377CBF4263B596A003A4E83 /* JellyfinPlayerApp.swift */; }; 5377CBF9263B596B003A4E83 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5377CBF8263B596B003A4E83 /* Assets.xcassets */; }; 5377CBFC263B596B003A4E83 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5377CBFB263B596B003A4E83 /* Preview Assets.xcassets */; }; - 5377CC01263B596B003A4E83 /* Model.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 5377CBFF263B596B003A4E83 /* Model.xcdatamodeld */; }; 5389276E263C25100035E14B /* ContinueWatchingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5389276D263C25100035E14B /* ContinueWatchingView.swift */; }; 53892770263C25230035E14B /* NextUpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5389276F263C25230035E14B /* NextUpView.swift */; }; 53892772263C8C6F0035E14B /* LoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53892771263C8C6F0035E14B /* LoadingView.swift */; }; @@ -205,7 +203,6 @@ 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 */; }; - 628B95382670CDAB0091AF3B /* Model.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 5377CBFF263B596B003A4E83 /* Model.xcdatamodeld */; }; 628B953A2670CE250091AF3B /* KeychainSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 628B95392670CE250091AF3B /* KeychainSwift */; }; 628B953C2670D2430091AF3B /* StringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621338922660107500A81A2A /* StringExtensions.swift */; }; 62C29E9C26D0FE4200C1D2E7 /* Stinsen in Frameworks */ = {isa = PBXBuildFile; productRef = 62C29E9B26D0FE4200C1D2E7 /* Stinsen */; }; @@ -263,9 +260,6 @@ E13DD3D5271693CD009D4DAF /* SwiftfinStoreDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3D4271693CD009D4DAF /* SwiftfinStoreDefaults.swift */; }; E13DD3D6271693CD009D4DAF /* SwiftfinStoreDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3D4271693CD009D4DAF /* SwiftfinStoreDefaults.swift */; }; E13DD3D7271693CD009D4DAF /* SwiftfinStoreDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3D4271693CD009D4DAF /* SwiftfinStoreDefaults.swift */; }; - E13DD3D927169406009D4DAF /* SwiftfinStoreKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3D827169406009D4DAF /* SwiftfinStoreKeychain.swift */; }; - E13DD3DA27169406009D4DAF /* SwiftfinStoreKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3D827169406009D4DAF /* SwiftfinStoreKeychain.swift */; }; - E13DD3DB27169406009D4DAF /* SwiftfinStoreKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3D827169406009D4DAF /* SwiftfinStoreKeychain.swift */; }; E13DD3DD27175CE3009D4DAF /* Defaults in Frameworks */ = {isa = PBXBuildFile; productRef = E13DD3DC27175CE3009D4DAF /* Defaults */; }; E13DD3DF27175CEA009D4DAF /* Defaults in Frameworks */ = {isa = PBXBuildFile; productRef = E13DD3DE27175CEA009D4DAF /* Defaults */; }; E13DD3E127176BD3009D4DAF /* ServerListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3E027176BD3009D4DAF /* ServerListViewModel.swift */; }; @@ -276,12 +270,13 @@ E13DD3EA27177ED6009D4DAF /* ServerListCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3E827177ED6009D4DAF /* ServerListCoordinator.swift */; }; E13DD3EC27178A54009D4DAF /* UserLoginViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3EB27178A54009D4DAF /* UserLoginViewModel.swift */; }; E13DD3ED27178A54009D4DAF /* UserLoginViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3EB27178A54009D4DAF /* UserLoginViewModel.swift */; }; - E13DD3EF27178F87009D4DAF /* NotificationCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3EE27178F87009D4DAF /* NotificationCenter.swift */; }; - E13DD3F027178F87009D4DAF /* NotificationCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3EE27178F87009D4DAF /* NotificationCenter.swift */; }; + E13DD3EF27178F87009D4DAF /* SwiftfinNotificationCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3EE27178F87009D4DAF /* SwiftfinNotificationCenter.swift */; }; + E13DD3F027178F87009D4DAF /* SwiftfinNotificationCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3EE27178F87009D4DAF /* SwiftfinNotificationCenter.swift */; }; E13DD3F227179378009D4DAF /* UserLoginCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3F127179378009D4DAF /* UserLoginCoordinator.swift */; }; E13DD3F327179378009D4DAF /* UserLoginCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3F127179378009D4DAF /* UserLoginCoordinator.swift */; }; E13DD3F5271793BB009D4DAF /* UserLoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3F4271793BB009D4DAF /* UserLoginView.swift */; }; E13DD3F6271793BB009D4DAF /* UserLoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3F4271793BB009D4DAF /* UserLoginView.swift */; }; + E13DD3F72717E87D009D4DAF /* SwiftfinNotificationCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3EE27178F87009D4DAF /* SwiftfinNotificationCenter.swift */; }; E14F7D0726DB36EF007C3AE6 /* ItemPortraitMainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E14F7D0626DB36EF007C3AE6 /* ItemPortraitMainView.swift */; }; E14F7D0926DB36F7007C3AE6 /* ItemLandscapeMainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E14F7D0826DB36F7007C3AE6 /* ItemLandscapeMainView.swift */; }; E173DA5026D048D600CC4EB7 /* ServerDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E173DA4F26D048D600CC4EB7 /* ServerDetailView.swift */; }; @@ -418,7 +413,6 @@ 5377CBF4263B596A003A4E83 /* JellyfinPlayerApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JellyfinPlayerApp.swift; sourceTree = ""; }; 5377CBF8263B596B003A4E83 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 5377CBFB263B596B003A4E83 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; - 5377CC00263B596B003A4E83 /* JellyfinPlayer.xcdatamodel */ = {isa = PBXFileReference; explicitFileType = wrapper.xcdatamodel; path = JellyfinPlayer.xcdatamodel; sourceTree = ""; }; 5377CC02263B596B003A4E83 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 5389276D263C25100035E14B /* ContinueWatchingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContinueWatchingView.swift; sourceTree = ""; }; 5389276F263C25230035E14B /* NextUpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextUpView.swift; sourceTree = ""; }; @@ -518,12 +512,11 @@ E13DD3C127164941009D4DAF /* SwiftfinStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftfinStore.swift; sourceTree = ""; }; E13DD3C727164B1E009D4DAF /* UIDeviceExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIDeviceExtensions.swift; sourceTree = ""; }; E13DD3D4271693CD009D4DAF /* SwiftfinStoreDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftfinStoreDefaults.swift; sourceTree = ""; }; - E13DD3D827169406009D4DAF /* SwiftfinStoreKeychain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftfinStoreKeychain.swift; sourceTree = ""; }; E13DD3E027176BD3009D4DAF /* ServerListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerListViewModel.swift; sourceTree = ""; }; E13DD3E427177D15009D4DAF /* ServerListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerListView.swift; sourceTree = ""; }; E13DD3E827177ED6009D4DAF /* ServerListCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerListCoordinator.swift; sourceTree = ""; }; E13DD3EB27178A54009D4DAF /* UserLoginViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserLoginViewModel.swift; sourceTree = ""; }; - E13DD3EE27178F87009D4DAF /* NotificationCenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationCenter.swift; sourceTree = ""; }; + E13DD3EE27178F87009D4DAF /* SwiftfinNotificationCenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftfinNotificationCenter.swift; sourceTree = ""; }; E13DD3F127179378009D4DAF /* UserLoginCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserLoginCoordinator.swift; sourceTree = ""; }; E13DD3F4271793BB009D4DAF /* UserLoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserLoginView.swift; sourceTree = ""; }; E14F7D0626DB36EF007C3AE6 /* ItemPortraitMainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemPortraitMainView.swift; sourceTree = ""; }; @@ -1049,9 +1042,9 @@ isa = PBXGroup; children = ( 536D3D73267BA8170004248C /* BackgroundManager.swift */, - E13DD3EE27178F87009D4DAF /* NotificationCenter.swift */, 53649AB0269CFB1900A2D8B7 /* LogManager.swift */, 62EC352E267666A5000E9F2D /* SessionManager.swift */, + E13DD3EE27178F87009D4DAF /* SwiftfinNotificationCenter.swift */, ); path = Singleton; sourceTree = ""; @@ -1069,7 +1062,6 @@ isa = PBXGroup; children = ( AE8C3158265D6F90008AA076 /* bitrates.json */, - 5377CBFF263B596B003A4E83 /* Model.xcdatamodeld */, ); path = Resources; sourceTree = ""; @@ -1100,7 +1092,6 @@ children = ( E13DD3C127164941009D4DAF /* SwiftfinStore.swift */, E13DD3D4271693CD009D4DAF /* SwiftfinStoreDefaults.swift */, - E13DD3D827169406009D4DAF /* SwiftfinStoreKeychain.swift */, ); path = SwiftfinStore; sourceTree = ""; @@ -1553,8 +1544,7 @@ C4E5081D2703F8370045C9AB /* LibrarySearchView.swift in Sources */, 53ABFDE9267974EF00886593 /* HomeViewModel.swift in Sources */, 53116A17268B919A003024C9 /* SeriesItemView.swift in Sources */, - E13DD3F027178F87009D4DAF /* NotificationCenter.swift in Sources */, - E13DD3DA27169406009D4DAF /* SwiftfinStoreKeychain.swift in Sources */, + E13DD3F027178F87009D4DAF /* SwiftfinNotificationCenter.swift in Sources */, 531690E7267ABD79005D8AB9 /* HomeView.swift in Sources */, 53ABFDDE267974E300886593 /* SplashView.swift in Sources */, 53ABFDE8267974EF00886593 /* SplashViewModel.swift in Sources */, @@ -1636,7 +1626,6 @@ E131691826C583BC0074BFEE /* LogConstructor.swift in Sources */, E1AD105726D981CE003E4A08 /* PortraitHStackView.swift in Sources */, E13DD3C327164941009D4DAF /* SwiftfinStore.swift in Sources */, - 535870A32669D89F00D05A09 /* Model.xcdatamodeld in Sources */, 09389CC826819B4600AE350E /* VideoPlayerModel.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1693,7 +1682,6 @@ 532E68CF267D9F6B007B9F13 /* VideoPlayerCastDeviceSelector.swift in Sources */, E14F7D0926DB36F7007C3AE6 /* ItemLandscapeMainView.swift in Sources */, 532175402671EE4F005491E6 /* LibraryFilterView.swift in Sources */, - 5377CC01263B596B003A4E83 /* Model.xcdatamodeld in Sources */, 53DF641E263D9C0600A7CD1A /* LibraryView.swift in Sources */, E188460026DECB9E00B0C5B7 /* ItemLandscapeTopBarView.swift in Sources */, 091B5A8B2683142E00D78B61 /* UDPBroadCastConnection.swift in Sources */, @@ -1727,7 +1715,6 @@ 62E632E3267D3BA60063E547 /* MovieItemViewModel.swift in Sources */, 091B5A8A2683142E00D78B61 /* ServerDiscovery.swift in Sources */, 62E632EF267D43320063E547 /* LibraryFilterViewModel.swift in Sources */, - E13DD3D927169406009D4DAF /* SwiftfinStoreKeychain.swift in Sources */, E13DD3C827164B1E009D4DAF /* UIDeviceExtensions.swift in Sources */, E1AD104D26D96CE3003E4A08 /* BaseItemDtoExtensions.swift in Sources */, E13DD3BF27163DD7009D4DAF /* AppDelegate.swift in Sources */, @@ -1742,7 +1729,7 @@ 5338F74E263B61370014BF09 /* ConnectToServerView.swift in Sources */, 09389CC726819B4600AE350E /* VideoPlayerModel.swift in Sources */, 6220D0B726D5EE1100B8E046 /* SearchCoordinator.swift in Sources */, - E13DD3EF27178F87009D4DAF /* NotificationCenter.swift in Sources */, + E13DD3EF27178F87009D4DAF /* SwiftfinNotificationCenter.swift in Sources */, 5377CBF5263B596A003A4E83 /* JellyfinPlayerApp.swift in Sources */, E1FCD09626C47118007C8DCF /* ErrorMessage.swift in Sources */, 53EE24E6265060780068F029 /* LibrarySearchView.swift in Sources */, @@ -1765,13 +1752,12 @@ E1AD105426D97161003E4A08 /* BaseItemDtoExtensions.swift in Sources */, E1FCD09A26C4F35A007C8DCF /* ErrorMessage.swift in Sources */, 628B95272670CABD0091AF3B /* NextUpWidget.swift in Sources */, + E13DD3F72717E87D009D4DAF /* SwiftfinNotificationCenter.swift in Sources */, 6220D0AF26D5EABE00B8E046 /* ViewExtensions.swift in Sources */, - 628B95382670CDAB0091AF3B /* Model.xcdatamodeld in Sources */, E13DD3D7271693CD009D4DAF /* SwiftfinStoreDefaults.swift in Sources */, E1FCD09926C4F358007C8DCF /* NetworkError.swift in Sources */, E131691926C583BC0074BFEE /* LogConstructor.swift in Sources */, E13DD3CA27164B80009D4DAF /* SwiftfinStore.swift in Sources */, - E13DD3DB27169406009D4DAF /* SwiftfinStoreKeychain.swift in Sources */, 62EC353226766849000E9F2D /* SessionManager.swift in Sources */, 536D3D79267BD5D00004248C /* ViewModel.swift in Sources */, ); @@ -2526,19 +2512,6 @@ productName = Defaults; }; /* End XCSwiftPackageProductDependency section */ - -/* Begin XCVersionGroup section */ - 5377CBFF263B596B003A4E83 /* Model.xcdatamodeld */ = { - isa = XCVersionGroup; - children = ( - 5377CC00263B596B003A4E83 /* JellyfinPlayer.xcdatamodel */, - ); - currentVersion = 5377CC00263B596B003A4E83 /* JellyfinPlayer.xcdatamodel */; - path = Model.xcdatamodeld; - sourceTree = ""; - versionGroupType = wrapper.xcdatamodel; - }; -/* End XCVersionGroup section */ }; rootObject = 5377CBE9263B596A003A4E83 /* Project object */; } diff --git a/JellyfinPlayer/Coordinators/ConnectToServerCoodinator.swift b/JellyfinPlayer/Coordinators/ConnectToServerCoodinator.swift index 4d3c49e0..a191313d 100644 --- a/JellyfinPlayer/Coordinators/ConnectToServerCoodinator.swift +++ b/JellyfinPlayer/Coordinators/ConnectToServerCoodinator.swift @@ -17,7 +17,7 @@ final class ConnectToServerCoodinator: NavigationCoordinatable { @Root var start = makeStart @Route(.push) var userLogin = makeUserLogin - func makeUserLogin(server: SwiftfinStore.Models.Server) -> UserLoginCoordinator { + func makeUserLogin(server: SwiftfinStore.State.Server) -> UserLoginCoordinator { return UserLoginCoordinator(viewModel: .init(server: server)) } diff --git a/JellyfinPlayer/VideoPlayer.swift b/JellyfinPlayer/VideoPlayer.swift index 3585c916..cddd460e 100644 --- a/JellyfinPlayer/VideoPlayer.swift +++ b/JellyfinPlayer/VideoPlayer.swift @@ -877,7 +877,7 @@ extension PlayerViewController: GCKGenericChannelDelegate { "command": command, "userId": SessionManager.main.currentLogin.user.id, // "deviceId": SessionManager.main.currentLogin.de.deviceID, - "accessToken": SessionManager.main.currentLogin.user.accessToken?.value ?? "", + "accessToken": SessionManager.main.currentLogin.user.accessToken, "serverAddress": SessionManager.main.currentLogin.server.uri, "serverId": SessionManager.main.currentLogin.server.id, "serverVersion": "10.8.0", diff --git a/JellyfinPlayer/Views/ServerListView.swift b/JellyfinPlayer/Views/ServerListView.swift index 3fa614f9..08167846 100644 --- a/JellyfinPlayer/Views/ServerListView.swift +++ b/JellyfinPlayer/Views/ServerListView.swift @@ -34,18 +34,18 @@ struct ServerListView: View { Button { SwiftfinStore.dataStack.perform(asynchronous: { transaction in - try! transaction.deleteAll(From()) - try! transaction.deleteAll(From()) - try! transaction.deleteAll(From()) + try! transaction.deleteAll(From()) + try! transaction.deleteAll(From()) + try! transaction.deleteAll(From()) }) { _ in - viewModel.servers = [] + SwiftfinStore.Defaults.suite[.lastServerUserID] = nil + viewModel.fetchServers() } } label: { Text("Purge") } } } - // ToolbarItem(placement: .navigationBarTrailing) { // Button { // serverListRouter.route(to: \.connectToServer) @@ -54,5 +54,8 @@ struct ServerListView: View { // } // } } + .onAppear { + viewModel.fetchServers() + } } } diff --git a/JellyfinPlayer/Views/SettingsView.swift b/JellyfinPlayer/Views/SettingsView.swift index 197bbe61..60faeee8 100644 --- a/JellyfinPlayer/Views/SettingsView.swift +++ b/JellyfinPlayer/Views/SettingsView.swift @@ -49,12 +49,14 @@ struct SettingsView: View { } Button { - settingsRouter.dismissCoordinator() - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { + SessionManager.main.logout() + +// settingsRouter.dismissCoordinator() +// DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { // TODO: todo and move notification somewhere else // SessionManager.current.logout() - SwiftfinNotificationCenter.main.post(name: SwiftfinNotificationCenter.Keys.didSignOut, object: nil) - } +// SwiftfinNotificationCenter.main.post(name: SwiftfinNotificationCenter.Keys.didSignOut, object: nil) +// } } label: { Text("Sign out") .font(.callout) diff --git a/Shared/Resources/Model.xcdatamodeld/.xccurrentversion b/Shared/Resources/Model.xcdatamodeld/.xccurrentversion index ea5bdb72..0c67376e 100644 --- a/Shared/Resources/Model.xcdatamodeld/.xccurrentversion +++ b/Shared/Resources/Model.xcdatamodeld/.xccurrentversion @@ -1,8 +1,5 @@ - - _XCCurrentVersionName - JellyfinPlayer.xcdatamodel - + diff --git a/Shared/Singleton/SessionManager.swift b/Shared/Singleton/SessionManager.swift index 19732556..db9ba4ec 100644 --- a/Shared/Singleton/SessionManager.swift +++ b/Shared/Singleton/SessionManager.swift @@ -21,7 +21,7 @@ import TVServices import SwiftUIFocusGuide #endif -typealias CurrentLogin = (server: SwiftfinStore.Models.Server, user: SwiftfinStore.Models.User) +typealias CurrentLogin = (server: SwiftfinStore.State.Server, user: SwiftfinStore.State.User) // MARK: NewSessionManager final class SessionManager { @@ -34,30 +34,28 @@ final class SessionManager { private init() { if let lastUserID = SwiftfinStore.Defaults.suite[.lastServerUserID], - let user = try? SwiftfinStore.dataStack.fetchOne(From(), - [Where("id == %@", lastUserID)]) { + let user = try? SwiftfinStore.dataStack.fetchOne(From(), + [Where("id == %@", lastUserID)]) { - // TODO: Fetch for right queue - // Strongly assuming that we didn't delete the server associate with the user - guard let server = user.server, let accessToken = user.accessToken else { return } + guard let server = user.server, let accessToken = user.accessToken else { fatalError("No associated server or access token for last user?") } guard let existingServer = SwiftfinStore.dataStack.fetchExisting(server) else { return } setAuthHeader(with: accessToken.value) - currentLogin = (server: existingServer, user: user) + currentLogin = (server: existingServer.state, user: user.state) } } - private func generateServerUserID(server: SwiftfinStore.Models.Server, user: SwiftfinStore.Models.User) -> String { + private func generateServerUserID(server: SwiftfinStore.Models.StoredServer, user: SwiftfinStore.Models.StoredUser) -> String { return "\(server.id)-\(user.id)" } - func fetchServers() -> [SwiftfinStore.Models.Server] { - let servers = try! SwiftfinStore.dataStack.fetchAll(From()) - return servers + func fetchServers() -> [SwiftfinStore.State.Server] { + let servers = try! SwiftfinStore.dataStack.fetchAll(From()) + return servers.map({ $0.state }) } // Connects to a server at the given uri, storing if successful - func connectToServer(with uri: String) -> AnyPublisher { + func connectToServer(with uri: String) -> AnyPublisher { var uri = uri if !uri.contains("http") { uri = "https://" + uri @@ -69,9 +67,9 @@ final class SessionManager { JellyfinAPI.basePath = uri return SystemAPI.getPublicSystemInfo() - .map({ response -> (SwiftfinStore.Models.Server, UnsafeDataTransaction) in + .map({ response -> (SwiftfinStore.Models.StoredServer, UnsafeDataTransaction) in let transaction = SwiftfinStore.dataStack.beginUnsafe() - let newServer = transaction.create(Into()) + let newServer = transaction.create(Into()) newServer.uri = response.localAddress ?? "SfUri" newServer.name = response.serverName ?? "SfServerName" newServer.id = response.id ?? "" @@ -85,36 +83,39 @@ final class SessionManager { try? transaction.commitAndWait() }) .map({ (server, _) in - return server + return server.state }) .eraseToAnyPublisher() } // Logs in a user with an associated server, storing if successful - func loginUser(server: SwiftfinStore.Models.Server, username: String, password: String) -> AnyPublisher { + func loginUser(server: SwiftfinStore.State.Server, username: String, password: String) -> AnyPublisher { setAuthHeader(with: "") return UserAPI.authenticateUserByName(authenticateUserByName: AuthenticateUserByName(username: username, pw: password)) - .map({ response -> (SwiftfinStore.Models.User, UnsafeDataTransaction) in + .map({ response -> (SwiftfinStore.Models.StoredServer, SwiftfinStore.Models.StoredUser, UnsafeDataTransaction) in guard let accessToken = response.accessToken else { fatalError("Received successful user with no access token") } let transaction = SwiftfinStore.dataStack.beginUnsafe() - let newUser = transaction.create(Into()) + let newUser = transaction.create(Into()) newUser.username = response.user?.name ?? "SfUsername" newUser.id = response.user?.id ?? "SfID" newUser.appleTVID = "" - let newAccessToken = transaction.create(Into()) + let newAccessToken = transaction.create(Into()) newAccessToken.value = accessToken newUser.accessToken = newAccessToken - let userServer = transaction.edit(server) - userServer?.users.insert(newUser) + guard let userServer = try? SwiftfinStore.dataStack.fetchOne(From(), + [Where("id == %@", server.id)]) else { fatalError("No stored server associated with given state server?")} - return (newUser, transaction) + guard let editUserServer = transaction.edit(userServer) else { fatalError("Can't get proxy for existing object?") } + editUserServer.users.insert(newUser) + + return (editUserServer, newUser, transaction) }) - .handleEvents(receiveOutput: { [unowned self] (user, transaction) in + .handleEvents(receiveOutput: { [unowned self] (server, user, transaction) in setAuthHeader(with: user.accessToken?.value ?? "") try? transaction.commitAndWait() @@ -124,16 +125,17 @@ final class SessionManager { SwiftfinStore.Defaults.suite[.lastServerUserID] = user.id - currentLogin = (server: currentServer, user: currentUser) + currentLogin = (server: currentServer.state, user: currentUser.state) }) - .map({ (user, _) in + .map({ (_, user, _) in return user }) .eraseToAnyPublisher() } func logout() { - // TODO: todo + SwiftfinStore.Defaults.suite[.lastServerUserID] = nil + SwiftfinNotificationCenter.main.post(name: SwiftfinNotificationCenter.Keys.didSignOut, object: nil) } private func setAuthHeader(with accessToken: String) { diff --git a/Shared/Singleton/NotificationCenter.swift b/Shared/Singleton/SwiftfinNotificationCenter.swift similarity index 100% rename from Shared/Singleton/NotificationCenter.swift rename to Shared/Singleton/SwiftfinNotificationCenter.swift diff --git a/Shared/SwiftfinStore/SwiftfinStore.swift b/Shared/SwiftfinStore/SwiftfinStore.swift index c30ca41b..f97ef347 100644 --- a/Shared/SwiftfinStore/SwiftfinStore.swift +++ b/Shared/SwiftfinStore/SwiftfinStore.swift @@ -13,9 +13,46 @@ import Defaults enum SwiftfinStore { + // Safe, copyable representations of their underlying CoreStoredObject's + // Relationships are represented by the related object's IDs or value + enum State { + + struct Server { + let uri: String + let name: String + let id: String + let os: String + let version: String + let userIDs: [String] + + fileprivate init(uri: String, name: String, id: String, os: String, version: String, usersIDs: [String]) { + self.uri = uri + self.name = name + self.id = id + self.os = os + self.version = version + self.userIDs = usersIDs + } + } + + struct User { + let username: String + let id: String + let serverID: String + let accessToken: String + + fileprivate init(username: String, id: String, serverID: String, accessToken: String) { + self.username = username + self.id = id + self.serverID = serverID + self.accessToken = accessToken + } + } + } + enum Models { - final class Server: CoreStoreObject { + final class StoredServer: CoreStoreObject { @Field.Stored("uri") var uri: String = "" @@ -32,11 +69,20 @@ enum SwiftfinStore { @Field.Stored("version") var version: String = "" - @Field.Relationship("users", inverse: \User.$server) - var users: Set + @Field.Relationship("users", inverse: \StoredUser.$server) + var users: Set + + var state: State.Server { + return State.Server(uri: uri, + name: name, + id: id, + os: os, + version: version, + usersIDs: users.map({ $0.id })) + } } - final class User: CoreStoreObject { + final class StoredUser: CoreStoreObject { @Field.Stored("username") var username: String = "" @@ -48,28 +94,37 @@ enum SwiftfinStore { var appleTVID: String = "" @Field.Relationship("server") - var server: Server? + var server: StoredServer? - @Field.Relationship("accessToken", inverse: \AccessToken.$user) - var accessToken: AccessToken? + @Field.Relationship("accessToken", inverse: \StoredAccessToken.$user) + var accessToken: StoredAccessToken? + + var state: State.User { + guard let server = server else { fatalError("No server associated with user") } + guard let accessToken = accessToken else { fatalError("No access token associated with user") } + return State.User(username: username, + id: id, + serverID: server.id, + accessToken: accessToken.value) + } } - final class AccessToken: CoreStoreObject { + final class StoredAccessToken: CoreStoreObject { @Field.Stored("value") var value: String = "" @Field.Relationship("user") - var user: User? + var user: StoredUser? } } static let dataStack: DataStack = { let schema = CoreStoreSchema(modelVersion: "V1", entities: [ - Entity("Server"), - Entity("User"), - Entity("AccessToken") + Entity("Server"), + Entity("User"), + Entity("AccessToken") ], versionLock: nil) // TODO: todo diff --git a/Shared/SwiftfinStore/SwiftfinStoreDefaults.swift b/Shared/SwiftfinStore/SwiftfinStoreDefaults.swift index 7d6d7d30..3907fdf2 100644 --- a/Shared/SwiftfinStore/SwiftfinStoreDefaults.swift +++ b/Shared/SwiftfinStore/SwiftfinStoreDefaults.swift @@ -17,10 +17,6 @@ extension SwiftfinStore { static let suite: UserDefaults = { return UserDefaults(suiteName: "swiftfinstore-defaults")! }() - -// enum Keys { -// static let lastUserID = Defaults.Key("lastUserID", suite: SwiftfinStore.Defaults.suite) -// } } } diff --git a/Shared/SwiftfinStore/SwiftfinStoreKeychain.swift b/Shared/SwiftfinStore/SwiftfinStoreKeychain.swift deleted file mode 100644 index 31368ccf..00000000 --- a/Shared/SwiftfinStore/SwiftfinStoreKeychain.swift +++ /dev/null @@ -1,33 +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 KeychainSwift - -extension SwiftfinStore { - - enum Keychain { - - private static let keychainAccessGroup = "9R8RREG67J.me.vigue.jellyfin.sharedKeychain" - - private static let keychain: KeychainSwift = { - let keychain = KeychainSwift() - keychain.accessGroup = keychainAccessGroup - return keychain - }() - - static func getAuthToken(serverUserID: String) -> String? { - return keychain.get("AccessToken_\(serverUserID)") - } - - static func delete(serverUserID: String) { - // TODO: todo - } - } -} diff --git a/Shared/ViewModels/ServerListViewModel.swift b/Shared/ViewModels/ServerListViewModel.swift index d77c7225..94293adf 100644 --- a/Shared/ViewModels/ServerListViewModel.swift +++ b/Shared/ViewModels/ServerListViewModel.swift @@ -12,9 +12,9 @@ import SwiftUI class ServerListViewModel: ObservableObject { - @Published var servers: [SwiftfinStore.Models.Server] = [] + @Published var servers: [SwiftfinStore.State.Server] = [] - init() { + func fetchServers() { self.servers = SessionManager.main.fetchServers() } } diff --git a/Shared/ViewModels/UserLoginViewModel.swift b/Shared/ViewModels/UserLoginViewModel.swift index c177bcfe..33e90dad 100644 --- a/Shared/ViewModels/UserLoginViewModel.swift +++ b/Shared/ViewModels/UserLoginViewModel.swift @@ -15,11 +15,10 @@ import Stinsen final class UserLoginViewModel: ViewModel { @RouterObject var router: UserLoginCoordinator.Router? - let server: SwiftfinStore.Models.Server + let server: SwiftfinStore.State.Server - init(server: SwiftfinStore.Models.Server) { - // Need to fetch for this context - self.server = SwiftfinStore.dataStack.fetchExisting(server)! + init(server: SwiftfinStore.State.Server) { + self.server = server } func login(username: String, password: String) {