Add state models and proper logout
This commit is contained in:
parent
e81b593fa1
commit
67bfdcb207
|
@ -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 = "<group>"; };
|
||||
5377CBF8263B596B003A4E83 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
5377CBFB263B596B003A4E83 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
||||
5377CC00263B596B003A4E83 /* JellyfinPlayer.xcdatamodel */ = {isa = PBXFileReference; explicitFileType = wrapper.xcdatamodel; path = JellyfinPlayer.xcdatamodel; sourceTree = "<group>"; };
|
||||
5377CC02263B596B003A4E83 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
5389276D263C25100035E14B /* ContinueWatchingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContinueWatchingView.swift; sourceTree = "<group>"; };
|
||||
5389276F263C25230035E14B /* NextUpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextUpView.swift; sourceTree = "<group>"; };
|
||||
|
@ -518,12 +512,11 @@
|
|||
E13DD3C127164941009D4DAF /* SwiftfinStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftfinStore.swift; sourceTree = "<group>"; };
|
||||
E13DD3C727164B1E009D4DAF /* UIDeviceExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIDeviceExtensions.swift; sourceTree = "<group>"; };
|
||||
E13DD3D4271693CD009D4DAF /* SwiftfinStoreDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftfinStoreDefaults.swift; sourceTree = "<group>"; };
|
||||
E13DD3D827169406009D4DAF /* SwiftfinStoreKeychain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftfinStoreKeychain.swift; sourceTree = "<group>"; };
|
||||
E13DD3E027176BD3009D4DAF /* ServerListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerListViewModel.swift; sourceTree = "<group>"; };
|
||||
E13DD3E427177D15009D4DAF /* ServerListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerListView.swift; sourceTree = "<group>"; };
|
||||
E13DD3E827177ED6009D4DAF /* ServerListCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerListCoordinator.swift; sourceTree = "<group>"; };
|
||||
E13DD3EB27178A54009D4DAF /* UserLoginViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserLoginViewModel.swift; sourceTree = "<group>"; };
|
||||
E13DD3EE27178F87009D4DAF /* NotificationCenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationCenter.swift; sourceTree = "<group>"; };
|
||||
E13DD3EE27178F87009D4DAF /* SwiftfinNotificationCenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftfinNotificationCenter.swift; sourceTree = "<group>"; };
|
||||
E13DD3F127179378009D4DAF /* UserLoginCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserLoginCoordinator.swift; sourceTree = "<group>"; };
|
||||
E13DD3F4271793BB009D4DAF /* UserLoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserLoginView.swift; sourceTree = "<group>"; };
|
||||
E14F7D0626DB36EF007C3AE6 /* ItemPortraitMainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemPortraitMainView.swift; sourceTree = "<group>"; };
|
||||
|
@ -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 = "<group>";
|
||||
|
@ -1069,7 +1062,6 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
AE8C3158265D6F90008AA076 /* bitrates.json */,
|
||||
5377CBFF263B596B003A4E83 /* Model.xcdatamodeld */,
|
||||
);
|
||||
path = Resources;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1100,7 +1092,6 @@
|
|||
children = (
|
||||
E13DD3C127164941009D4DAF /* SwiftfinStore.swift */,
|
||||
E13DD3D4271693CD009D4DAF /* SwiftfinStoreDefaults.swift */,
|
||||
E13DD3D827169406009D4DAF /* SwiftfinStoreKeychain.swift */,
|
||||
);
|
||||
path = SwiftfinStore;
|
||||
sourceTree = "<group>";
|
||||
|
@ -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 = "<group>";
|
||||
versionGroupType = wrapper.xcdatamodel;
|
||||
};
|
||||
/* End XCVersionGroup section */
|
||||
};
|
||||
rootObject = 5377CBE9263B596A003A4E83 /* Project object */;
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -34,18 +34,18 @@ struct ServerListView: View {
|
|||
|
||||
Button {
|
||||
SwiftfinStore.dataStack.perform(asynchronous: { transaction in
|
||||
try! transaction.deleteAll(From<SwiftfinStore.Models.Server>())
|
||||
try! transaction.deleteAll(From<SwiftfinStore.Models.User>())
|
||||
try! transaction.deleteAll(From<SwiftfinStore.Models.AccessToken>())
|
||||
try! transaction.deleteAll(From<SwiftfinStore.Models.StoredServer>())
|
||||
try! transaction.deleteAll(From<SwiftfinStore.Models.StoredUser>())
|
||||
try! transaction.deleteAll(From<SwiftfinStore.Models.StoredAccessToken>())
|
||||
}) { _ 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>_XCCurrentVersionName</key>
|
||||
<string>JellyfinPlayer.xcdatamodel</string>
|
||||
</dict>
|
||||
<dict/>
|
||||
</plist>
|
||||
|
|
|
@ -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<SwiftfinStore.Models.User>(),
|
||||
[Where<SwiftfinStore.Models.User>("id == %@", lastUserID)]) {
|
||||
let user = try? SwiftfinStore.dataStack.fetchOne(From<SwiftfinStore.Models.StoredUser>(),
|
||||
[Where<SwiftfinStore.Models.StoredUser>("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<SwiftfinStore.Models.Server>())
|
||||
return servers
|
||||
func fetchServers() -> [SwiftfinStore.State.Server] {
|
||||
let servers = try! SwiftfinStore.dataStack.fetchAll(From<SwiftfinStore.Models.StoredServer>())
|
||||
return servers.map({ $0.state })
|
||||
}
|
||||
|
||||
// Connects to a server at the given uri, storing if successful
|
||||
func connectToServer(with uri: String) -> AnyPublisher<SwiftfinStore.Models.Server, Error> {
|
||||
func connectToServer(with uri: String) -> AnyPublisher<SwiftfinStore.State.Server, Error> {
|
||||
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<SwiftfinStore.Models.Server>())
|
||||
let newServer = transaction.create(Into<SwiftfinStore.Models.StoredServer>())
|
||||
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<SwiftfinStore.Models.User, Error> {
|
||||
func loginUser(server: SwiftfinStore.State.Server, username: String, password: String) -> AnyPublisher<SwiftfinStore.Models.StoredUser, Error> {
|
||||
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<SwiftfinStore.Models.User>())
|
||||
let newUser = transaction.create(Into<SwiftfinStore.Models.StoredUser>())
|
||||
newUser.username = response.user?.name ?? "SfUsername"
|
||||
newUser.id = response.user?.id ?? "SfID"
|
||||
newUser.appleTVID = ""
|
||||
|
||||
let newAccessToken = transaction.create(Into<SwiftfinStore.Models.AccessToken>())
|
||||
let newAccessToken = transaction.create(Into<SwiftfinStore.Models.StoredAccessToken>())
|
||||
newAccessToken.value = accessToken
|
||||
newUser.accessToken = newAccessToken
|
||||
|
||||
let userServer = transaction.edit(server)
|
||||
userServer?.users.insert(newUser)
|
||||
guard let userServer = try? SwiftfinStore.dataStack.fetchOne(From<SwiftfinStore.Models.StoredServer>(),
|
||||
[Where<SwiftfinStore.Models.StoredServer>("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) {
|
||||
|
|
|
@ -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<User>
|
||||
@Field.Relationship("users", inverse: \StoredUser.$server)
|
||||
var users: Set<StoredUser>
|
||||
|
||||
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<SwiftfinStore.Models.Server>("Server"),
|
||||
Entity<SwiftfinStore.Models.User>("User"),
|
||||
Entity<SwiftfinStore.Models.AccessToken>("AccessToken")
|
||||
Entity<SwiftfinStore.Models.StoredServer>("Server"),
|
||||
Entity<SwiftfinStore.Models.StoredUser>("User"),
|
||||
Entity<SwiftfinStore.Models.StoredAccessToken>("AccessToken")
|
||||
],
|
||||
versionLock: nil) // TODO: todo
|
||||
|
||||
|
|
|
@ -17,10 +17,6 @@ extension SwiftfinStore {
|
|||
static let suite: UserDefaults = {
|
||||
return UserDefaults(suiteName: "swiftfinstore-defaults")!
|
||||
}()
|
||||
|
||||
// enum Keys {
|
||||
// static let lastUserID = Defaults.Key<String?>("lastUserID", suite: SwiftfinStore.Defaults.suite)
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue