Migrate to the latest version of Factory (#1097)

This commit is contained in:
Daniel Chick 2024-07-01 20:58:59 -05:00 committed by GitHub
parent 439cd85c77
commit 29b917ead0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
39 changed files with 115 additions and 115 deletions

View File

@ -21,9 +21,12 @@ import SwiftUI
final class MainCoordinator: NavigationCoordinatable {
@Injected(LogManager.service)
@Injected(\.logService)
private var logger
@Injected(\.currentUserSession)
private var userSession
var stack: Stinsen.NavigationStack<MainCoordinator>
@Root
@ -50,7 +53,7 @@ final class MainCoordinator: NavigationCoordinatable {
do {
try await SwiftfinStore.setupDataStack()
if UserSession.current() != nil, !Defaults[.signOutOnClose] {
if userSession != nil, !Defaults[.signOutOnClose] {
await MainActor.run {
withAnimation(.linear(duration: 0.1)) {
let _ = root(\.serverCheck)
@ -118,9 +121,9 @@ final class MainCoordinator: NavigationCoordinatable {
@objc
func didChangeCurrentServerURL(_ notification: Notification) {
guard UserSession.current() != nil else { return }
guard userSession != nil else { return }
UserSession.current.reset()
Container.shared.currentUserSession.reset()
Notifications[.didSignIn].post()
}

View File

@ -18,7 +18,7 @@ import SwiftUI
final class MainCoordinator: NavigationCoordinatable {
@Injected(LogManager.service)
@Injected(\.logService)
private var logger
var stack: Stinsen.NavigationStack<MainCoordinator>
@ -38,7 +38,7 @@ final class MainCoordinator: NavigationCoordinatable {
do {
try await SwiftfinStore.setupDataStack()
if UserSession.current() != nil {
if Container.shared.currentUserSession() != nil {
await MainActor.run {
withAnimation(.linear(duration: 0.1)) {
let _ = root(\.mainTab)

View File

@ -98,7 +98,7 @@ extension BaseItemDto {
}
// TODO: client passing for widget/shared group views?
guard let client = UserSession.current()?.client else { return nil }
guard let client = Container.shared.currentUserSession()?.client else { return nil }
let parameters = Paths.GetItemImageParameters(
maxWidth: scaleWidth,

View File

@ -21,7 +21,7 @@ extension BaseItemDto {
let tempOverkillBitrate = 360_000_000
let profile = DeviceProfile.build(for: currentVideoPlayerType, maxBitrate: tempOverkillBitrate)
let userSession = UserSession.current()!
let userSession = Container.shared.currentUserSession()!
let playbackInfo = PlaybackInfoDto(deviceProfile: profile)
let playbackInfoParameters = Paths.GetPostedPlaybackInfoParameters(
@ -56,7 +56,7 @@ extension BaseItemDto {
profile.directPlayProfiles = [DirectPlayProfile(type: .video)]
}
let userSession = UserSession.current()!
let userSession = Container.shared.currentUserSession()!
let playbackInfo = PlaybackInfoDto(deviceProfile: profile)
let playbackInfoParameters = Paths.GetPostedPlaybackInfoParameters(

View File

@ -193,8 +193,7 @@ extension BaseItemDto {
parameters: parameters
)
let imageURL = UserSession
.current()!
let imageURL = Container.shared.currentUserSession()!
.client
.fullURL(with: request)

View File

@ -23,7 +23,7 @@ extension BaseItemPerson: Poster {
func portraitImageSources(maxWidth: CGFloat? = nil) -> [ImageSource] {
guard let client = UserSession.current()?.client else { return [] }
guard let client = Container.shared.currentUserSession()?.client else { return [] }
// TODO: figure out what to do about screen scaling with .main being deprecated
// - maxWidth assume already scaled?

View File

@ -18,7 +18,7 @@ extension MediaSourceInfo {
func videoPlayerViewModel(with item: BaseItemDto, playSessionID: String) throws -> VideoPlayerViewModel {
let userSession: UserSession! = UserSession.current()
let userSession: UserSession! = Container.shared.currentUserSession()
let playbackURL: URL
let streamType: StreamType
@ -68,7 +68,7 @@ extension MediaSourceInfo {
func liveVideoPlayerViewModel(with item: BaseItemDto, playSessionID: String) throws -> VideoPlayerViewModel {
let userSession: UserSession! = UserSession.current()
let userSession: UserSession! = Container.shared.currentUserSession()
let playbackURL: URL
let streamType: StreamType

View File

@ -16,7 +16,7 @@ extension MediaStream {
static var none: MediaStream = .init(displayTitle: L10n.none, index: -1)
var asPlaybackChild: VLCVideoPlayer.PlaybackChild? {
guard let deliveryURL, let client = UserSession.current()?.client else { return nil }
guard let deliveryURL, let client = Container.shared.currentUserSession()?.client else { return nil }
let deliveryPath = deliveryURL.removingFirst(if: client.configuration.url.absoluteString.last == "/")

View File

@ -13,7 +13,7 @@ import UDPBroadcast
class ServerDiscovery {
@Injected(LogManager.service)
@Injected(\.logService)
private var logger
private var connection: UDPBroadcastConnection?

View File

@ -12,17 +12,12 @@ import Foundation
import JellyfinAPI
extension Container {
static let downloadManager = Factory(scope: .singleton) {
let manager = DownloadManager()
manager.clearTmp()
return manager
}
var downloadManager: Factory<DownloadManager> { self { DownloadManager() }.shared }
}
class DownloadManager: ObservableObject {
@Injected(LogManager.service)
@Injected(\.logService)
private var logger
@Published

View File

@ -38,9 +38,9 @@ class DownloadTask: NSObject, ObservableObject {
case ready
}
@Injected(LogManager.service)
@Injected(\.logService)
private var logger
@Injected(UserSession.current)
@Injected(\.currentUserSession)
private var userSession: UserSession!
@Published
@ -80,8 +80,7 @@ class DownloadTask: NSObject, ObservableObject {
await MainActor.run {
self.state = .error(error)
Container.downloadManager()
.remove(task: self)
Container.shared.downloadManager.reset()
}
return
}
@ -284,8 +283,7 @@ extension DownloadTask: URLSessionDownloadDelegate {
DispatchQueue.main.async {
self.state = .error(error)
Container.downloadManager()
.remove(task: self)
Container.shared.downloadManager.reset()
}
}
@ -295,8 +293,7 @@ extension DownloadTask: URLSessionDownloadDelegate {
DispatchQueue.main.async {
self.state = .error(error)
Container.downloadManager()
.remove(task: self)
Container.shared.downloadManager.reset()
}
}
}

View File

@ -10,10 +10,8 @@ import Factory
import Foundation
import KeychainSwift
enum Keychain {
extension Container {
// TODO: take a look at all security options
static let service = Factory<KeychainSwift>(scope: .singleton) {
KeychainSwift()
}
var keychainService: Factory<KeychainSwift> { self { KeychainSwift() }.singleton }
}

View File

@ -13,22 +13,28 @@ import Logging
import Pulse
// TODO: cleanup
extension Container {
var logService: Factory<Logger> { self { Logger(label: "org.jellyfin.swiftfin") }.singleton }
enum LogManager {
static let service = Factory<Logger>(scope: .singleton) {
Logger(label: "org.jellyfin.swiftfin")
var pulseNetworkLogger: Factory<NetworkLogger> {
self {
let configuration = NetworkLogger.Configuration()
return NetworkLogger(configuration: configuration)
}
.singleton
}
}
struct LogManager {
// TODO: make rules for logging sessions and redacting
static let pulseNetworkLogger = Factory<NetworkLogger>(scope: .singleton) {
var configuration = NetworkLogger.Configuration()
// static let pulseNetworkLogger = Factory<NetworkLogger>(scope: .singleton) {
// var configuration = NetworkLogger.Configuration()
// TODO: this used to be necessary to stop the mass of image requests
// clogging the logs, however don't seem necessary anymore?
// Find out how to get images to be logged and have an option to
// turn it on, via SuperUser.
// TODO: this used to be necessary to stop the mass of image requests
// clogging the logs, however don't seem necessary anymore?
// Find out how to get images to be logged and have an option to
// turn it on, via SuperUser.
// configuration.willHandleEvent = { event -> LoggerStore.Event? in
// switch event {
@ -46,8 +52,8 @@ enum LogManager {
// return event
// }
return NetworkLogger(configuration: configuration)
}
// return NetworkLogger(configuration: configuration)
// }
}
struct SwiftfinConsoleLogger: LogHandler {
@ -79,7 +85,7 @@ struct SwiftfinConsoleLogger: LogHandler {
struct SwiftfinCorestoreLogger: CoreStoreLogger {
@Injected(LogManager.service)
@Injected(\.logService)
private var logger
func log(

View File

@ -11,7 +11,7 @@ import Foundation
class SwiftfinNotification {
@Injected(Notifications.service)
@Injected(\.notificationCenter)
private var notificationService
let name: Notification.Name
@ -37,9 +37,11 @@ class SwiftfinNotification {
}
}
enum Notifications {
extension Container {
var notificationCenter: Factory<NotificationCenter> { self { NotificationCenter.default }.singleton }
}
static let service = Factory(scope: .singleton) { NotificationCenter.default }
enum Notifications {
struct Key: Hashable {

View File

@ -31,7 +31,7 @@ final class UserSession {
let client = JellyfinClient(
configuration: .swiftfinConfiguration(url: server.currentURL),
sessionConfiguration: .swiftfin,
sessionDelegate: URLSessionProxyDelegate(logger: LogManager.pulseNetworkLogger()),
sessionDelegate: URLSessionProxyDelegate(logger: Container.shared.pulseNetworkLogger()),
accessToken: user.accessToken
)
@ -39,32 +39,27 @@ final class UserSession {
}
}
fileprivate extension Container.Scope {
extension Container {
var currentUserSession: Factory<UserSession?> {
self {
if let lastUserID = Defaults[.lastSignedInUserID],
let user = try? SwiftfinStore.dataStack.fetchOne(
From<UserModel>().where(\.$id == lastUserID)
)
{
guard let server = user.server,
let _ = SwiftfinStore.dataStack.fetchExisting(server)
else {
fatalError("No associated server for last user")
}
// static let userSessionScope = .
}
extension UserSession {
static let current = Factory<UserSession?>(scope: .cached) {
if let lastUserID = Defaults[.lastSignedInUserID],
let user = try? SwiftfinStore.dataStack.fetchOne(
From<UserModel>().where(\.$id == lastUserID)
)
{
guard let server = user.server,
let existingServer = SwiftfinStore.dataStack.fetchExisting(server)
else {
fatalError("No associated server for last user")
return .init(
server: server.state,
user: user.state
)
}
return .init(
server: server.state,
user: user.state
)
}
return nil
return nil
}.cached
}
}

View File

@ -8,6 +8,7 @@
import Combine
import CoreStore
import Factory
import Foundation
import SwiftUI
@ -125,7 +126,7 @@ extension StoredValue {
domain: key.domain
)
} catch {
LogManager.service().error("Unable to store and create publisher for: \(key)")
Container.shared.logService().error("Unable to store and create publisher for: \(key)")
return nil
}

View File

@ -26,7 +26,7 @@ extension StoredValues.Keys {
domain: String,
default defaultValue: Value
) -> Key<Value> {
guard let name, let currentUser = UserSession.current()?.user else {
guard let name, let currentUser = Container.shared.currentUserSession()?.user else {
return Key(always: defaultValue)
}

View File

@ -7,6 +7,7 @@
//
import CoreStore
import Factory
import Foundation
import KeychainSwift
@ -33,7 +34,7 @@ extension SwiftfinStore.Mappings {
// move access token to Keychain
if let id = sourceObject["id"] as? String, let accessToken = sourceObject["accessToken"] as? String {
Keychain.service().set(accessToken, forKey: "\(id)-accessToken")
Container.shared.keychainService().set(accessToken, forKey: "\(id)-accessToken")
} else {
fatalError("wtf")
}

View File

@ -7,6 +7,7 @@
//
import CoreStore
import Factory
import Foundation
import JellyfinAPI
import Pulse
@ -41,7 +42,7 @@ extension SwiftfinStore.State {
JellyfinClient(
configuration: .swiftfinConfiguration(url: currentURL),
sessionConfiguration: .swiftfin,
sessionDelegate: URLSessionProxyDelegate(logger: LogManager.pulseNetworkLogger())
sessionDelegate: URLSessionProxyDelegate(logger: Container.shared.pulseNetworkLogger())
)
}
}

View File

@ -20,6 +20,10 @@ typealias UserState = SwiftfinStore.State.User
// MARK: Namespaces
extension Container {
var dataStore: Factory<DataStack> { self { SwiftfinStore.dataStack }.singleton }
}
enum SwiftfinStore {
/// Namespace for V1 objects
@ -64,14 +68,10 @@ extension SwiftfinStore {
case .success:
continuation.resume()
case let .failure(error):
LogManager.service().error("Failed creating datastack with: \(error.localizedDescription)")
Container.shared.logService().error("Failed creating datastack with: \(error.localizedDescription)")
continuation.resume(throwing: JellyfinAPIError("Failed creating datastack with: \(error.localizedDescription)"))
}
}
}
}
static let service = Factory<DataStack>(scope: .singleton) {
SwiftfinStore.dataStack
}
}

View File

@ -7,6 +7,7 @@
//
import CoreStore
import Factory
import Foundation
import JellyfinAPI
import KeychainSwift
@ -42,7 +43,7 @@ extension UserState {
var accessToken: String {
get {
guard let accessToken = Keychain.service().get("\(id)-accessToken") else {
guard let accessToken = Container.shared.keychainService().get("\(id)-accessToken") else {
assertionFailure("access token missing in keychain")
return ""
}
@ -50,7 +51,7 @@ extension UserState {
return accessToken
}
nonmutating set {
Keychain.service().set(newValue, forKey: "\(id)-accessToken")
Container.shared.keychainService().set(newValue, forKey: "\(id)-accessToken")
}
}
@ -101,7 +102,7 @@ extension UserState {
UserDefaults.userSuite(id: id).removeAll()
let keychain = Keychain.service()
let keychain = Container.shared.keychainService()
keychain.delete("\(id)-pin")
}
@ -129,7 +130,7 @@ extension UserState {
let client = JellyfinClient(
configuration: .swiftfinConfiguration(url: server.currentURL),
sessionConfiguration: .swiftfin,
sessionDelegate: URLSessionProxyDelegate(logger: LogManager.pulseNetworkLogger()),
sessionDelegate: URLSessionProxyDelegate(logger: Container.shared.pulseNetworkLogger()),
accessToken: accessToken
)

View File

@ -8,6 +8,7 @@
import Combine
import CoreStore
import Factory
import Foundation
import Get
import JellyfinAPI
@ -146,7 +147,7 @@ final class ConnectToServerViewModel: ViewModel, Eventful, Stateful {
let client = JellyfinClient(
configuration: .swiftfinConfiguration(url: url),
sessionDelegate: URLSessionProxyDelegate(logger: LogManager.pulseNetworkLogger())
sessionDelegate: URLSessionProxyDelegate(logger: Container.shared.pulseNetworkLogger())
)
let response = try await client.send(Paths.getPublicSystemInfo)

View File

@ -11,7 +11,7 @@ import SwiftUI
class DownloadListViewModel: ViewModel {
@Injected(Container.downloadManager)
@Injected(\.downloadManager)
private var downloadManager
@Published

View File

@ -110,7 +110,7 @@ final class SettingsViewModel: ViewModel {
func signOut() {
Defaults[.lastSignedInUserID] = nil
UserSession.current.reset()
Container.shared.currentUserSession.reset()
Notifications[.didSignOut].post()
}
}

View File

@ -13,17 +13,17 @@ import KeychainSwift
class ViewModel: ObservableObject {
@Injected(SwiftfinStore.service)
@Injected(\.dataStore)
var dataStack
@Injected(Keychain.service)
@Injected(\.keychainService)
var keychain
@Injected(LogManager.service)
@Injected(\.logService)
var logger
/// The current *signed in* user session
@Injected(UserSession.current)
@Injected(\.currentUserSession)
var userSession: UserSession!
var cancellables = Set<AnyCancellable>()

View File

@ -67,7 +67,7 @@ struct SwiftfinApp: App {
if Defaults[.signOutOnBackground], backgroundedInterval > Defaults[.backgroundSignOutInterval] {
Defaults[.lastSignedInUserID] = nil
UserSession.current.reset()
Container.shared.currentUserSession.reset()
Notifications[.didSignOut].post()
}
}

View File

@ -13,7 +13,7 @@ extension ItemView {
struct PlayButton: View {
@Injected(LogManager.service)
@Injected(\.logService)
private var logger
@EnvironmentObject

View File

@ -306,7 +306,7 @@ struct SelectUserView: View {
self.isPresentingError = true
case let .signedIn(user):
Defaults[.lastSignedInUserID] = user.id
UserSession.current.reset()
Container.shared.currentUserSession.reset()
Notifications[.didSignIn].post()
}
}

View File

@ -172,7 +172,7 @@ struct UserSignInView: View {
router.dismissCoordinator()
Defaults[.lastSignedInUserID] = user.id
UserSession.current.reset()
Container.shared.currentUserSession.reset()
Notifications[.didSignIn].post()
}
}

View File

@ -5172,7 +5172,7 @@
repositoryURL = "https://github.com/sindresorhus/Defaults";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 7.0.0;
minimumVersion = 8.0.0;
};
};
E145EB492BE16849003BF6F3 /* XCRemoteSwiftPackageReference "keychain-swift" */ = {
@ -5228,7 +5228,7 @@
repositoryURL = "https://github.com/hmlongco/Factory";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 1.0.0;
minimumVersion = 2.0.0;
};
};
E19DDEC52948EF9900954E10 /* XCRemoteSwiftPackageReference "swift-collections" */ = {

View File

@ -1,5 +1,5 @@
{
"originHash" : "323b2ad9aaa9c000faf264d68272f0e9fab1349d9f910a0b95ee6aea10460f31",
"originHash" : "651194fc1966b57201a0de2cba27dc40798bbdf515febdc83f00d634d916fea4",
"pins" : [
{
"identity" : "blurhashkit",
@ -51,8 +51,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/sindresorhus/Defaults",
"state" : {
"revision" : "3efef5a28ebdbbe922d4a2049493733ed14475a6",
"version" : "7.3.1"
"revision" : "38925e3cfacf3fb89a81a35b1cd44fd5a5b7e0fa",
"version" : "8.2.0"
}
},
{
@ -69,8 +69,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/hmlongco/Factory",
"state" : {
"revision" : "39ff6a675cd0272d833d184d35add0f8fddd63de",
"version" : "1.3.7"
"revision" : "587995f7d5cc667951d635fbf6b4252324ba0439",
"version" : "2.3.2"
}
},
{

View File

@ -90,7 +90,7 @@ struct SwiftfinApp: App {
if backgroundedInterval > Defaults[.backgroundSignOutInterval] {
Defaults[.lastSignedInUserID] = nil
UserSession.current.reset()
Container.shared.currentUserSession.reset()
Notifications[.didSignOut].post()
}
}

View File

@ -18,7 +18,7 @@ extension DownloadTaskView {
@Default(.accentColor)
private var accentColor
@Injected(Container.downloadManager)
@Injected(\.downloadManager)
private var downloadManager
@EnvironmentObject

View File

@ -18,7 +18,7 @@ extension ItemView {
@Default(.accentColor)
private var accentColor
@Injected(Container.downloadManager)
@Injected(\.downloadManager)
private var downloadManager: DownloadManager
@EnvironmentObject

View File

@ -45,7 +45,7 @@ struct DownloadTaskButton: View {
extension DownloadTaskButton {
init(item: BaseItemDto) {
let downloadManager = Container.downloadManager()
let downloadManager = Container.shared.downloadManager()
self.downloadTask = downloadManager.task(for: item) ?? .init(item: item)
self.onSelect = { _ in }

View File

@ -19,7 +19,7 @@ extension ItemView {
@Default(.accentColor)
private var accentColor
@Injected(LogManager.service)
@Injected(\.logService)
private var logger
@EnvironmentObject

View File

@ -562,7 +562,7 @@ struct SelectUserView: View {
UIDevice.feedback(.success)
Defaults[.lastSignedInUserID] = user.id
UserSession.current.reset()
Container.shared.currentUserSession.reset()
Notifications[.didSignIn].post()
}
}

View File

@ -13,7 +13,7 @@ extension SettingsView {
struct UserProfileRow: View {
@Injected(UserSession.current)
@Injected(\.currentUserSession)
private var userSession: UserSession!
let action: () -> Void

View File

@ -74,7 +74,7 @@ struct UserSignInView: View {
UIDevice.feedback(.success)
Defaults[.lastSignedInUserID] = user.id
UserSession.current.reset()
Container.shared.currentUserSession.reset()
Notifications[.didSignIn].post()
}
}