From 9f114a471efc39a0871ec550972f18234af01b8f Mon Sep 17 00:00:00 2001 From: david-swift Date: Mon, 1 Jul 2024 21:53:14 +0200 Subject: [PATCH] Fix pointers not being passed by every widget --- Sources/Model/Extensions/Array.swift | 31 +++++++----- .../Model/User Interface/App/AppStorage.swift | 2 + .../User Interface/Scene/SceneStorage.swift | 3 +- .../Model/User Interface/View/AnyView.swift | 27 ++++++----- .../User Interface/View/ViewStorage.swift | 1 - .../Model/User Interface/View/Widget.swift | 15 +++--- .../Model/User Interface/View/Wrapper.swift | 15 ++++++ Sources/View/AppearObserver.swift | 20 ++++---- Sources/View/ContentModifier.swift | 20 ++++---- Sources/View/Freeze.swift | 19 ++++---- Sources/View/InspectorWrapper.swift | 20 ++++---- Sources/View/ModifierStopper.swift | 20 ++++---- Sources/View/StateWrapper.swift | 23 +++++---- Sources/View/Wrapper.swift | 47 ------------------- Tests/SampleBackends/Backend1.swift | 40 ++++++++++++---- Tests/SampleBackends/Backend2.swift | 32 +++++++++++-- 16 files changed, 184 insertions(+), 151 deletions(-) create mode 100644 Sources/Model/User Interface/View/Wrapper.swift delete mode 100644 Sources/View/Wrapper.swift diff --git a/Sources/Model/Extensions/Array.swift b/Sources/Model/Extensions/Array.swift index 8c4b11a..bb381ff 100644 --- a/Sources/Model/Extensions/Array.swift +++ b/Sources/Model/Extensions/Array.swift @@ -13,10 +13,15 @@ extension Array: AnyView where Element == AnyView { public var viewContent: Body { self } /// Get a widget from a collection of views. - /// - Parameter modifiers: Modify views before being updated. + /// - Parameters: + /// - modifiers: Modify views before being updated. + /// - type: The app storage type. /// - Returns: A widget. - public func widget(modifiers: [(AnyView) -> AnyView]) -> Widget { - if count == 1, let widget = self[safe: 0]?.widget(modifiers: modifiers) { + public func widget( + modifiers: [(AnyView) -> AnyView], + type: Storage.Type + ) -> Widget where Storage: AppStorage { + if count == 1, let widget = self[safe: 0]?.widget(modifiers: modifiers, type: type) { return widget } else { var modified = self @@ -25,7 +30,7 @@ extension Array: AnyView where Element == AnyView { modified[safe: index] = modifier(view) } } - return Wrapper { modified } + return Storage.WrapperType { modified } } } @@ -34,17 +39,17 @@ extension Array: AnyView where Element == AnyView { /// - storage: The collection of view storages. /// - modifiers: Modify views before being updated. /// - updateProperties: Whether to update properties. - /// - type: The type of the widgets. - public func update( + /// - type: The type of the app storage. + public func update( _ storage: [ViewStorage], modifiers: [(AnyView) -> AnyView], updateProperties: Bool, - type: WidgetType.Type - ) { + type: Storage.Type + ) where Storage: AppStorage { for (index, element) in filter({ $0.renderable(type: type, modifiers: modifiers) }).enumerated() { if let storage = storage[safe: index] { element - .widget(modifiers: modifiers) + .widget(modifiers: modifiers, type: type) .updateStorage(storage, modifiers: modifiers, updateProperties: updateProperties, type: type) } } @@ -53,12 +58,12 @@ extension Array: AnyView where Element == AnyView { /// Get the view storages of a collection of views. /// - Parameters: /// - modifiers: Modify views before generating the storages. - /// - type: The type of the widgets. + /// - type: The type of the app storage. /// - Returns: The storages. - public func storages( + public func storages( modifiers: [(AnyView) -> AnyView], - type: WidgetType.Type - ) -> [ViewStorage] { + type: Storage.Type + ) -> [ViewStorage] where Storage: AppStorage { compactMap { view in view.renderable(type: type, modifiers: modifiers) ? view.storage(modifiers: modifiers, type: type) : nil } diff --git a/Sources/Model/User Interface/App/AppStorage.swift b/Sources/Model/User Interface/App/AppStorage.swift index 3473fe6..c124d0a 100644 --- a/Sources/Model/User Interface/App/AppStorage.swift +++ b/Sources/Model/User Interface/App/AppStorage.swift @@ -12,6 +12,8 @@ public protocol AppStorage: AnyObject { associatedtype SceneElementType /// The type of widget elements (which should be backend-specific). associatedtype WidgetType + /// The wrapper widget. + associatedtype WrapperType: Wrapper /// The scene. var app: () -> any App { get } diff --git a/Sources/Model/User Interface/Scene/SceneStorage.swift b/Sources/Model/User Interface/Scene/SceneStorage.swift index 117670d..f1c078a 100644 --- a/Sources/Model/User Interface/Scene/SceneStorage.swift +++ b/Sources/Model/User Interface/Scene/SceneStorage.swift @@ -12,8 +12,7 @@ public class SceneStorage { public var id: String /// The pointer. /// - /// It can be a C pointer, a Swift class, or other information depending on the backend, - /// or it can be left out. + /// It can be a C pointer, a Swift class, or other information depending on the backend. public var pointer: Any? /// The scene element's view content. public var content: [String: [ViewStorage]] diff --git a/Sources/Model/User Interface/View/AnyView.swift b/Sources/Model/User Interface/View/AnyView.swift index 3be5ccb..063ef99 100644 --- a/Sources/Model/User Interface/View/AnyView.swift +++ b/Sources/Model/User Interface/View/AnyView.swift @@ -28,14 +28,14 @@ extension AnyView { /// - storage: The storage. /// - modifiers: Modify views before being updated. /// - updateProperties: Whether to update properties. - /// - type: The type of the widgets. - public func updateStorage( + /// - type: The type of the app storage. + public func updateStorage( _ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool, - type: WidgetType.Type - ) { - widget(modifiers: modifiers) + type: Storage.Type + ) where Storage: AppStorage { + widget(modifiers: modifiers, type: type) .update(storage, modifiers: modifiers, updateProperties: updateProperties, type: type) } @@ -44,28 +44,31 @@ extension AnyView { /// - modifiers: Modify views before being updated. /// - type: The widget types. /// - Returns: The storage. - public func storage(modifiers: [(AnyView) -> AnyView], type: WidgetType.Type) -> ViewStorage { - widget(modifiers: modifiers).container(modifiers: modifiers, type: type) + public func storage( + modifiers: [(AnyView) -> AnyView], + type: Storage.Type + ) -> ViewStorage where Storage: AppStorage { + widget(modifiers: modifiers, type: type).container(modifiers: modifiers, type: type) } /// Wrap the view into a widget. /// - Parameter modifiers: Modify views before being updated. /// - Returns: The widget. - func widget(modifiers: [(AnyView) -> AnyView]) -> Widget { + func widget(modifiers: [(AnyView) -> AnyView], type: Storage.Type) -> Widget where Storage: AppStorage { let modified = getModified(modifiers: modifiers) if let peer = modified as? Widget { return peer } if let array = modified as? Body { - return Wrapper { array } + return Storage.WrapperType { array } } - return Wrapper { viewContent.map { $0.getModified(modifiers: modifiers) } } + return Storage.WrapperType { viewContent.map { $0.getModified(modifiers: modifiers) } } } /// Whether the view can be rendered in a certain environment. - func renderable(type: WidgetType.Type, modifiers: [(AnyView) -> AnyView]) -> Bool { + func renderable(type: Storage.Type, modifiers: [(AnyView) -> AnyView]) -> Bool where Storage: AppStorage { let result = getModified(modifiers: modifiers) - return result as? WidgetType != nil + return result as? Storage.WidgetType != nil || result as? SimpleView != nil || result as? View != nil || result as? ConvenienceWidget != nil diff --git a/Sources/Model/User Interface/View/ViewStorage.swift b/Sources/Model/User Interface/View/ViewStorage.swift index d24152e..7b6ef0a 100644 --- a/Sources/Model/User Interface/View/ViewStorage.swift +++ b/Sources/Model/User Interface/View/ViewStorage.swift @@ -11,7 +11,6 @@ public class ViewStorage { /// The pointer. /// /// It can be a C pointer, a Swift class, or other information depending on the backend. - /// Some convenience widgets do not need a pointer to a native framework at all. public var pointer: Any? /// The view's content for container widgets. public var content: [String: [ViewStorage]] diff --git a/Sources/Model/User Interface/View/Widget.swift b/Sources/Model/User Interface/View/Widget.swift index 300064b..3d404dc 100644 --- a/Sources/Model/User Interface/View/Widget.swift +++ b/Sources/Model/User Interface/View/Widget.swift @@ -14,20 +14,23 @@ public protocol Widget: AnyView { /// The view storage. /// - Parameters: /// - modifiers: Modify views before being updated. - /// - type: The type of the widgets. - func container(modifiers: [(AnyView) -> AnyView], type: WidgetType.Type) -> ViewStorage + /// - type: The type of the app storage. + func container( + modifiers: [(AnyView) -> AnyView], + type: Storage.Type + ) -> ViewStorage where Storage: AppStorage /// Update the stored content. /// - Parameters: /// - storage: The storage to update. /// - modifiers: Modify views before being updated /// - updateProperties: Whether to update the view's properties. - /// - type: The type of the widgets. - func update( + /// - type: The type of the app storage. + func update( _ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool, - type: WidgetType.Type - ) + type: Storage.Type + ) where Storage: AppStorage } diff --git a/Sources/Model/User Interface/View/Wrapper.swift b/Sources/Model/User Interface/View/Wrapper.swift new file mode 100644 index 0000000..fa660ec --- /dev/null +++ b/Sources/Model/User Interface/View/Wrapper.swift @@ -0,0 +1,15 @@ +// +// Wrapper.swift +// Meta +// +// Created by david-swift on 01.07.24. +// + +/// Wrap a body into a single widget. +public protocol Wrapper: Widget { + + /// Initialize a `Wrapper`. + /// - Parameter content: The view content. + init(@ViewBuilder content: @escaping () -> Body) + +} diff --git a/Sources/View/AppearObserver.swift b/Sources/View/AppearObserver.swift index ee5d07f..83f64a9 100644 --- a/Sources/View/AppearObserver.swift +++ b/Sources/View/AppearObserver.swift @@ -16,11 +16,14 @@ struct AppearObserver: ConvenienceWidget { /// The view storage. /// - Parameters: /// - modifiers: Modify views before being updated. - /// - type: The type of the widgets. - func container(modifiers: [(any AnyView) -> any AnyView], type: WidgetType.Type) -> ViewStorage { + /// - type: The type of the app storage. + func container( + modifiers: [(any AnyView) -> any AnyView], + type: Storage.Type + ) -> ViewStorage where Storage: AppStorage { let storage = content.storage(modifiers: modifiers, type: type) modify(storage) - return .init(nil, content: [.mainContent: [storage]]) + return storage } /// Update the stored content. @@ -28,16 +31,13 @@ struct AppearObserver: ConvenienceWidget { /// - storage: The storage to update. /// - modifiers: Modify views before being updated /// - updateProperties: Whether to update the view's properties. - /// - type: The type of the widgets. - func update( + /// - type: The type of the app storage. + func update( _ storage: ViewStorage, modifiers: [(any AnyView) -> any AnyView], updateProperties: Bool, - type: WidgetType.Type - ) { - guard let storage = storage.content[.mainContent]?.first else { - return - } + type: Storage.Type + ) where Storage: AppStorage { content.updateStorage(storage, modifiers: modifiers, updateProperties: updateProperties, type: type) } diff --git a/Sources/View/ContentModifier.swift b/Sources/View/ContentModifier.swift index e463e09..1abe1fa 100644 --- a/Sources/View/ContentModifier.swift +++ b/Sources/View/ContentModifier.swift @@ -16,9 +16,12 @@ struct ContentModifier: ConvenienceWidget where Content: AnyView { /// The view storage. /// - Parameters: /// - modifiers: Modify views before being updated. - /// - type: The type of the widgets. - func container(modifiers: [(any AnyView) -> any AnyView], type: WidgetType.Type) -> ViewStorage { - .init(nil, content: [.mainContent: [content.storage(modifiers: modifiers + [modifyView], type: type)]]) + /// - type: The type of the app storage. + func container( + modifiers: [(any AnyView) -> any AnyView], + type: Storage.Type + ) -> ViewStorage where Storage: AppStorage { + content.storage(modifiers: modifiers + [modifyView], type: type) } /// Update the stored content. @@ -26,16 +29,13 @@ struct ContentModifier: ConvenienceWidget where Content: AnyView { /// - storage: The storage to update. /// - modifiers: Modify views before being updated /// - updateProperties: Whether to update the view's properties. - /// - type: The type of the widgets. - func update( + /// - type: The type of the app storage. + func update( _ storage: ViewStorage, modifiers: [(any AnyView) -> any AnyView], updateProperties: Bool, - type: WidgetType.Type - ) { - guard let storage = storage.content[.mainContent]?.first else { - return - } + type: Storage.Type + ) where Storage: AppStorage { content .updateStorage(storage, modifiers: modifiers + [modifyView], updateProperties: updateProperties, type: type) } diff --git a/Sources/View/Freeze.swift b/Sources/View/Freeze.swift index 9344919..15b0ad9 100644 --- a/Sources/View/Freeze.swift +++ b/Sources/View/Freeze.swift @@ -16,9 +16,12 @@ struct Freeze: ConvenienceWidget { /// The view storage. /// - Parameters: /// - modifiers: Modify views before being updated. - /// - type: The type of the widgets. - func container(modifiers: [(any AnyView) -> any AnyView], type: WidgetType.Type) -> ViewStorage { - .init(nil, content: [.mainContent: [content.storage(modifiers: modifiers, type: type)]]) + /// - type: The type of the app storage. + func container( + modifiers: [(any AnyView) -> any AnyView], + type: Storage.Type + ) -> ViewStorage where Storage: AppStorage { + content.storage(modifiers: modifiers, type: type) } /// Update the stored content. @@ -26,14 +29,14 @@ struct Freeze: ConvenienceWidget { /// - storage: The storage to update. /// - modifiers: Modify views before being updated /// - updateProperties: Whether to update the view's properties. - /// - type: The type of the widgets. - func update( + /// - type: The type of the app storage. + func update( _ storage: ViewStorage, modifiers: [(any AnyView) -> any AnyView], updateProperties: Bool, - type: WidgetType.Type - ) { - guard !freeze, let storage = storage.content[.mainContent]?.first else { + type: Storage.Type + ) where Storage: AppStorage { + guard !freeze else { return } content.updateStorage(storage, modifiers: modifiers, updateProperties: updateProperties, type: type) diff --git a/Sources/View/InspectorWrapper.swift b/Sources/View/InspectorWrapper.swift index 8780d8c..9166010 100644 --- a/Sources/View/InspectorWrapper.swift +++ b/Sources/View/InspectorWrapper.swift @@ -16,11 +16,14 @@ struct InspectorWrapper: ConvenienceWidget { /// The view storage. /// - Parameters: /// - modifiers: Modify views before being updated. - /// - type: The type of the widgets. - func container(modifiers: [(any AnyView) -> any AnyView], type: WidgetType.Type) -> ViewStorage { + /// - type: The type of the app storage. + func container( + modifiers: [(any AnyView) -> any AnyView], + type: Storage.Type + ) -> ViewStorage where Storage: AppStorage { let storage = content.storage(modifiers: modifiers, type: type) modify(storage) - return .init(nil, content: [.mainContent: [storage]]) + return storage } /// Update the stored content. @@ -28,16 +31,13 @@ struct InspectorWrapper: ConvenienceWidget { /// - storage: The storage to update. /// - modifiers: Modify views before being updated /// - updateProperties: Whether to update the view's properties. - /// - type: The type of the widgets. - func update( + /// - type: The type of the app storage. + func update( _ storage: ViewStorage, modifiers: [(any AnyView) -> any AnyView], updateProperties: Bool, - type: WidgetType.Type - ) { - guard let storage = storage.content[.mainContent]?.first else { - return - } + type: Storage.Type + ) where Storage: AppStorage { content.updateStorage(storage, modifiers: modifiers, updateProperties: updateProperties, type: type) modify(storage) } diff --git a/Sources/View/ModifierStopper.swift b/Sources/View/ModifierStopper.swift index e9eae9a..32834fe 100644 --- a/Sources/View/ModifierStopper.swift +++ b/Sources/View/ModifierStopper.swift @@ -14,9 +14,12 @@ struct ModifierStopper: ConvenienceWidget { /// The view storage. /// - Parameters: /// - modifiers: Modify views before being updated. - /// - type: The type of the widgets. - func container(modifiers: [(any AnyView) -> any AnyView], type: WidgetType.Type) -> ViewStorage { - .init(nil, content: [.mainContent: [content.storage(modifiers: [], type: type)]]) + /// - type: The type of the app storage. + func container( + modifiers: [(any AnyView) -> any AnyView], + type: Storage.Type + ) -> ViewStorage where Storage: AppStorage { + content.storage(modifiers: [], type: type) } /// Update the stored content. @@ -24,16 +27,13 @@ struct ModifierStopper: ConvenienceWidget { /// - storage: The storage to update. /// - modifiers: Modify views before being updated /// - updateProperties: Whether to update the view's properties. - /// - type: The type of the widgets. - func update( + /// - type: The type of the app storage. + func update( _ storage: ViewStorage, modifiers: [(any AnyView) -> any AnyView], updateProperties: Bool, - type: WidgetType.Type - ) { - guard let storage = storage.content[.mainContent]?.first else { - return - } + type: Storage.Type + ) where Storage: AppStorage { content.updateStorage(storage, modifiers: [], updateProperties: updateProperties, type: type) } diff --git a/Sources/View/StateWrapper.swift b/Sources/View/StateWrapper.swift index 89f9b47..f836c1a 100644 --- a/Sources/View/StateWrapper.swift +++ b/Sources/View/StateWrapper.swift @@ -35,13 +35,13 @@ struct StateWrapper: ConvenienceWidget { /// - storage: The view storage. /// - modifiers: Modify views before being updated. /// - updateProperties: Whether to update properties. - /// - type: The type of the widgets. - func update( + /// - type: The type of the app storage. + func update( _ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool, - type: WidgetType.Type - ) { + type: Storage.Type + ) where Storage: AppStorage { var updateProperties = updateProperties for property in state { if let oldID = storage.state[property.key]?.id { @@ -53,20 +53,23 @@ struct StateWrapper: ConvenienceWidget { StateManager.updatedState(id: property.value.id) } } - guard let storages = storage.content[.mainContent] else { + guard let storage = storage.content[.mainContent]?.first else { return } - content().update(storages, modifiers: modifiers, updateProperties: updateProperties, type: type) + content().updateStorage(storage, modifiers: modifiers, updateProperties: updateProperties, type: type) } /// Get a view storage. /// - Parameters: /// - modifiers: Modify views before being updated. - /// - type: The type of the widgets. + /// - type: The type of the app storage. /// - Returns: The view storage. - func container(modifiers: [(AnyView) -> AnyView], type: WidgetType.Type) -> ViewStorage { - let content = content().storages(modifiers: modifiers, type: type) - let storage = ViewStorage(nil, content: [.mainContent: content]) + func container( + modifiers: [(AnyView) -> AnyView], + type: Storage.Type + ) -> ViewStorage where Storage: AppStorage { + let content = content().storage(modifiers: modifiers, type: type) + let storage = ViewStorage(content.pointer, content: [.mainContent: [content]]) storage.state = state if #available(macOS 14, *), #available(iOS 17, *), state.contains(where: { $0.value.isObservable }) { observe(storage: storage) diff --git a/Sources/View/Wrapper.swift b/Sources/View/Wrapper.swift deleted file mode 100644 index fa00877..0000000 --- a/Sources/View/Wrapper.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// Wrapper.swift -// Meta -// -// Created by david-swift on 27.05.24. -// - -/// Wrap a body into a single widget. -public struct Wrapper: ConvenienceWidget { - - /// The content. - var content: Body - - /// Initialize a `Wrapper`. - /// - Parameter content: The view content. - public init(@ViewBuilder content: @escaping () -> Body) { - self.content = content() - } - - /// Update a view storage. - /// - Parameters: - /// - storage: The view storage. - /// - modifiers: Modify views before being updated. - /// - updateProperties: Whether to update properties. - /// - type: The widget types. - public func update( - _ storage: ViewStorage, - modifiers: [(AnyView) -> AnyView], - updateProperties: Bool, - type: WidgetType.Type - ) { - guard let storages = storage.content[.mainContent] else { - return - } - content.update(storages, modifiers: modifiers, updateProperties: updateProperties, type: type) - } - - /// Get a view storage. - /// - Parameters: - /// - modifiers: Modify views before being updated. - /// - type: The type of the widgets. - /// - Returns: The view storage. - public func container(modifiers: [(AnyView) -> AnyView], type: WidgetType.Type) -> ViewStorage { - .init(nil, content: [.mainContent: content.storages(modifiers: modifiers, type: type)]) - } - -} diff --git a/Tests/SampleBackends/Backend1.swift b/Tests/SampleBackends/Backend1.swift index 805859e..ef438c3 100644 --- a/Tests/SampleBackends/Backend1.swift +++ b/Tests/SampleBackends/Backend1.swift @@ -6,14 +6,14 @@ public enum Backend1 { public init() { } - public func container(modifiers: [(AnyView) -> AnyView], type: WidgetType.Type) -> ViewStorage { + public func container(modifiers: [(AnyView) -> AnyView], type: Storage.Type) -> ViewStorage where Storage: AppStorage { print("Init test widget 1") let storage = ViewStorage(nil) storage.fields["test"] = 0 return storage } - public func update(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool, type: WidgetType.Type) { + public func update(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool, type: Storage.Type) { print("Update test widget 1 (#\(storage.fields["test"] ?? ""))") storage.fields["test"] = (storage.fields["test"] as? Int ?? 0) + 1 } @@ -24,14 +24,14 @@ public enum Backend1 { public init() { } - public func container(modifiers: [(AnyView) -> AnyView], type: WidgetType.Type) -> ViewStorage { + public func container(modifiers: [(AnyView) -> AnyView], type: Storage.Type) -> ViewStorage where Storage: AppStorage { print("Init test widget 3") let storage = ViewStorage(nil) storage.fields["test"] = 0 return storage } - public func update(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool, type: WidgetType.Type) { + public func update(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool, type: Storage.Type) { print("Update test widget 3 (#\(storage.fields["test"] ?? ""))") storage.fields["test"] = (storage.fields["test"] as? Int ?? 0) + 1 } @@ -48,7 +48,7 @@ public enum Backend1 { self.action = action } - public func container(modifiers: [(any AnyView) -> any AnyView], type: WidgetType.Type) -> ViewStorage { + public func container(modifiers: [(any AnyView) -> any AnyView], type: Storage.Type) -> ViewStorage where Storage: AppStorage { print("Init button") let storage = ViewStorage(nil) Task { @@ -59,7 +59,7 @@ public enum Backend1 { return storage } - public func update(_ storage: ViewStorage, modifiers: [(any AnyView) -> any AnyView], updateProperties: Bool, type: WidgetType.Type) { + public func update(_ storage: ViewStorage, modifiers: [(any AnyView) -> any AnyView], updateProperties: Bool, type: Storage.Type) { if updateProperties { print("Update button (label = \(label))") storage.fields["action"] = action @@ -90,7 +90,7 @@ public enum Backend1 { public func container(app: Storage) -> SceneStorage where Storage: AppStorage { print("Show \(id)") - let viewStorage = content.storage(modifiers: [], type: Storage.WidgetType.self) + let viewStorage = content.storage(modifiers: [], type: Storage.self) return .init(id: id, pointer: nil, content: [.mainContent : [viewStorage]]) { print("Make visible") } @@ -101,7 +101,30 @@ public enum Backend1 { guard let viewStorage = storage.content[.mainContent]?.first else { return } - content.updateStorage(viewStorage, modifiers: [], updateProperties: updateProperties, type: Storage.WidgetType.self) + content.updateStorage(viewStorage, modifiers: [], updateProperties: updateProperties, type: Storage.self) + } + + } + + public struct Wrapper: BackendWidget, Meta.Wrapper { + + var content: Body + + public init(@ViewBuilder content: @escaping () -> Body) { + self.content = content() + } + + public func container(modifiers: [(any Meta.AnyView) -> any Meta.AnyView], type: Storage.Type) -> Meta.ViewStorage where Storage : Meta.AppStorage { + let storage = ViewStorage(nil) + storage.content = [.mainContent: content.storages(modifiers: modifiers, type: type)] + return storage + } + + public func update(_ storage: Meta.ViewStorage, modifiers: [(any Meta.AnyView) -> any Meta.AnyView], updateProperties: Bool, type: Storage.Type) where Storage : Meta.AppStorage { + guard let storages = storage.content[.mainContent] else { + return + } + content.update(storages, modifiers: modifiers, updateProperties: updateProperties, type: type) } } @@ -114,6 +137,7 @@ public enum Backend1 { public typealias SceneElementType = BackendSceneElement public typealias WidgetType = BackendWidget + public typealias WrapperType = Wrapper public var app: () -> any App public var sceneStorage: [SceneStorage] = [] diff --git a/Tests/SampleBackends/Backend2.swift b/Tests/SampleBackends/Backend2.swift index a5340b0..1ddc0fc 100644 --- a/Tests/SampleBackends/Backend2.swift +++ b/Tests/SampleBackends/Backend2.swift @@ -6,14 +6,14 @@ public enum Backend2 { public init() { } - public func container(modifiers: [(AnyView) -> AnyView], type: WidgetType.Type) -> ViewStorage { + public func container(modifiers: [(AnyView) -> AnyView], type: Storage.Type) -> ViewStorage where Storage: AppStorage { print("Init test widget 2") let storage = ViewStorage(nil) storage.fields["test"] = 0 return storage } - public func update(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool, type: WidgetType.Type) { + public func update(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool, type: Storage.Type) { print("Update test widget 2 (#\(storage.fields["test"] ?? ""))") storage.fields["test"] = (storage.fields["test"] as? Int ?? 0) + 1 } @@ -24,20 +24,43 @@ public enum Backend2 { public init() { } - public func container(modifiers: [(AnyView) -> AnyView], type: WidgetType.Type) -> ViewStorage { + public func container(modifiers: [(AnyView) -> AnyView], type: Storage.Type) -> ViewStorage where Storage: AppStorage { print("Init test widget 4") let storage = ViewStorage(nil) storage.fields["test"] = 0 return storage } - public func update(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool, type: WidgetType.Type) { + public func update(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool, type: Storage.Type) { print("Update test widget 4 (#\(storage.fields["test"] ?? ""))") storage.fields["test"] = (storage.fields["test"] as? Int ?? 0) + 1 } } + public struct Wrapper: BackendWidget, Meta.Wrapper { + + var content: Body + + public init(@ViewBuilder content: @escaping () -> Body) { + self.content = content() + } + + public func container(modifiers: [(any Meta.AnyView) -> any Meta.AnyView], type: Storage.Type) -> Meta.ViewStorage where Storage : Meta.AppStorage { + let storage = ViewStorage(nil) + storage.content = [.mainContent: content.storages(modifiers: modifiers, type: type)] + return storage + } + + public func update(_ storage: Meta.ViewStorage, modifiers: [(any Meta.AnyView) -> any Meta.AnyView], updateProperties: Bool, type: Storage.Type) where Storage : Meta.AppStorage { + guard let storages = storage.content[.mainContent] else { + return + } + content.update(storages, modifiers: modifiers, updateProperties: updateProperties, type: type) + } + + } + public protocol BackendWidget: Widget { } public protocol BackendSceneElement: SceneElement { } @@ -46,6 +69,7 @@ public enum Backend2 { public typealias SceneElementType = BackendSceneElement public typealias WidgetType = BackendWidget + public typealias WrapperType = Wrapper public var app: () -> any App public var sceneStorage: [SceneStorage] = []