Implement view updating system
This commit is contained in:
parent
3c17404dc6
commit
c15839de3b
@ -15,9 +15,9 @@ extension Array: AnyView where Element == AnyView {
|
|||||||
/// Get the debug tree for an array of views.
|
/// Get the debug tree for an array of views.
|
||||||
/// - Parameter parameters: Whether the widget parameters should be visible in the tree.
|
/// - Parameter parameters: Whether the widget parameters should be visible in the tree.
|
||||||
/// - Returns: The tree.
|
/// - Returns: The tree.
|
||||||
public func getBodyDebugTree<ViewType>(parameters: Bool, type: ViewType.Type) -> String {
|
public func getBodyDebugTree<WidgetType>(parameters: Bool, type: WidgetType.Type) -> String {
|
||||||
var description = ""
|
var description = ""
|
||||||
for view in self where view as? ViewType != nil {
|
for view in self where view.renderable(type: type) {
|
||||||
let viewDescription: String
|
let viewDescription: String
|
||||||
if let widget = view as? Widget {
|
if let widget = view as? Widget {
|
||||||
viewDescription = widget.getViewDescription(parameters: parameters, type: type)
|
viewDescription = widget.getViewDescription(parameters: parameters, type: type)
|
||||||
@ -45,7 +45,6 @@ extension Array: AnyView where Element == AnyView {
|
|||||||
modified[safe: index] = modifier(view)
|
modified[safe: index] = modifier(view)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: Is wrapper correct choice?
|
|
||||||
return Wrapper { modified }
|
return Wrapper { modified }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -55,12 +54,13 @@ extension Array: AnyView where Element == AnyView {
|
|||||||
/// - storage: The collection of view storages.
|
/// - storage: The collection of view storages.
|
||||||
/// - modifiers: Modify views before being updated.
|
/// - modifiers: Modify views before being updated.
|
||||||
/// - updateProperties: Whether to update properties.
|
/// - updateProperties: Whether to update properties.
|
||||||
public func update(_ storage: [ViewStorage], modifiers: [(AnyView) -> AnyView], updateProperties: Bool) {
|
/// - type: The type of the widgets.
|
||||||
for (index, element) in enumerated() {
|
public func update<WidgetType>(_ 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] {
|
if let storage = storage[safe: index] {
|
||||||
element
|
element
|
||||||
.widget(modifiers: modifiers)
|
.widget(modifiers: modifiers)
|
||||||
.updateStorage(storage, modifiers: modifiers, updateProperties: updateProperties)
|
.updateStorage(storage, modifiers: modifiers, updateProperties: updateProperties, type: type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,7 @@ extension AnyView {
|
|||||||
/// Get the view's debug tree.
|
/// Get the view's debug tree.
|
||||||
/// - Parameter parameters: Whether the widget parameters should be included in the debug tree.
|
/// - Parameter parameters: Whether the widget parameters should be included in the debug tree.
|
||||||
/// - Returns: A textual description.
|
/// - Returns: A textual description.
|
||||||
public func getDebugTree<ViewType>(parameters: Bool, type: ViewType.Type) -> String {
|
public func getDebugTree<WidgetType>(parameters: Bool, type: WidgetType.Type) -> String {
|
||||||
if let body = self as? Body {
|
if let body = self as? Body {
|
||||||
return body.getBodyDebugTree(parameters: parameters, type: type)
|
return body.getBodyDebugTree(parameters: parameters, type: type)
|
||||||
}
|
}
|
||||||
@ -42,21 +42,24 @@ extension AnyView {
|
|||||||
/// - storage: The storage.
|
/// - storage: The storage.
|
||||||
/// - modifiers: Modify views before being updated.
|
/// - modifiers: Modify views before being updated.
|
||||||
/// - updateProperties: Whether to update properties.
|
/// - updateProperties: Whether to update properties.
|
||||||
public func updateStorage(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool) {
|
/// - type: The type of the widgets.
|
||||||
|
public func updateStorage<WidgetType>(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool, type: WidgetType.Type) {
|
||||||
let modified = getModified(modifiers: modifiers)
|
let modified = getModified(modifiers: modifiers)
|
||||||
if let widget = modified as? Widget {
|
if let widget = modified as? Widget {
|
||||||
widget.update(storage, modifiers: modifiers, updateProperties: updateProperties)
|
widget.update(storage, modifiers: modifiers, updateProperties: updateProperties, type: type)
|
||||||
} else {
|
} else {
|
||||||
Wrapper { viewContent }
|
Wrapper { viewContent }
|
||||||
.update(storage, modifiers: modifiers, updateProperties: updateProperties)
|
.update(storage, modifiers: modifiers, updateProperties: updateProperties, type: type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a storage.
|
/// Get a storage.
|
||||||
/// - Parameter modifiers: Modify views before being updated.
|
/// - Parameters:
|
||||||
|
/// - modifiers: Modify views before being updated.
|
||||||
|
/// - type: The widget types.
|
||||||
/// - Returns: The storage.
|
/// - Returns: The storage.
|
||||||
public func storage(modifiers: [(AnyView) -> AnyView]) -> ViewStorage {
|
public func storage<WidgetType>(modifiers: [(AnyView) -> AnyView], type: WidgetType.Type) -> ViewStorage {
|
||||||
widget(modifiers: modifiers).container(modifiers: modifiers)
|
widget(modifiers: modifiers).container(modifiers: modifiers, type: type)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrap the view into a widget.
|
/// Wrap the view into a widget.
|
||||||
@ -70,6 +73,11 @@ extension AnyView {
|
|||||||
return Wrapper { viewContent }
|
return Wrapper { viewContent }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether the view can be rendered in a certain environment.
|
||||||
|
func renderable<WidgetType>(type: WidgetType.Type) -> Bool {
|
||||||
|
self as? WidgetType != nil || self as? SimpleView != nil || self as? View != nil
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `Body` is an array of views.
|
/// `Body` is an array of views.
|
||||||
|
|||||||
@ -53,40 +53,6 @@ public enum ViewBuilder {
|
|||||||
component
|
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.
|
/// Convert a component to an array of elements.
|
||||||
/// - Parameter component: The component to convert.
|
/// - Parameter component: The component to convert.
|
||||||
/// - Returns: The generated array of elements.
|
/// - Returns: The generated array of elements.
|
||||||
|
|||||||
@ -13,14 +13,17 @@ public protocol Widget: AnyView {
|
|||||||
/// The debug tree's content.
|
/// The debug tree's content.
|
||||||
var debugTreeContent: [(String, body: Body)] { get }
|
var debugTreeContent: [(String, body: Body)] { get }
|
||||||
/// The view storage.
|
/// The view storage.
|
||||||
/// - Parameter modifiers: Modify views before being updated.
|
/// - Parameters:
|
||||||
func container(modifiers: [(AnyView) -> AnyView]) -> ViewStorage
|
/// - modifiers: Modify views before being updated.
|
||||||
|
/// - type: The type of the widgets.
|
||||||
|
func container<WidgetType>(modifiers: [(AnyView) -> AnyView], type: WidgetType.Type) -> ViewStorage
|
||||||
/// Update the stored content.
|
/// Update the stored content.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - storage: The storage to update.
|
/// - storage: The storage to update.
|
||||||
/// - modifiers: Modify views before being updated
|
/// - modifiers: Modify views before being updated
|
||||||
/// - updateProperties: Whether to update the view's properties.
|
/// - 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<WidgetType>(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool, type: WidgetType.Type)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,7 +33,7 @@ extension Widget {
|
|||||||
public var viewContent: Body { [] }
|
public var viewContent: Body { [] }
|
||||||
|
|
||||||
/// A description of the view.
|
/// A description of the view.
|
||||||
public func getViewDescription<ViewType>(parameters: Bool, type: ViewType.Type) -> String {
|
public func getViewDescription<WidgetType>(parameters: Bool, type: WidgetType.Type) -> String {
|
||||||
var content = ""
|
var content = ""
|
||||||
for element in debugTreeContent {
|
for element in debugTreeContent {
|
||||||
if content.isEmpty {
|
if content.isEmpty {
|
||||||
|
|||||||
@ -50,7 +50,8 @@ public struct StateWrapper: Widget {
|
|||||||
/// - storage: The view storage.
|
/// - storage: The view storage.
|
||||||
/// - modifiers: Modify views before being updated.
|
/// - modifiers: Modify views before being updated.
|
||||||
/// - updateProperties: Whether to update properties.
|
/// - updateProperties: Whether to update properties.
|
||||||
public func update(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool) {
|
/// - type: The type of the widgets.
|
||||||
|
public func update<WidgetType>(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool, type: WidgetType.Type) {
|
||||||
var updateProperties = storage.fields[updateID] as? Bool ?? false
|
var updateProperties = storage.fields[updateID] as? Bool ?? false
|
||||||
storage.fields[updateID] = false
|
storage.fields[updateID] = false
|
||||||
for property in state {
|
for property in state {
|
||||||
@ -65,15 +66,17 @@ public struct StateWrapper: Widget {
|
|||||||
if let storage = storage.content[.mainContent]?.first {
|
if let storage = storage.content[.mainContent]?.first {
|
||||||
content()
|
content()
|
||||||
.widget(modifiers: modifiers)
|
.widget(modifiers: modifiers)
|
||||||
.update(storage, modifiers: modifiers, updateProperties: updateProperties)
|
.update(storage, modifiers: modifiers, updateProperties: updateProperties, type: type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a view storage.
|
/// 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.
|
/// - Returns: The view storage.
|
||||||
public func container(modifiers: [(AnyView) -> AnyView]) -> ViewStorage {
|
public func container<WidgetType>(modifiers: [(AnyView) -> AnyView], type: WidgetType.Type) -> ViewStorage {
|
||||||
let content = content().widget(modifiers: modifiers).container(modifiers: modifiers)
|
let content = content().storage(modifiers: modifiers, type: type)
|
||||||
let storage = ViewStorage(content.pointer, content: [.mainContent: [content]])
|
let storage = ViewStorage(content.pointer, content: [.mainContent: [content]])
|
||||||
storage.state = state
|
storage.state = state
|
||||||
observe(storage: storage)
|
observe(storage: storage)
|
||||||
|
|||||||
@ -32,20 +32,21 @@ public struct Wrapper: Widget {
|
|||||||
/// - storage: The view storage.
|
/// - storage: The view storage.
|
||||||
/// - modifiers: Modify views before being updated.
|
/// - modifiers: Modify views before being updated.
|
||||||
/// - updateProperties: Whether to update properties.
|
/// - updateProperties: Whether to update properties.
|
||||||
public func update(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool) {
|
/// - type: The widget types.
|
||||||
if let storage = storage.content[.mainContent]?.first {
|
public func update<WidgetType>(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool, type: WidgetType.Type) {
|
||||||
content
|
guard let storages = storage.content[.mainContent] else {
|
||||||
.widget(modifiers: modifiers)
|
return
|
||||||
.update(storage, modifiers: modifiers, updateProperties: updateProperties)
|
|
||||||
}
|
}
|
||||||
|
content.update(storages, modifiers: modifiers, updateProperties: updateProperties, type: type)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a view storage.
|
/// 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.
|
/// - Returns: The view storage.
|
||||||
public func container(modifiers: [(AnyView) -> AnyView]) -> ViewStorage {
|
public func container<WidgetType>(modifiers: [(AnyView) -> AnyView], type: WidgetType.Type) -> ViewStorage {
|
||||||
let content = content.widget(modifiers: modifiers).container(modifiers: modifiers)
|
ViewStorage(nil, content: [.mainContent: content.map { $0.storage(modifiers: [], type: type) }])
|
||||||
return .init(content.pointer, content: [.mainContent: [content]])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,17 +4,31 @@ import SampleBackends
|
|||||||
struct DemoView: SimpleView {
|
struct DemoView: SimpleView {
|
||||||
|
|
||||||
var view: Body {
|
var view: Body {
|
||||||
Backend1.TestWidget()
|
Backend1.TestWidget1()
|
||||||
|
TestView()
|
||||||
testContent
|
testContent
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
var testContent: Body {
|
var testContent: Body {
|
||||||
Backend2.TestWidget()
|
Backend2.TestWidget2()
|
||||||
Backend1.TestWidget()
|
Backend1.TestWidget1()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
print(DemoView().getDebugTree(parameters: true, type: Backend1.BackendView.self))
|
struct TestView: SimpleView {
|
||||||
print(DemoView().getDebugTree(parameters: true, type: Backend2.BackendView.self))
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|||||||
@ -2,33 +2,32 @@ import Meta
|
|||||||
|
|
||||||
public enum Backend1 {
|
public enum Backend1 {
|
||||||
|
|
||||||
public struct TestWidget: BackendWidget {
|
public struct TestWidget1: BackendWidget {
|
||||||
|
|
||||||
public init() { }
|
public init() { }
|
||||||
|
|
||||||
public var debugTreeContent: [(String, body: Body)] {
|
public var debugTreeContent: [(String, body: Body)] {
|
||||||
[]
|
[]
|
||||||
}
|
}
|
||||||
|
|
||||||
public var debugTreeParameters: [(String, value: CustomStringConvertible)] {
|
public var debugTreeParameters: [(String, value: CustomStringConvertible)] {
|
||||||
[]
|
[]
|
||||||
}
|
}
|
||||||
|
|
||||||
public func container(modifiers: [(AnyView) -> AnyView]) -> ViewStorage {
|
public func container<WidgetType>(modifiers: [(AnyView) -> AnyView], type: WidgetType.Type) -> ViewStorage {
|
||||||
print("Init Content")
|
print("Init test widget 1")
|
||||||
let storage = ViewStorage(nil)
|
let storage = ViewStorage(nil)
|
||||||
storage.fields["test"] = 0
|
storage.fields["test"] = 0
|
||||||
return storage
|
return storage
|
||||||
}
|
}
|
||||||
|
|
||||||
public func update(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool) {
|
public func update<WidgetType>(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool, type: WidgetType.Type) {
|
||||||
storage.fields["test"] = storage.fields["tests"] as? Int ?? 0 + 1
|
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: Widget { }
|
||||||
|
|
||||||
public protocol BackendWidget: BackendView, Widget { }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import Meta
|
|||||||
|
|
||||||
public enum Backend2 {
|
public enum Backend2 {
|
||||||
|
|
||||||
public struct TestWidget: BackendWidget {
|
public struct TestWidget2: BackendWidget {
|
||||||
|
|
||||||
public init() { }
|
public init() { }
|
||||||
|
|
||||||
@ -14,21 +14,20 @@ public enum Backend2 {
|
|||||||
[]
|
[]
|
||||||
}
|
}
|
||||||
|
|
||||||
public func container(modifiers: [(AnyView) -> AnyView]) -> ViewStorage {
|
public func container<WidgetType>(modifiers: [(AnyView) -> AnyView], type: WidgetType.Type) -> ViewStorage {
|
||||||
print("Init Content")
|
print("Init test widget 2")
|
||||||
let storage = ViewStorage(nil)
|
let storage = ViewStorage(nil)
|
||||||
storage.fields["test"] = 0
|
storage.fields["test"] = 0
|
||||||
return storage
|
return storage
|
||||||
}
|
}
|
||||||
|
|
||||||
public func update(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool) {
|
public func update<WidgetType>(_ storage: ViewStorage, modifiers: [(AnyView) -> AnyView], updateProperties: Bool, type: WidgetType.Type) {
|
||||||
storage.fields["test"] = storage.fields["tests"] as? Int ?? 0 + 1
|
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: Widget { }
|
||||||
|
|
||||||
public protocol BackendWidget: BackendView, Widget { }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user