Skip to content

Commit a8e401a

Browse files
committed
SwiftOCAUI: remove binding() extensions
they no longer work after Combine/Observable support was removed
1 parent 65e114a commit a8e401a

File tree

10 files changed

+170
-154
lines changed

10 files changed

+170
-154
lines changed

Sources/SwiftOCAUI/Conformances/OcaRoot+Binding.swift

Lines changed: 0 additions & 72 deletions
This file was deleted.
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
//
2+
// Copyright (c) 2024-2025 PADL Software Pty Ltd
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the License);
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an 'AS IS' BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
17+
@_spi(SwiftOCAPrivate)
18+
import SwiftOCA
19+
import SwiftUI
20+
21+
public struct OcaPropertyView<Value: Sendable, Resolved: View>: View {
22+
let object: OcaRoot
23+
let property: any OcaPropertyRepresentable
24+
let content: (Value) -> Resolved
25+
26+
@State
27+
private var currentValue: Result<Value, Error>?
28+
29+
public init(
30+
_ object: OcaRoot,
31+
_ property: any OcaPropertyRepresentable,
32+
@ViewBuilder content: @escaping (Value) -> Resolved
33+
) {
34+
self.object = object
35+
self.property = property
36+
self.content = content
37+
}
38+
39+
public var body: some View {
40+
Group {
41+
if let currentValue {
42+
switch currentValue {
43+
case let .success(value):
44+
content(value)
45+
case let .failure(error):
46+
Text("Error: \(error.localizedDescription)").foregroundStyle(.tertiary)
47+
}
48+
} else {
49+
ProgressView()
50+
}
51+
}
52+
.task {
53+
await property.subscribe(object)
54+
do {
55+
for try await result in property.async {
56+
switch result {
57+
case let .success(value):
58+
if let typed = value as? Value {
59+
currentValue = .success(typed)
60+
} else {
61+
currentValue = .failure(Ocp1Error.status(.badFormat))
62+
}
63+
case let .failure(error):
64+
currentValue = .failure(error)
65+
}
66+
}
67+
} catch {}
68+
}
69+
}
70+
}
71+
72+
public struct OcaWritablePropertyView<Value: Sendable, Resolved: View>: View {
73+
let object: OcaRoot
74+
let property: any OcaPropertySubjectRepresentable
75+
let content: (Binding<Value>) -> Resolved
76+
77+
@State
78+
private var currentValue: Value?
79+
80+
public init(
81+
_ object: OcaRoot,
82+
_ property: any OcaPropertyRepresentable,
83+
@ViewBuilder content: @escaping (Binding<Value>) -> Resolved
84+
) {
85+
self.object = object
86+
self.property = property as! (any OcaPropertySubjectRepresentable)
87+
self.content = content
88+
}
89+
90+
private var binding: Binding<Value> {
91+
Binding<Value>(
92+
get: { currentValue! },
93+
set: { newValue in
94+
currentValue = newValue
95+
Task {
96+
try? await property._setValue(object, newValue)
97+
}
98+
}
99+
)
100+
}
101+
102+
public var body: some View {
103+
Group {
104+
if currentValue != nil {
105+
content(binding)
106+
} else {
107+
ProgressView()
108+
}
109+
}
110+
.task {
111+
await property.subscribe(object)
112+
do {
113+
for try await result in property.async {
114+
if case let .success(value) = result, let typed = value as? Value {
115+
currentValue = typed
116+
}
117+
}
118+
} catch {}
119+
}
120+
}
121+
}

Sources/SwiftOCAUI/Views/Utility/LogSliderView.swift

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,3 @@ struct OcaLogSliderView: View {
5656
.id(value.value)
5757
}
5858
}
59-
60-
extension Binding where Value == OcaProperty<OcaBoundedPropertyValue<OcaFloat32>>.PropertyValue {
61-
var value: Binding<OcaBoundedPropertyValue<OcaFloat32>> {
62-
Binding<OcaBoundedPropertyValue<OcaFloat32>>(get: {
63-
if case let .success(value) = self.wrappedValue {
64-
value
65-
} else {
66-
OcaBoundedPropertyValue(value: 0.0, in: 0.0...0.0)
67-
}
68-
}, set: { newValue in
69-
self.wrappedValue = .success(newValue)
70-
})
71-
}
72-
}

Sources/SwiftOCAUI/Views/Workers/Actuators/BooleanActuatorView.swift

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,6 @@ extension OcaBooleanActuator: OcaViewRepresentable {
2323
}
2424
}
2525

26-
private extension Binding where Value == OcaProperty<OcaBoolean>.PropertyValue {
27-
var value: Binding<Bool> {
28-
Binding<Bool>(get: {
29-
if case let .success(isOn) = self.wrappedValue {
30-
isOn
31-
} else {
32-
false
33-
}
34-
}, set: { isOn in
35-
self.wrappedValue = .success(isOn)
36-
})
37-
}
38-
}
39-
4026
public struct OcaBooleanView: OcaView {
4127
@State
4228
var object: OcaBooleanActuator
@@ -46,9 +32,10 @@ public struct OcaBooleanView: OcaView {
4632
}
4733

4834
public var body: some View {
49-
Toggle(isOn: object.binding(for: object.$setting).value) {}
50-
.toggleStyle(SymbolToggleStyle(systemImage: "circle.fill", activeColor: .accentColor))
51-
.padding()
52-
.showProgressIfWaiting(object.$setting)
35+
OcaWritablePropertyView(object, object.$setting) { (value: Binding<OcaBoolean>) in
36+
Toggle(isOn: value) {}
37+
.toggleStyle(SymbolToggleStyle(systemImage: "circle.fill", activeColor: .accentColor))
38+
.padding()
39+
}
5340
}
5441
}

Sources/SwiftOCAUI/Views/Workers/Actuators/Float32ActuatorView.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@ public struct OcaFloat32ActuatorView: OcaView {
3232
}
3333

3434
public var body: some View {
35-
OcaLogSliderView(value: object.binding(for: object.$setting).value)
36-
.showProgressIfWaiting(object.$setting)
35+
OcaWritablePropertyView(
36+
object,
37+
object.$setting
38+
) { (value: Binding<OcaBoundedPropertyValue<OcaFloat32>>) in
39+
OcaLogSliderView(value: value)
40+
}
3741
}
3842
}

Sources/SwiftOCAUI/Views/Workers/Actuators/GainView.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@ public struct OcaGainView: OcaView {
3232
}
3333

3434
public var body: some View {
35-
OcaLogSliderView(value: object.binding(for: object.$gain).value)
36-
.showProgressIfWaiting(object.$gain)
35+
OcaWritablePropertyView(
36+
object,
37+
object.$gain
38+
) { (value: Binding<OcaBoundedPropertyValue<OcaDB>>) in
39+
OcaLogSliderView(value: value)
40+
}
3741
}
3842
}

Sources/SwiftOCAUI/Views/Workers/Actuators/MuteView.swift

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,6 @@ extension OcaMute: OcaViewRepresentable {
2323
}
2424
}
2525

26-
private extension Binding where Value == OcaProperty<OcaMuteState>.PropertyValue {
27-
var value: Binding<Bool> {
28-
Binding<Bool>(get: {
29-
if case let .success(muteState) = self.wrappedValue {
30-
muteState == .muted
31-
} else {
32-
false
33-
}
34-
}, set: { isOn in
35-
self.wrappedValue = .success(isOn ? .muted : .unmuted)
36-
})
37-
}
38-
}
39-
4026
public struct OcaMuteView: OcaView {
4127
@State
4228
var object: OcaMute
@@ -46,12 +32,17 @@ public struct OcaMuteView: OcaView {
4632
}
4733

4834
public var body: some View {
49-
Toggle(isOn: object.binding(for: object.$state).value) {}
50-
.toggleStyle(SymbolToggleStyle(
51-
systemImage: "speaker.slash.circle.fill",
52-
activeColor: .red
53-
))
54-
.padding()
55-
.showProgressIfWaiting(object.$state)
35+
OcaWritablePropertyView(object, object.$state) { (value: Binding<OcaMuteState>) in
36+
let boolBinding = Binding<Bool>(
37+
get: { value.wrappedValue == .muted },
38+
set: { value.wrappedValue = $0 ? .muted : .unmuted }
39+
)
40+
Toggle(isOn: boolBinding) {}
41+
.toggleStyle(SymbolToggleStyle(
42+
systemImage: "speaker.slash.circle.fill",
43+
activeColor: .red
44+
))
45+
.padding()
46+
}
5647
}
5748
}

Sources/SwiftOCAUI/Views/Workers/Actuators/PanBalanceView.swift

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,12 @@ public struct OcaPanBalanceView: OcaView {
3333
}
3434

3535
public var body: some View {
36-
OcaVariableSliderView(value: object.binding(for: object.$position).value)
37-
.valueSliderStyle(HorizontalValueSliderStyle())
38-
.showProgressIfWaiting(object.$position)
36+
OcaWritablePropertyView(
37+
object,
38+
object.$position
39+
) { (value: Binding<OcaBoundedPropertyValue<OcaFloat32>>) in
40+
OcaVariableSliderView(value: value)
41+
.valueSliderStyle(HorizontalValueSliderStyle())
42+
}
3943
}
4044
}

Sources/SwiftOCAUI/Views/Workers/Actuators/PolarityView.swift

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,6 @@ extension OcaPolarity: OcaViewRepresentable {
2323
}
2424
}
2525

26-
private extension Binding where Value == OcaProperty<OcaPolarityState>.PropertyValue {
27-
var value: Binding<Bool> {
28-
Binding<Bool>(get: {
29-
if case let .success(isInverted) = self.wrappedValue {
30-
isInverted == .inverted
31-
} else {
32-
false
33-
}
34-
}, set: { isInverted in
35-
self.wrappedValue = .success(isInverted ? .inverted : .nonInverted)
36-
})
37-
}
38-
}
39-
4026
public struct OcaPolarityView: OcaView {
4127
@State
4228
var object: OcaPolarity
@@ -46,9 +32,14 @@ public struct OcaPolarityView: OcaView {
4632
}
4733

4834
public var body: some View {
49-
Toggle(isOn: object.binding(for: object.$state).value) {}
50-
.toggleStyle(SymbolToggleStyle(systemImage: "circle.slash", activeColor: .accentColor))
51-
.padding()
52-
.showProgressIfWaiting(object.$state)
35+
OcaWritablePropertyView(object, object.$state) { (value: Binding<OcaPolarityState>) in
36+
let boolBinding = Binding<Bool>(
37+
get: { value.wrappedValue == .inverted },
38+
set: { value.wrappedValue = $0 ? .inverted : .nonInverted }
39+
)
40+
Toggle(isOn: boolBinding) {}
41+
.toggleStyle(SymbolToggleStyle(systemImage: "circle.slash", activeColor: .accentColor))
42+
.padding()
43+
}
5344
}
5445
}

0 commit comments

Comments
 (0)