diff --git a/Package.swift b/Package.swift index 7e08558f..e216901c 100644 --- a/Package.swift +++ b/Package.swift @@ -206,7 +206,7 @@ let CommonTargets: [Target] = [ let package = Package( name: "SwiftOCA", platforms: [ - .macOS(.v13), + .macOS(.v14), .iOS(.v16), ], products: CommonProducts + PlatformProducts, diff --git a/Sources/SwiftOCA/OCC/ControlClasses/Root.swift b/Sources/SwiftOCA/OCC/ControlClasses/Root.swift index c322419b..bca80fed 100644 --- a/Sources/SwiftOCA/OCC/ControlClasses/Root.swift +++ b/Sources/SwiftOCA/OCC/ControlClasses/Root.swift @@ -16,33 +16,28 @@ import AsyncExtensions import Foundation -#if canImport(Combine) -import Combine -#elseif canImport(OpenCombine) -import OpenCombine -#else -protocol ObservableObject {} // placeholder -#endif -#if canImport(SwiftUI) -import SwiftUI -#endif - -open class OcaRoot: CustomStringConvertible, ObservableObject, @unchecked Sendable, - OcaKeyPathMarkerProtocol +import Observation + +open class OcaRoot: CustomStringConvertible, @unchecked Sendable, + OcaKeyPathMarkerProtocol, Observable { typealias Root = OcaRoot public internal(set) weak var connectionDelegate: Ocp1Connection? + fileprivate var subscriptionCancellable: Ocp1Connection.SubscriptionCancellable? + fileprivate let _$observationRegistrar = Observation.ObservationRegistrar() // 1.1 open class var classID: OcaClassID { OcaClassID("1") } + private var _classID: StaticProperty { StaticProperty(propertyIDs: [OcaPropertyID("1.1")], value: Self.classID) } // 1.2 open class var classVersion: OcaClassVersionNumber { 3 } + private var _classVersion: StaticProperty { StaticProperty( propertyIDs: [OcaPropertyID("1.2")], @@ -185,7 +180,7 @@ protocol OcaKeyPathMarkerProtocol: AnyObject {} extension PartialKeyPath: @unchecked Sendable {} // fix warning -private extension OcaKeyPathMarkerProtocol where Self: OcaRoot { +extension OcaKeyPathMarkerProtocol where Self: OcaRoot { var allKeyPaths: [String: PartialKeyPath] { _allKeyPaths(value: self).reduce(into: [:]) { if $1.key.hasPrefix("_") { @@ -193,6 +188,19 @@ private extension OcaKeyPathMarkerProtocol where Self: OcaRoot { } } } + + nonisolated func access( + keyPath: KeyPath + ) { + _$observationRegistrar.access(self, keyPath: keyPath) + } + + nonisolated func withMutation( + keyPath: KeyPath, + _ mutation: () throws -> T + ) rethrows -> T { + try _$observationRegistrar.withMutation(of: self, keyPath: keyPath, mutation) + } } public extension OcaRoot { @@ -301,18 +309,6 @@ public extension OcaRoot { AsyncCurrentValueSubject(currentValue) } - #if canImport(SwiftUI) - var binding: Binding { - Binding( - get: { - currentValue - }, - set: { _ in - } - ) - } - #endif - @_spi(SwiftOCAPrivate) @discardableResult public func _getValue( _ object: OcaRoot, diff --git a/Sources/SwiftOCA/OCC/PropertyTypes/BoundedProperty.swift b/Sources/SwiftOCA/OCC/PropertyTypes/BoundedProperty.swift index 0e60b14a..b4d38fd0 100644 --- a/Sources/SwiftOCA/OCC/PropertyTypes/BoundedProperty.swift +++ b/Sources/SwiftOCA/OCC/PropertyTypes/BoundedProperty.swift @@ -137,18 +137,16 @@ public struct OcaBoundedProperty< storage storageKeyPath: ReferenceWritableKeyPath ) -> PropertyValue { get { - #if canImport(SwiftUI) - object[keyPath: storageKeyPath]._storage._referenceObject(_enclosingInstance: object) - #endif + object[keyPath: storageKeyPath]._storage._registerObservable( + _enclosingInstance: object, + wrapped: wrappedKeyPath + ) return object[keyPath: storageKeyPath]._storage ._get( _enclosingInstance: object ) } set { - #if canImport(SwiftUI) - object[keyPath: storageKeyPath]._storage._referenceObject(_enclosingInstance: object) - #endif object[keyPath: storageKeyPath]._storage._set( _enclosingInstance: object, newValue @@ -181,7 +179,7 @@ public struct OcaBoundedProperty< throw Ocp1Error.unhandledEvent } - _storage._send(_enclosingInstance: object, .success(value)) + _storage._send(object, .success(value)) } public var projectedValue: Self { @@ -215,23 +213,3 @@ public struct OcaBoundedProperty< try await _storage.setValueIfMutable(object, value) } } - -#if canImport(SwiftUI) -public extension OcaBoundedProperty { - var binding: Binding { - Binding( - get: { - if let object = _storage.object { - _storage._get(_enclosingInstance: object) - } else { - .initial - } - }, - set: { - guard let object = _storage.object else { return } - _storage._set(_enclosingInstance: object, $0) - } - ) - } -} -#endif diff --git a/Sources/SwiftOCA/OCC/PropertyTypes/Property.swift b/Sources/SwiftOCA/OCC/PropertyTypes/Property.swift index 29156a85..5e7cdde2 100644 --- a/Sources/SwiftOCA/OCC/PropertyTypes/Property.swift +++ b/Sources/SwiftOCA/OCC/PropertyTypes/Property.swift @@ -20,6 +20,7 @@ import Foundation #if canImport(SwiftUI) import SwiftUI #endif +import Observation public struct OcaPropertyResolutionFlags: OptionSet, Sendable { public typealias RawValue = UInt32 @@ -61,10 +62,6 @@ public protocol OcaPropertyRepresentable: CustomStringConvertible { func getJsonValue(_ object: OcaRoot, flags: OcaPropertyResolutionFlags) async throws -> [String: Any] - - #if canImport(SwiftUI) - var binding: Binding { get } - #endif } public extension OcaPropertyRepresentable { @@ -164,6 +161,8 @@ public struct OcaProperty: Codable, Sendable, } } + var _send: (@Sendable (_: OcaRoot?, _: PropertyValue) -> ())! + @_spi(SwiftOCAPrivate) public let subject: AsyncCurrentValueSubject @@ -193,27 +192,10 @@ public struct OcaProperty: Codable, Sendable, nonmutating set { fatalError() } } - #if canImport(SwiftUI) - private(set) weak var object: OcaRoot? - - mutating func _referenceObject(_enclosingInstance object: OcaRoot) { - self.object = object - } - #endif - public var currentValue: PropertyValue { subject.value } - func _send(_enclosingInstance object: OcaRoot, _ state: PropertyValue) { - #if canImport(Combine) || canImport(OpenCombine) - DispatchQueue.main.async { - object.objectWillChange.send() - } - #endif - subject.send(state) - } - /// It's not possible to wrap `subscript(_enclosingInstance:wrapped:storage:)` because we can't /// cast struct key paths to `ReferenceWritableKeyPath`. For property wrapper wrappers, use /// these internal get/set functions. @@ -243,9 +225,9 @@ public struct OcaProperty: Codable, Sendable, try await setValueIfMutable(object, value) } catch is CancellationError { // if task cancelled due to a view being dismissed, reset state to initial - _send(_enclosingInstance: object, .initial) + _send(object, .initial) } catch { - _send(_enclosingInstance: object, .failure(error)) + _send(object, .failure(error)) await object.connectionDelegate?.logger.trace( "set property handler for \(object) property \(propertyID) received error from device: \(error)" ) @@ -258,22 +240,34 @@ public struct OcaProperty: Codable, Sendable, } } + mutating func _registerObservable( + _enclosingInstance object: T, + wrapped wrappedKeyPath: ReferenceWritableKeyPath + ) { + object.access(keyPath: wrappedKeyPath) + + _send = { @Sendable [subject] object, newValue in + guard let object else { return } + object.withMutation(keyPath: wrappedKeyPath) { + subject.send(newValue) + } + } + } + public static subscript( _enclosingInstance object: T, wrapped wrappedKeyPath: ReferenceWritableKeyPath, storage storageKeyPath: ReferenceWritableKeyPath ) -> PropertyValue { get { - #if canImport(SwiftUI) - object[keyPath: storageKeyPath]._referenceObject(_enclosingInstance: object) - #endif + object[keyPath: storageKeyPath]._registerObservable( + _enclosingInstance: object, + wrapped: wrappedKeyPath + ) return object[keyPath: storageKeyPath] ._get(_enclosingInstance: object) } set { - #if canImport(SwiftUI) - object[keyPath: storageKeyPath]._referenceObject(_enclosingInstance: object) - #endif object[keyPath: storageKeyPath] ._set(_enclosingInstance: object, newValue) } @@ -294,6 +288,7 @@ public struct OcaProperty: Codable, Sendable, self.setMethodID = setMethodID subject = AsyncCurrentValueSubject(PropertyValue.initial) self.setValueTransformer = setValueTransformer + _send = { @Sendable [subject] in subject.send($1) } } public init( @@ -342,18 +337,18 @@ public struct OcaProperty: Codable, Sendable, let returnValue: Value = try await object.sendCommandRrq(methodID: getMethodID) if flags.contains(.cacheValue) { - _send(_enclosingInstance: object, .success(returnValue)) + _send(object, .success(returnValue)) } return returnValue } catch is CancellationError { if flags.contains(.cacheErrors) { - _send(_enclosingInstance: object, .initial) + _send(object, .initial) } throw CancellationError() } catch { if flags.contains(.cacheErrors) { - _send(_enclosingInstance: object, .failure(error)) + _send(object, .failure(error)) } await object.connectionDelegate?.logger .trace( @@ -391,7 +386,7 @@ public struct OcaProperty: Codable, Sendable, ) // if we're not expecting an event, then be sure to update it here - _send(_enclosingInstance: object, .success(value)) + _send(object, .success(value)) } } @@ -400,7 +395,7 @@ public struct OcaProperty: Codable, Sendable, } public func refresh(_ object: OcaRoot) async { - _send(_enclosingInstance: object, .initial) + _send(object, .initial) } func onEvent(_ object: OcaRoot, event: OcaEvent, eventData data: Data) throws { @@ -427,7 +422,7 @@ public struct OcaProperty: Codable, Sendable, } fallthrough case .currentChanged: - _send(_enclosingInstance: object, .success(eventData.propertyValue)) + _send(object, .success(eventData.propertyValue)) default: throw Ocp1Error.unhandledEvent } @@ -507,23 +502,3 @@ extension OcaProperty.PropertyValue: Hashable where Value: Hashable & Codable { } } } - -#if canImport(SwiftUI) -public extension OcaProperty { - var binding: Binding { - Binding( - get: { - if let object { - _get(_enclosingInstance: object) - } else { - .initial - } - }, - set: { - guard let object else { return } - _set(_enclosingInstance: object, $0) - } - ) - } -} -#endif diff --git a/Sources/SwiftOCA/OCC/PropertyTypes/VectorProperty.swift b/Sources/SwiftOCA/OCC/PropertyTypes/VectorProperty.swift index 7cbed5f2..ace00e8d 100644 --- a/Sources/SwiftOCA/OCC/PropertyTypes/VectorProperty.swift +++ b/Sources/SwiftOCA/OCC/PropertyTypes/VectorProperty.swift @@ -111,16 +111,14 @@ public struct OcaVectorProperty< storage storageKeyPath: ReferenceWritableKeyPath ) -> PropertyValue { get { - #if canImport(SwiftUI) - object[keyPath: storageKeyPath]._storage._referenceObject(_enclosingInstance: object) - #endif + object[keyPath: storageKeyPath]._storage._registerObservable( + _enclosingInstance: object, + wrapped: wrappedKeyPath + ) return object[keyPath: storageKeyPath]._storage ._get(_enclosingInstance: object) } set { - #if canImport(SwiftUI) - object[keyPath: storageKeyPath]._storage._referenceObject(_enclosingInstance: object) - #endif object[keyPath: storageKeyPath]._storage._set(_enclosingInstance: object, newValue) } } @@ -152,7 +150,7 @@ public struct OcaVectorProperty< xy.x = subjectValue.x xy.y = eventData.propertyValue } - _storage._send(_enclosingInstance: object, .success(xy)) + _storage._send(object, .success(xy)) default: throw Ocp1Error.unhandledEvent } @@ -188,23 +186,3 @@ public struct OcaVectorProperty< throw Ocp1Error.notImplemented } } - -#if canImport(SwiftUI) -public extension OcaVectorProperty { - var binding: Binding { - Binding( - get: { - if let object = _storage.object { - _storage._get(_enclosingInstance: object) - } else { - .initial - } - }, - set: { - guard let object = _storage.object else { return } - _storage._set(_enclosingInstance: object, $0) - } - ) - } -} -#endif diff --git a/Sources/SwiftOCA/OCP.1/Ocp1Connection+Connect.swift b/Sources/SwiftOCA/OCP.1/Ocp1Connection+Connect.swift index 6e09f42c..80fff499 100644 --- a/Sources/SwiftOCA/OCP.1/Ocp1Connection+Connect.swift +++ b/Sources/SwiftOCA/OCP.1/Ocp1Connection+Connect.swift @@ -19,11 +19,6 @@ import AsyncExtensions @preconcurrency import Foundation import Logging -#if canImport(Combine) -import Combine -#elseif canImport(OpenCombine) -import OpenCombine -#endif import SystemPackage private extension Ocp1Error { @@ -163,9 +158,6 @@ extension Ocp1Connection { private func _updateConnectionState(_ connectionState: Ocp1ConnectionState) { logger.trace("_updateConnectionState: \(_connectionState.value) => \(connectionState)") _connectionState.send(connectionState) - #if canImport(Combine) || canImport(OpenCombine) - objectWillChange.send() - #endif } /// update the device connection state, called from the connection (for diff --git a/Sources/SwiftOCAUI/Conformances/OcaProperty+Binding.swift b/Sources/SwiftOCAUI/Conformances/OcaProperty+Binding.swift new file mode 100644 index 00000000..81bbbf72 --- /dev/null +++ b/Sources/SwiftOCAUI/Conformances/OcaProperty+Binding.swift @@ -0,0 +1,23 @@ +// +// OcaProperty+Binding.swift +// SwiftOCAUI +// +// Created by Luke Howard on 1/12/2024. +// + +import SwiftUI +@_spi(SwiftOCAPrivate) +import SwiftOCA + +public extension OcaPropertySubjectRepresentable { + var binding: Binding { + Binding( + get: { + subject.value + }, + set: { _ in + // + } + ) + } +} diff --git a/Sources/SwiftOCAUI/Views/Managers/DeviceManager.swift b/Sources/SwiftOCAUI/Views/Managers/DeviceManager.swift index ec0c6ea3..6848e51d 100644 --- a/Sources/SwiftOCAUI/Views/Managers/DeviceManager.swift +++ b/Sources/SwiftOCAUI/Views/Managers/DeviceManager.swift @@ -18,11 +18,11 @@ import SwiftOCA import SwiftUI struct OcaDeviceManagerView: View, OcaView { - @StateObject + @State var object: OcaDeviceManager init(_ object: OcaRoot) { - _object = StateObject(wrappedValue: object as! OcaDeviceManager) + _object = State(wrappedValue: object as! OcaDeviceManager) } public var body: some View { diff --git a/Sources/SwiftOCAUI/Views/NavigationLabel.swift b/Sources/SwiftOCAUI/Views/NavigationLabel.swift index c322fe04..cd923260 100644 --- a/Sources/SwiftOCAUI/Views/NavigationLabel.swift +++ b/Sources/SwiftOCAUI/Views/NavigationLabel.swift @@ -28,11 +28,11 @@ extension OcaRoot { } struct OcaNavigationLabel: View, OcaView { - @StateObject + @State var object: OcaRoot init(_ object: OcaRoot) { - _object = StateObject(wrappedValue: object) + _object = State(wrappedValue: object) } public var body: some View { diff --git a/Sources/SwiftOCAUI/Views/PropertyTableView.swift b/Sources/SwiftOCAUI/Views/PropertyTableView.swift index 7c37cb1a..36c2fba2 100644 --- a/Sources/SwiftOCAUI/Views/PropertyTableView.swift +++ b/Sources/SwiftOCAUI/Views/PropertyTableView.swift @@ -41,11 +41,11 @@ extension OcaPropertyRepresentable { } struct OcaPropertyTableView: OcaView { - @StateObject + @State var object: OcaRoot init(_ object: OcaRoot) { - _object = StateObject(wrappedValue: object) + _object = State(wrappedValue: object) } public var body: some View { diff --git a/Sources/SwiftOCAUI/Views/Workers/Actuators/BooleanActuatorView.swift b/Sources/SwiftOCAUI/Views/Workers/Actuators/BooleanActuatorView.swift index 55b17b0d..2876dc74 100644 --- a/Sources/SwiftOCAUI/Views/Workers/Actuators/BooleanActuatorView.swift +++ b/Sources/SwiftOCAUI/Views/Workers/Actuators/BooleanActuatorView.swift @@ -38,11 +38,11 @@ private extension Binding where Value == OcaProperty.PropertyValue { } public struct OcaBooleanView: OcaView { - @StateObject + @State var object: OcaBooleanActuator public init(_ object: OcaRoot) { - _object = StateObject(wrappedValue: object as! OcaBooleanActuator) + _object = State(wrappedValue: object as! OcaBooleanActuator) } public var body: some View { diff --git a/Sources/SwiftOCAUI/Views/Workers/Actuators/Float32ActuatorView.swift b/Sources/SwiftOCAUI/Views/Workers/Actuators/Float32ActuatorView.swift index 7db01c5d..c20d5e9d 100644 --- a/Sources/SwiftOCAUI/Views/Workers/Actuators/Float32ActuatorView.swift +++ b/Sources/SwiftOCAUI/Views/Workers/Actuators/Float32ActuatorView.swift @@ -24,11 +24,11 @@ extension OcaFloat32Actuator: OcaViewRepresentable { } public struct OcaFloat32ActuatorView: OcaView { - @StateObject + @State var object: OcaFloat32Actuator public init(_ object: OcaRoot) { - _object = StateObject(wrappedValue: object as! OcaFloat32Actuator) + _object = State(wrappedValue: object as! OcaFloat32Actuator) } public var body: some View { diff --git a/Sources/SwiftOCAUI/Views/Workers/Actuators/GainView.swift b/Sources/SwiftOCAUI/Views/Workers/Actuators/GainView.swift index 3f14315c..c442e425 100644 --- a/Sources/SwiftOCAUI/Views/Workers/Actuators/GainView.swift +++ b/Sources/SwiftOCAUI/Views/Workers/Actuators/GainView.swift @@ -24,11 +24,11 @@ extension OcaGain: OcaViewRepresentable { } public struct OcaGainView: OcaView { - @StateObject + @State var object: OcaGain public init(_ object: OcaRoot) { - _object = StateObject(wrappedValue: object as! OcaGain) + _object = State(wrappedValue: object as! OcaGain) } public var body: some View { diff --git a/Sources/SwiftOCAUI/Views/Workers/Actuators/MuteView.swift b/Sources/SwiftOCAUI/Views/Workers/Actuators/MuteView.swift index 4838d8f9..1c353163 100644 --- a/Sources/SwiftOCAUI/Views/Workers/Actuators/MuteView.swift +++ b/Sources/SwiftOCAUI/Views/Workers/Actuators/MuteView.swift @@ -38,11 +38,11 @@ private extension Binding where Value == OcaProperty.PropertyValue } public struct OcaMuteView: OcaView { - @StateObject + @State var object: OcaMute public init(_ object: OcaRoot) { - _object = StateObject(wrappedValue: object as! OcaMute) + _object = State(wrappedValue: object as! OcaMute) } public var body: some View { diff --git a/Sources/SwiftOCAUI/Views/Workers/Actuators/PanBalanceView.swift b/Sources/SwiftOCAUI/Views/Workers/Actuators/PanBalanceView.swift index c8022ab3..012b14d2 100644 --- a/Sources/SwiftOCAUI/Views/Workers/Actuators/PanBalanceView.swift +++ b/Sources/SwiftOCAUI/Views/Workers/Actuators/PanBalanceView.swift @@ -25,11 +25,11 @@ extension OcaPanBalance: OcaViewRepresentable { } public struct OcaPanBalanceView: OcaView { - @StateObject + @State var object: OcaPanBalance public init(_ object: OcaRoot) { - _object = StateObject(wrappedValue: object as! OcaPanBalance) + _object = State(wrappedValue: object as! OcaPanBalance) } public var body: some View { diff --git a/Sources/SwiftOCAUI/Views/Workers/Actuators/PolarityView.swift b/Sources/SwiftOCAUI/Views/Workers/Actuators/PolarityView.swift index 044a0e20..5b45a838 100644 --- a/Sources/SwiftOCAUI/Views/Workers/Actuators/PolarityView.swift +++ b/Sources/SwiftOCAUI/Views/Workers/Actuators/PolarityView.swift @@ -38,11 +38,11 @@ private extension Binding where Value == OcaProperty.PropertyV } public struct OcaPolarityView: OcaView { - @StateObject + @State var object: OcaPolarity public init(_ object: OcaRoot) { - _object = StateObject(wrappedValue: object as! OcaPolarity) + _object = State(wrappedValue: object as! OcaPolarity) } public var body: some View { diff --git a/Sources/SwiftOCAUI/Views/Workers/BlockNavigationSplitView.swift b/Sources/SwiftOCAUI/Views/Workers/BlockNavigationSplitView.swift index e5353625..860efebb 100644 --- a/Sources/SwiftOCAUI/Views/Workers/BlockNavigationSplitView.swift +++ b/Sources/SwiftOCAUI/Views/Workers/BlockNavigationSplitView.swift @@ -24,7 +24,7 @@ struct OcaBlockNavigationSplitView: OcaView { var oNoPath @Environment(\.lastError) var lastError - @StateObject + @State var object: OcaBlock @State var members: [OcaRoot]? @@ -34,7 +34,7 @@ struct OcaBlockNavigationSplitView: OcaView { var selectedONo: OcaONo? = nil init(_ object: OcaRoot) { - _object = StateObject(wrappedValue: object as! OcaBlock) + _object = State(wrappedValue: object as! OcaBlock) } var selectedObject: OcaRoot? { diff --git a/Sources/SwiftOCAUI/Views/Workers/BlockNavigationStackView.swift b/Sources/SwiftOCAUI/Views/Workers/BlockNavigationStackView.swift index f12fa860..927c28e6 100644 --- a/Sources/SwiftOCAUI/Views/Workers/BlockNavigationStackView.swift +++ b/Sources/SwiftOCAUI/Views/Workers/BlockNavigationStackView.swift @@ -18,7 +18,7 @@ import SwiftOCA import SwiftUI struct OcaBlockNavigationStackView: OcaView { - @StateObject + @State var object: OcaBlock @Environment(\.navigationPath) var oNoPath @@ -32,7 +32,7 @@ struct OcaBlockNavigationStackView: OcaView { var selectedONo: OcaONo? = nil init(_ object: OcaRoot) { - _object = StateObject(wrappedValue: object as! OcaBlock) + _object = State(wrappedValue: object as! OcaBlock) } public var body: some View { diff --git a/Sources/SwiftOCAUI/Views/Workers/MatrixNavigationSplitView.swift b/Sources/SwiftOCAUI/Views/Workers/MatrixNavigationSplitView.swift index b5dfa484..19da1b79 100644 --- a/Sources/SwiftOCAUI/Views/Workers/MatrixNavigationSplitView.swift +++ b/Sources/SwiftOCAUI/Views/Workers/MatrixNavigationSplitView.swift @@ -18,7 +18,7 @@ import SwiftOCA import SwiftUI struct OcaMatrixNavigationSplitView: OcaView { - @StateObject + @State var object: OcaMatrix @Environment(\.navigationPath) var oNoPath @@ -32,7 +32,7 @@ struct OcaMatrixNavigationSplitView: OcaView { var hasContainerMembers = false init(_ object: OcaRoot) { - _object = StateObject(wrappedValue: object as! OcaMatrix) + _object = State(wrappedValue: object as! OcaMatrix) } public var body: some View { diff --git a/Sources/SwiftOCAUI/Views/Workers/Sensors/BasicSensorViews.swift b/Sources/SwiftOCAUI/Views/Workers/Sensors/BasicSensorViews.swift index 60137aba..56e90b83 100644 --- a/Sources/SwiftOCAUI/Views/Workers/Sensors/BasicSensorViews.swift +++ b/Sources/SwiftOCAUI/Views/Workers/Sensors/BasicSensorViews.swift @@ -24,11 +24,11 @@ extension OcaGenericBasicSensor: OcaViewRepresentable { } public struct OcaGenericBasicSensorView: OcaView { - @StateObject + @State var object: OcaGenericBasicSensor public init(_ object: OcaRoot) { - _object = StateObject(wrappedValue: object as! OcaGenericBasicSensor) + _object = State(wrappedValue: object as! OcaGenericBasicSensor) } public var body: some View { @@ -44,11 +44,11 @@ extension OcaBooleanSensor: OcaViewRepresentable { } public struct OcaBooleanSensorView: OcaView { - @StateObject + @State var object: OcaBooleanSensor public init(_ object: OcaRoot) { - _object = StateObject(wrappedValue: object as! OcaBooleanSensor) + _object = State(wrappedValue: object as! OcaBooleanSensor) } public var body: some View { diff --git a/Sources/SwiftOCAUI/Views/Workers/Sensors/IdentificationSensorView.swift b/Sources/SwiftOCAUI/Views/Workers/Sensors/IdentificationSensorView.swift index 0e003e8a..0e3c2371 100644 --- a/Sources/SwiftOCAUI/Views/Workers/Sensors/IdentificationSensorView.swift +++ b/Sources/SwiftOCAUI/Views/Workers/Sensors/IdentificationSensorView.swift @@ -23,6 +23,7 @@ extension OcaIdentificationSensor: OcaViewRepresentable { } } +@Observable private final class OcaIdentificationState: ObservableObject { var state: Bool = false @@ -34,14 +35,14 @@ private final class OcaIdentificationState: ObservableObject { } public struct OcaIdentificationSensorView: OcaView { - @StateObject + @State var object: OcaIdentificationSensor - @StateObject + @State fileprivate var isIdentifying = OcaIdentificationState() public init(_ object: OcaRoot) { - _object = StateObject(wrappedValue: object as! OcaIdentificationSensor) + _object = State(wrappedValue: object as! OcaIdentificationSensor) } public var body: some View { diff --git a/Sources/SwiftOCAUI/Views/Workers/Sensors/LevelSensorView.swift b/Sources/SwiftOCAUI/Views/Workers/Sensors/LevelSensorView.swift index 78c76e7c..82ec9394 100644 --- a/Sources/SwiftOCAUI/Views/Workers/Sensors/LevelSensorView.swift +++ b/Sources/SwiftOCAUI/Views/Workers/Sensors/LevelSensorView.swift @@ -59,11 +59,11 @@ extension OcaLevelSensor: OcaViewRepresentable { } public struct OcaLevelSensorView: OcaView { - @StateObject + @State var object: OcaLevelSensor public init(_ object: OcaRoot) { - _object = StateObject(wrappedValue: object as! OcaLevelSensor) + _object = State(wrappedValue: object as! OcaLevelSensor) } public var body: some View { diff --git a/SwiftOCA.xcodeproj/project.pbxproj b/SwiftOCA.xcodeproj/project.pbxproj index 455375f6..19274514 100644 --- a/SwiftOCA.xcodeproj/project.pbxproj +++ b/SwiftOCA.xcodeproj/project.pbxproj @@ -35,6 +35,7 @@ D32229D42ABC270900B56B6B /* Ocp1IORingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D32229CC2ABC270900B56B6B /* Ocp1IORingController.swift */; }; D32229D62ABD26E100B56B6B /* DeviceEndpointRegistrar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D32229D52ABD26E100B56B6B /* DeviceEndpointRegistrar.swift */; }; D32437CF2BA9276700C89102 /* AnyCodable in Frameworks */ = {isa = PBXBuildFile; productRef = D32437CE2BA9276700C89102 /* AnyCodable */; }; + D324D9B52CFC5A3800232790 /* OcaProperty+Binding.swift in Sources */ = {isa = PBXBuildFile; fileRef = D324D9B42CFC5A3800232790 /* OcaProperty+Binding.swift */; }; D32C49DD2B5102A300D73201 /* Logging in Frameworks */ = {isa = PBXBuildFile; productRef = D32C49DC2B5102A300D73201 /* Logging */; }; D33A35A72B2FB1D600FEDC43 /* MediaClock3.swift in Sources */ = {isa = PBXBuildFile; fileRef = D33A35A62B2FB1D600FEDC43 /* MediaClock3.swift */; }; D33A35A92B2FB7BE00FEDC43 /* MediaClockManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D33A35A82B2FB7BE00FEDC43 /* MediaClockManager.swift */; }; @@ -353,6 +354,7 @@ D32229CB2ABC270900B56B6B /* Ocp1IORingDeviceEndpoint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Ocp1IORingDeviceEndpoint.swift; sourceTree = ""; }; D32229CC2ABC270900B56B6B /* Ocp1IORingController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Ocp1IORingController.swift; sourceTree = ""; }; D32229D52ABD26E100B56B6B /* DeviceEndpointRegistrar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceEndpointRegistrar.swift; sourceTree = ""; }; + D324D9B42CFC5A3800232790 /* OcaProperty+Binding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OcaProperty+Binding.swift"; sourceTree = ""; }; D33A35A62B2FB1D600FEDC43 /* MediaClock3.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaClock3.swift; sourceTree = ""; }; D33A35A82B2FB7BE00FEDC43 /* MediaClockManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaClockManager.swift; sourceTree = ""; }; D33A35AA2B2FBD0700FEDC43 /* DeviceTimeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceTimeManager.swift; sourceTree = ""; }; @@ -1042,6 +1044,7 @@ D3DA69F32A3DF988001250A1 /* EnvironmentValues.swift */, D3E6E2792A417FAE00BF7095 /* OcaArray2D+Extras.swift */, D3E6E2872A43BD1900BF7095 /* OcaDB+Linear.swift */, + D324D9B42CFC5A3800232790 /* OcaProperty+Binding.swift */, ); path = Conformances; sourceTree = ""; @@ -1982,6 +1985,7 @@ D3028C1E2A418BAE00B8DB42 /* BonjourDeviceView.swift in Sources */, D3DA69E42A3DCA75001250A1 /* NavigationLabel.swift in Sources */, D3DA69EB2A3DCD60001250A1 /* BlockNavigationStackView.swift in Sources */, + D324D9B52CFC5A3800232790 /* OcaProperty+Binding.swift in Sources */, D3E6E2812A43B33D00BF7095 /* PolarityView.swift in Sources */, D3DA69F72A3FE538001250A1 /* DynamicStack.swift in Sources */, D30644092A77EB160063DA65 /* BasicSensorViews.swift in Sources */, @@ -2029,7 +2033,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; EXECUTABLE_PREFIX = lib; - MACOSX_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 14.6; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -2045,7 +2049,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; EXECUTABLE_PREFIX = lib; - MACOSX_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 14.6; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; @@ -2058,7 +2062,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = T53Q9CN4T9; ENABLE_HARDENED_RUNTIME = YES; - MACOSX_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 14.6; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -2072,7 +2076,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = T53Q9CN4T9; ENABLE_HARDENED_RUNTIME = YES; - MACOSX_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 14.6; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; @@ -2092,7 +2096,7 @@ "@executable_path/../Frameworks", "@loader_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 14.6; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.padl.SwiftOCATests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2116,7 +2120,7 @@ "@executable_path/../Frameworks", "@loader_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 14.6; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.padl.SwiftOCATests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2139,7 +2143,7 @@ "@executable_path/../Frameworks", "@loader_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 14.6; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.padl.SwiftOCADeviceTests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2163,7 +2167,7 @@ "@executable_path/../Frameworks", "@loader_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 14.6; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.padl.SwiftOCADeviceTests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2183,7 +2187,7 @@ EXECUTABLE_PREFIX = lib; GCC_C_LANGUAGE_STANDARD = gnu17; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MACOSX_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 14.6; OTHER_SWIFT_FLAGS = "-package-name swiftoca -parse-stdlib"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -2203,7 +2207,7 @@ EXECUTABLE_PREFIX = lib; GCC_C_LANGUAGE_STANDARD = gnu17; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MACOSX_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 14.6; OTHER_SWIFT_FLAGS = "-package-name swiftoca -parse-stdlib"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -2341,7 +2345,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; EXECUTABLE_PREFIX = lib; - MACOSX_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 14.6; OTHER_SWIFT_FLAGS = "-package-name swiftoca"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -2362,7 +2366,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; EXECUTABLE_PREFIX = lib; - MACOSX_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 14.6; OTHER_SWIFT_FLAGS = "-package-name swiftoca"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -2395,7 +2399,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 14.6; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.padl.OCABrowser; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2433,7 +2437,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 14.6; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.padl.OCABrowser; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2458,7 +2462,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; EXECUTABLE_PREFIX = lib; - MACOSX_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 14.6; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "watchsimulator watchos macosx iphonesimulator iphoneos driverkit appletvsimulator appletvos"; @@ -2478,7 +2482,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; EXECUTABLE_PREFIX = lib; - MACOSX_DEPLOYMENT_TARGET = 13.0; + MACOSX_DEPLOYMENT_TARGET = 14.6; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "watchsimulator watchos macosx iphonesimulator iphoneos driverkit appletvsimulator appletvos";