diff --git a/Sources/Model/Extensions/Array.swift b/Sources/Model/Extensions/Array.swift index 914c268..2c93d24 100644 --- a/Sources/Model/Extensions/Array.swift +++ b/Sources/Model/Extensions/Array.swift @@ -15,9 +15,9 @@ extension Array: AnyView where Element == AnyView { /// Get the debug tree for an array of views. /// - Parameter parameters: Whether the widget parameters should be visible in the tree. /// - Returns: The tree. - public func getBodyDebugTree(parameters: Bool, type: ViewType.Type) -> String { + public func getBodyDebugTree(parameters: Bool, type: WidgetType.Type) -> String { var description = "" - for view in self where view as? ViewType != nil { + for view in self where view.renderable(type: type) { let viewDescription: String if let widget = view as? Widget { viewDescription = widget.getViewDescription(parameters: parameters, type: type) @@ -45,7 +45,6 @@ extension Array: AnyView where Element == AnyView { modified[safe: index] = modifier(view) } } - // TODO: Is wrapper correct choice? return Wrapper { modified } } } @@ -55,12 +54,13 @@ extension Array: AnyView where Element == AnyView { /// - storage: The collection of view storages. /// - modifiers: Modify views before being updated. /// - updateProperties: Whether to update properties. - public func update(_ storage: [ViewStorage], modifiers: [(AnyView) -> AnyView], updateProperties: Bool) { - for (index, element) in enumerated() { + /// - type: The type of the widgets. + public func update(_ storage: [ViewStorage], modifiers: [(AnyView) -> AnyView], updateProperties: Bool, type: WidgetType.Type) { + for (index, element) in enumerated() where element.renderable(type: type) { if let storage = storage[safe: index] { element .widget(modifiers: modifiers) - .updateStorage(storage, modifiers: modifiers, updateProperties: updateProperties) + .updateStorage(storage, modifiers: modifiers, updateProperties: updateProperties, type: type) } } } diff --git a/Sources/Model/User Interface/View/AnyView.swift b/Sources/Model/User Interface/View/AnyView.swift index 7fd4f32..5a1ff3d 100644 --- a/Sources/Model/User Interface/View/AnyView.swift +++ b/Sources/Model/User Interface/View/AnyView.swift @@ -18,7 +18,7 @@ extension AnyView { /// Get the view's debug tree. /// - Parameter parameters: Whether the widget parameters should be included in the debug tree. /// - Returns: A textual description. - public func getDebugTree(parameters: Bool, type: ViewType.Type) -> String { + public func getDebugTree(parameters: Bool, type: WidgetType.Type) -> String { if let body = self as? Body { return body.getBodyDebugTree(parameters: parameters, type: type) } @@ -42,21 +42,24 @@ extension AnyView { /// - storage: The storage. /// - modifiers: Modify views before being updated. /// - updateProperties: Whether to update properties. - public func updateStorage(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool) { + /// - type: The type of the widgets. + public func updateStorage(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool, type: WidgetType.Type) { let modified = getModified(modifiers: modifiers) if let widget = modified as? Widget { - widget.update(storage, modifiers: modifiers, updateProperties: updateProperties) + widget.update(storage, modifiers: modifiers, updateProperties: updateProperties, type: type) } else { Wrapper { viewContent } - .update(storage, modifiers: modifiers, updateProperties: updateProperties) + .update(storage, modifiers: modifiers, updateProperties: updateProperties, type: type) } } /// Get a storage. - /// - Parameter modifiers: Modify views before being updated. + /// - Parameters: + /// - modifiers: Modify views before being updated. + /// - type: The widget types. /// - Returns: The storage. - public func storage(modifiers: [(AnyView) -> AnyView]) -> ViewStorage { - widget(modifiers: modifiers).container(modifiers: modifiers) + public func storage(modifiers: [(AnyView) -> AnyView], type: WidgetType.Type) -> ViewStorage { + widget(modifiers: modifiers).container(modifiers: modifiers, type: type) } /// Wrap the view into a widget. @@ -70,6 +73,11 @@ extension AnyView { return Wrapper { viewContent } } + /// Whether the view can be rendered in a certain environment. + func renderable(type: WidgetType.Type) -> Bool { + self as? WidgetType != nil || self as? SimpleView != nil || self as? View != nil + } + } /// `Body` is an array of views. diff --git a/Sources/Model/User Interface/View/ViewBuilder.swift b/Sources/Model/User Interface/View/ViewBuilder.swift index 59342d9..bfb5c9c 100644 --- a/Sources/Model/User Interface/View/ViewBuilder.swift +++ b/Sources/Model/User Interface/View/ViewBuilder.swift @@ -53,40 +53,6 @@ public enum ViewBuilder { component } - // TODO: Add support for optionals, building either - /* - /// Enables support for `if` statements without an `else`. - /// - Parameter component: An optional component. - /// - Returns: A nonoptional component. - public static func buildOptional(_ component: Component?) -> Component { - .element( - Bin() - .child { - if let component { - buildFinalResult(component) - } else { - [] - } - } - .visible(component != nil) - ) - } - - /// Enables support for `if`-`else` and `switch` statements. - /// - Parameter component: A component. - /// - Returns: The component. - public static func buildEither(first component: Component) -> Component { - .element(ViewStack(id: true) { _ in buildFinalResult(component) }) - } - - /// Enables support for `if`-`else` and `switch` statements. - /// - Parameter component: A component. - /// - Returns: The component. - public static func buildEither(second component: Component) -> Component { - .element(ViewStack(id: false) { _ in buildFinalResult(component) }) - } - */ - /// Convert a component to an array of elements. /// - Parameter component: The component to convert. /// - Returns: The generated array of elements. diff --git a/Sources/Model/User Interface/View/Widget.swift b/Sources/Model/User Interface/View/Widget.swift index ce98bcf..9ff74c2 100644 --- a/Sources/Model/User Interface/View/Widget.swift +++ b/Sources/Model/User Interface/View/Widget.swift @@ -13,14 +13,17 @@ public protocol Widget: AnyView { /// The debug tree's content. var debugTreeContent: [(String, body: Body)] { get } /// The view storage. - /// - Parameter modifiers: Modify views before being updated. - func container(modifiers: [(AnyView) -> AnyView]) -> ViewStorage + /// - Parameters: + /// - modifiers: Modify views before being updated. + /// - type: The type of the widgets. + func container(modifiers: [(AnyView) -> AnyView], type: WidgetType.Type) -> ViewStorage /// Update the stored content. /// - Parameters: /// - storage: The storage to update. /// - modifiers: Modify views before being updated /// - updateProperties: Whether to update the view's properties. - func update(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool) + /// - type: The type of the widgets. + func update(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool, type: WidgetType.Type) } @@ -30,7 +33,7 @@ extension Widget { public var viewContent: Body { [] } /// A description of the view. - public func getViewDescription(parameters: Bool, type: ViewType.Type) -> String { + public func getViewDescription(parameters: Bool, type: WidgetType.Type) -> String { var content = "" for element in debugTreeContent { if content.isEmpty { diff --git a/Sources/View/StateWrapper.swift b/Sources/View/StateWrapper.swift index 2df1b1e..a059415 100644 --- a/Sources/View/StateWrapper.swift +++ b/Sources/View/StateWrapper.swift @@ -50,7 +50,8 @@ public struct StateWrapper: Widget { /// - storage: The view storage. /// - modifiers: Modify views before being updated. /// - updateProperties: Whether to update properties. - public func update(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool) { + /// - type: The type of the widgets. + public func update(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool, type: WidgetType.Type) { var updateProperties = storage.fields[updateID] as? Bool ?? false storage.fields[updateID] = false for property in state { @@ -65,15 +66,17 @@ public struct StateWrapper: Widget { if let storage = storage.content[.mainContent]?.first { content() .widget(modifiers: modifiers) - .update(storage, modifiers: modifiers, updateProperties: updateProperties) + .update(storage, modifiers: modifiers, updateProperties: updateProperties, type: type) } } /// Get a view storage. - /// - Parameter modifiers: Modify views before being updated. + /// - Parameters: + /// - modifiers: Modify views before being updated. + /// - type: The type of the widgets. /// - Returns: The view storage. - public func container(modifiers: [(AnyView) -> AnyView]) -> ViewStorage { - let content = content().widget(modifiers: modifiers).container(modifiers: modifiers) + public func container(modifiers: [(AnyView) -> AnyView], type: WidgetType.Type) -> ViewStorage { + let content = content().storage(modifiers: modifiers, type: type) let storage = ViewStorage(content.pointer, content: [.mainContent: [content]]) storage.state = state observe(storage: storage) diff --git a/Sources/View/Wrapper.swift b/Sources/View/Wrapper.swift index d0a3564..fd73cc1 100644 --- a/Sources/View/Wrapper.swift +++ b/Sources/View/Wrapper.swift @@ -32,20 +32,21 @@ public struct Wrapper: Widget { /// - storage: The view storage. /// - modifiers: Modify views before being updated. /// - updateProperties: Whether to update properties. - public func update(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool) { - if let storage = storage.content[.mainContent]?.first { - content - .widget(modifiers: modifiers) - .update(storage, modifiers: modifiers, updateProperties: updateProperties) + /// - 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. - /// - Parameter modifiers: Modify views before being updated. + /// - Parameters: + /// - modifiers: Modify views before being updated. + /// - type: The type of the widgets. /// - Returns: The view storage. - public func container(modifiers: [(AnyView) -> AnyView]) -> ViewStorage { - let content = content.widget(modifiers: modifiers).container(modifiers: modifiers) - return .init(content.pointer, content: [.mainContent: [content]]) + public func container(modifiers: [(AnyView) -> AnyView], type: WidgetType.Type) -> ViewStorage { + ViewStorage(nil, content: [.mainContent: content.map { $0.storage(modifiers: [], type: type) }]) } } diff --git a/Tests/DemoApp/DemoApp.swift b/Tests/DemoApp/DemoApp.swift index 86980da..801c64b 100644 --- a/Tests/DemoApp/DemoApp.swift +++ b/Tests/DemoApp/DemoApp.swift @@ -4,17 +4,31 @@ import SampleBackends struct DemoView: SimpleView { var view: Body { - Backend1.TestWidget() + Backend1.TestWidget1() + TestView() testContent } @ViewBuilder var testContent: Body { - Backend2.TestWidget() - Backend1.TestWidget() + Backend2.TestWidget2() + Backend1.TestWidget1() } } -print(DemoView().getDebugTree(parameters: true, type: Backend1.BackendView.self)) -print(DemoView().getDebugTree(parameters: true, type: Backend2.BackendView.self)) \ No newline at end of file +struct TestView: SimpleView { + + var view: Body { + [] + } + +} + +print(DemoView().getDebugTree(parameters: true, type: Backend1.BackendWidget.self)) +print(DemoView().getDebugTree(parameters: true, type: Backend2.BackendWidget.self)) + +let storage = DemoView().storage(modifiers: [], type: Backend1.BackendWidget.self) +for _ in 0...2 { + DemoView().updateStorage(storage, modifiers: [], updateProperties: true, type: Backend2.BackendWidget.self) +} diff --git a/Tests/SampleBackends/Backend1.swift b/Tests/SampleBackends/Backend1.swift index c02adbd..d89b124 100644 --- a/Tests/SampleBackends/Backend1.swift +++ b/Tests/SampleBackends/Backend1.swift @@ -2,33 +2,32 @@ import Meta public enum Backend1 { - public struct TestWidget: BackendWidget { + public struct TestWidget1: BackendWidget { public init() { } public var debugTreeContent: [(String, body: Body)] { [] } - + public var debugTreeParameters: [(String, value: CustomStringConvertible)] { [] } - public func container(modifiers: [(AnyView) -> AnyView]) -> ViewStorage { - print("Init Content") + public func container(modifiers: [(AnyView) -> AnyView], type: WidgetType.Type) -> ViewStorage { + 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) { - storage.fields["test"] = storage.fields["tests"] as? Int ?? 0 + 1 + public func update(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool, type: WidgetType.Type) { + print("Update test widget 1 (#\(storage.fields["test"] ?? ""))") + storage.fields["test"] = (storage.fields["test"] as? Int ?? 0) + 1 } } - public protocol BackendView: AnyView { } - - public protocol BackendWidget: BackendView, Widget { } + public protocol BackendWidget: Widget { } -} \ No newline at end of file +} diff --git a/Tests/SampleBackends/Backend2.swift b/Tests/SampleBackends/Backend2.swift index 2c5cca0..ead4de5 100644 --- a/Tests/SampleBackends/Backend2.swift +++ b/Tests/SampleBackends/Backend2.swift @@ -2,7 +2,7 @@ import Meta public enum Backend2 { - public struct TestWidget: BackendWidget { + public struct TestWidget2: BackendWidget { public init() { } @@ -14,21 +14,20 @@ public enum Backend2 { [] } - public func container(modifiers: [(AnyView) -> AnyView]) -> ViewStorage { - print("Init Content") + public func container(modifiers: [(AnyView) -> AnyView], type: WidgetType.Type) -> ViewStorage { + 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) { - storage.fields["test"] = storage.fields["tests"] as? Int ?? 0 + 1 + public func update(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool, type: WidgetType.Type) { + print("Update test widget 2 (#\(storage.fields["test"] ?? ""))") + storage.fields["test"] = (storage.fields["test"] as? Int ?? 0) + 1 } } - public protocol BackendView: AnyView { } - - public protocol BackendWidget: BackendView, Widget { } + public protocol BackendWidget: Widget { } -} \ No newline at end of file +}