Compare commits
10 commits
22213037ca
...
dc4fb77a66
| Author | SHA1 | Date | |
|---|---|---|---|
| dc4fb77a66 | |||
| 91faf3c0f4 | |||
| 428eb32be1 | |||
| 0ecb95d7c8 | |||
| b12352c29d | |||
| 7173da4464 | |||
| 86940f3d7d | |||
| be7931b062 | |||
| c3a971b49e | |||
| 2280142fe1 |
14 changed files with 138 additions and 55 deletions
|
|
@ -14,27 +14,54 @@ let package = Package(
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
.target(
|
.target(
|
||||||
name: "LuminateCore",
|
name: "LuminateAPI",
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"),
|
.product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"),
|
||||||
.product(name: "OpenAPIURLSession", package: "swift-openapi-urlsession"),
|
.product(name: "OpenAPIURLSession", package: "swift-openapi-urlsession"),
|
||||||
.product(name: "SQLite", package: "SQLite.swift"),
|
|
||||||
],
|
],
|
||||||
plugins: [
|
plugins: [
|
||||||
.plugin(name: "OpenAPIGenerator", package: "swift-openapi-generator")
|
.plugin(name: "OpenAPIGenerator", package: "swift-openapi-generator")
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
|
.target(
|
||||||
|
name: "LuminateCore",
|
||||||
|
dependencies: [
|
||||||
|
"LuminateAPI",
|
||||||
|
.product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"),
|
||||||
|
.product(name: "OpenAPIURLSession", package: "swift-openapi-urlsession"),
|
||||||
|
.product(name: "SQLite", package: "SQLite.swift"),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
.target(
|
||||||
|
name: "LuminateDI",
|
||||||
|
dependencies: [
|
||||||
|
"LuminateCore",
|
||||||
|
.product(name: "Adwaita", package: "adwaita-swift"),
|
||||||
|
]
|
||||||
|
),
|
||||||
.target(
|
.target(
|
||||||
name: "LuminateHome",
|
name: "LuminateHome",
|
||||||
dependencies: ["LuminateCore", .product(name: "Adwaita", package: "adwaita-swift")]
|
dependencies: [
|
||||||
|
"LuminateCore",
|
||||||
|
"LuminateDI",
|
||||||
|
.product(name: "Adwaita", package: "adwaita-swift"),
|
||||||
|
]
|
||||||
),
|
),
|
||||||
.target(
|
.target(
|
||||||
name: "LuminateLibrary",
|
name: "LuminateLibrary",
|
||||||
dependencies: ["LuminateCore", .product(name: "Adwaita", package: "adwaita-swift")]
|
dependencies: [
|
||||||
|
"LuminateCore",
|
||||||
|
"LuminateDI",
|
||||||
|
.product(name: "Adwaita", package: "adwaita-swift"),
|
||||||
|
]
|
||||||
),
|
),
|
||||||
.target(
|
.target(
|
||||||
name: "LuminatePlayer",
|
name: "LuminatePlayer",
|
||||||
dependencies: ["LuminateCore", .product(name: "Adwaita", package: "adwaita-swift")]
|
dependencies: [
|
||||||
|
"LuminateCore",
|
||||||
|
"LuminateDI",
|
||||||
|
.product(name: "Adwaita", package: "adwaita-swift"),
|
||||||
|
]
|
||||||
),
|
),
|
||||||
.executableTarget(
|
.executableTarget(
|
||||||
name: "Luminate",
|
name: "Luminate",
|
||||||
|
|
@ -42,6 +69,7 @@ let package = Package(
|
||||||
"LuminateHome",
|
"LuminateHome",
|
||||||
"LuminateLibrary",
|
"LuminateLibrary",
|
||||||
"LuminatePlayer",
|
"LuminatePlayer",
|
||||||
|
"LuminateDI",
|
||||||
.product(name: "Adwaita", package: "adwaita-swift"),
|
.product(name: "Adwaita", package: "adwaita-swift"),
|
||||||
.product(name: "Localized", package: "localized"),
|
.product(name: "Localized", package: "localized"),
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import Adwaita
|
import Adwaita
|
||||||
import Foundation
|
import Foundation
|
||||||
import LuminateCore
|
import LuminateCore
|
||||||
|
import LuminateDI
|
||||||
import LuminateHome
|
import LuminateHome
|
||||||
import LuminateLibrary
|
import LuminateLibrary
|
||||||
import LuminatePlayer
|
import LuminatePlayer
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import Adwaita
|
import Adwaita
|
||||||
import Foundation
|
import Foundation
|
||||||
import LuminateCore
|
import LuminateCore
|
||||||
|
import LuminateDI
|
||||||
|
|
||||||
public struct ServerSetupView: View {
|
public struct ServerSetupView: View {
|
||||||
|
|
||||||
|
|
|
||||||
1
Sources/LuminateAPI/LuminateAPI.swift
Normal file
1
Sources/LuminateAPI/LuminateAPI.swift
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
public enum LuminateAPI {}
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
import Foundation
|
|
||||||
|
|
||||||
public final class DIContainer {
|
|
||||||
|
|
||||||
public static let shared = DIContainer()
|
|
||||||
public private(set) var values = InjectionValues()
|
|
||||||
|
|
||||||
private init() {}
|
|
||||||
|
|
||||||
public func register<T>(
|
|
||||||
_ keyPath: WritableKeyPath<InjectionValues, T?>,
|
|
||||||
value: T
|
|
||||||
) {
|
|
||||||
values[keyPath: keyPath] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
public func resolve<T>(
|
|
||||||
_ keyPath: KeyPath<InjectionValues, T?>
|
|
||||||
) -> T {
|
|
||||||
guard let value = values[keyPath: keyPath] else {
|
|
||||||
fatalError(
|
|
||||||
"DIContainer: No value registered for \(keyPath). "
|
|
||||||
+ "Call DIContainer.shared.register(\\.key, value:) during app startup."
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
public func reset() {
|
|
||||||
values = InjectionValues()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
import Foundation
|
|
||||||
|
|
||||||
@propertyWrapper
|
|
||||||
public struct Injected<T> {
|
|
||||||
|
|
||||||
private let keyPath: KeyPath<InjectionValues, T?>
|
|
||||||
|
|
||||||
public var wrappedValue: T {
|
|
||||||
DIContainer.shared.resolve(keyPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
public init(_ keyPath: KeyPath<InjectionValues, T?>) {
|
|
||||||
self.keyPath = keyPath
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
@_exported import LuminateAPI
|
||||||
@_exported import OpenAPIRuntime
|
@_exported import OpenAPIRuntime
|
||||||
@_exported import OpenAPIURLSession
|
@_exported import OpenAPIURLSession
|
||||||
|
|
||||||
|
|
|
||||||
70
Sources/LuminateDI/DIContainer.swift
Normal file
70
Sources/LuminateDI/DIContainer.swift
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
import Adwaita
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
public final class DIContainer: @unchecked Sendable {
|
||||||
|
|
||||||
|
public static let shared = DIContainer()
|
||||||
|
public private(set) var values = InjectionValues()
|
||||||
|
private var observers: [AnyKeyPath: [UUID: @Sendable () -> Void]] = [:]
|
||||||
|
private let lock = NSLock()
|
||||||
|
|
||||||
|
private init() {}
|
||||||
|
|
||||||
|
public func register<T>(
|
||||||
|
_ keyPath: WritableKeyPath<InjectionValues, T?>,
|
||||||
|
value: T
|
||||||
|
) {
|
||||||
|
lock.withLock {
|
||||||
|
values[keyPath: keyPath] = value
|
||||||
|
}
|
||||||
|
notifyObservers(for: keyPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func resolve<T>(
|
||||||
|
_ keyPath: KeyPath<InjectionValues, T?>
|
||||||
|
) -> T {
|
||||||
|
lock.withLock {
|
||||||
|
guard let value = values[keyPath: keyPath] else {
|
||||||
|
fatalError(
|
||||||
|
"DIContainer: No value registered for \(keyPath). "
|
||||||
|
+ "Call DIContainer.shared.register(\\.key, value:) during app startup."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
func addObserver<T>(
|
||||||
|
for keyPath: KeyPath<InjectionValues, T?>,
|
||||||
|
handler: @escaping @Sendable () -> Void
|
||||||
|
) -> UUID {
|
||||||
|
let id = UUID()
|
||||||
|
lock.withLock {
|
||||||
|
observers[keyPath, default: [:]][id] = handler
|
||||||
|
}
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeObserver(_ id: UUID) {
|
||||||
|
lock.withLock {
|
||||||
|
for keyPath in observers.keys {
|
||||||
|
observers[keyPath]?.removeValue(forKey: id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func notifyObservers(for keyPath: AnyKeyPath) {
|
||||||
|
let handlers: [@Sendable () -> Void] = lock.withLock {
|
||||||
|
Array((observers[keyPath] ?? [:]).values)
|
||||||
|
}
|
||||||
|
handlers.forEach { $0() }
|
||||||
|
}
|
||||||
|
|
||||||
|
public func reset() {
|
||||||
|
lock.withLock {
|
||||||
|
values = InjectionValues()
|
||||||
|
observers.removeAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
Sources/LuminateDI/Injected.swift
Normal file
28
Sources/LuminateDI/Injected.swift
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import Adwaita
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
@propertyWrapper
|
||||||
|
public struct Injected<T> {
|
||||||
|
|
||||||
|
private let keyPath: KeyPath<InjectionValues, T?>
|
||||||
|
private let observerRef: ObserverRef
|
||||||
|
|
||||||
|
public var wrappedValue: T {
|
||||||
|
DIContainer.shared.resolve(keyPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(_ keyPath: KeyPath<InjectionValues, T?>) {
|
||||||
|
self.keyPath = keyPath
|
||||||
|
self.observerRef = ObserverRef(
|
||||||
|
id: DIContainer.shared.addObserver(for: keyPath) {
|
||||||
|
StateManager.updateViews()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class ObserverRef {
|
||||||
|
let id: UUID
|
||||||
|
init(id: UUID) { self.id = id }
|
||||||
|
deinit { DIContainer.shared.removeObserver(id) }
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import LuminateCore
|
||||||
|
|
||||||
public struct InjectionValues {
|
public struct InjectionValues {
|
||||||
|
|
||||||
|
|
@ -9,5 +10,4 @@ public struct InjectionValues {
|
||||||
public var persistence: PersistenceService?
|
public var persistence: PersistenceService?
|
||||||
|
|
||||||
public init() {}
|
public init() {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import Adwaita
|
import Adwaita
|
||||||
import Foundation
|
import Foundation
|
||||||
import LuminateCore
|
import LuminateCore
|
||||||
|
import LuminateDI
|
||||||
|
|
||||||
struct HomePosterCell: View {
|
struct HomePosterCell: View {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import Adwaita
|
import Adwaita
|
||||||
import LuminateCore
|
import LuminateCore
|
||||||
|
import LuminateDI
|
||||||
|
|
||||||
public struct HomeView: View {
|
public struct HomeView: View {
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue