-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathBaseHybridViewModelProperty.swift
More file actions
97 lines (82 loc) · 3.53 KB
/
BaseHybridViewModelProperty.swift
File metadata and controls
97 lines (82 loc) · 3.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import Foundation
import RiveRuntime
/// Protocol for Rive property types that support listener management
protocol RivePropertyWithListeners: AnyObject {
associatedtype ListenerValueType
func addListener(_ callback: @escaping (ListenerValueType) -> Void) -> UUID
func removeListener(_ id: UUID)
}
typealias BooleanPropertyType = RiveDataBindingViewModel.Instance.BooleanProperty
typealias NumberPropertyType = RiveDataBindingViewModel.Instance.NumberProperty
typealias StringPropertyType = RiveDataBindingViewModel.Instance.StringProperty
typealias EnumPropertyType = RiveDataBindingViewModel.Instance.EnumProperty
typealias ColorPropertyType = RiveDataBindingViewModel.Instance.ColorProperty
typealias TriggerPropertyType = RiveDataBindingViewModel.Instance.TriggerProperty
typealias ImagePropertyType = RiveDataBindingViewModel.Instance.ImageProperty
// Make all Rive property types conform to the protocol
extension BooleanPropertyType: RivePropertyWithListeners {
typealias ListenerValueType = Bool // Native: Bool → Bool (no conversion)
}
extension NumberPropertyType: RivePropertyWithListeners {
typealias ListenerValueType = Float // Native: Float → Double (needs conversion)
}
extension StringPropertyType: RivePropertyWithListeners {
typealias ListenerValueType = String // Native: String → String (no conversion)
}
extension EnumPropertyType: RivePropertyWithListeners {
typealias ListenerValueType = String // Native: String → String (no conversion)
}
extension ColorPropertyType: RivePropertyWithListeners {
typealias ListenerValueType = UIColor // Native: UIColor → Double (needs conversion)
}
// Note: TriggerProperty doesn't fit the pattern - it has () -> Void listeners, not (Void) -> Void
/// Helper class for managing ViewModel property listeners
class PropertyListenerHelper<PropertyType: RivePropertyWithListeners> {
private var listenerIds: [UUID] = []
weak var property: PropertyType?
init(property: PropertyType) {
self.property = property
}
/// Adds a listener to the property and automatically tracks its ID for cleanup
func addListener(_ callback: @escaping (PropertyType.ListenerValueType) -> Void) {
guard let property = property else { return }
let id = property.addListener(callback)
listenerIds.append(id)
}
func removeListeners() throws {
guard let property = property else { return }
for id in listenerIds {
property.removeListener(id)
}
listenerIds.removeAll()
}
func dispose() throws {
try? removeListeners()
}
}
/// Protocol for properties that have typed values (Bool, String, Double, etc.)
/// Provides a default addListener implementation
protocol ValuedPropertyProtocol<ValueType> {
associatedtype PropertyType: RivePropertyWithListeners
associatedtype ValueType
var property: PropertyType! { get }
var helper: PropertyListenerHelper<PropertyType> { get }
func addListener(onChanged: @escaping (ValueType) -> Void) throws
func removeListeners() throws
func dispose() throws
}
/// Default implementations for lifecycle methods (always available)
extension ValuedPropertyProtocol {
func removeListeners() throws {
try helper.removeListeners()
}
func dispose() throws {
try helper.dispose()
}
}
/// Automatic addListener() ONLY when ListenerValueType == ValueType (no conversion needed)
extension ValuedPropertyProtocol where PropertyType.ListenerValueType == ValueType {
func addListener(onChanged: @escaping (ValueType) -> Void) throws {
helper.addListener(onChanged) // Types match, just forward directly!
}
}