Add state models and proper logout

This commit is contained in:
Ethan Pippin 2021-10-13 22:25:57 -06:00
parent e81b593fa1
commit 67bfdcb207
13 changed files with 125 additions and 131 deletions

View File

@ -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 */;
}

View File

@ -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))
}

View File

@ -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",

View File

@ -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()
}
}
}

View File

@ -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)

View File

@ -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>

View File

@ -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) {

View File

@ -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

View File

@ -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)
// }
}
}

View File

@ -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
}
}
}

View File

@ -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()
}
}

View File

@ -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) {