Add support for conditional and optional views
This commit is contained in:
parent
05617d2966
commit
1c0d491b02
@ -26,9 +26,7 @@ extension Array: AnyView where Element == AnyView {
|
||||
} else {
|
||||
var modified = self
|
||||
for (index, view) in modified.enumerated() {
|
||||
for modifier in modifiers {
|
||||
modified[safe: index] = modifier(view)
|
||||
}
|
||||
modified[safe: index] = view.getModified(modifiers: modifiers, type: type)
|
||||
}
|
||||
return Data.WrapperType { modified }
|
||||
}
|
||||
|
||||
@ -15,11 +15,14 @@ public protocol AnyView {
|
||||
|
||||
extension AnyView {
|
||||
|
||||
func getModified(modifiers: [(AnyView) -> AnyView]) -> AnyView {
|
||||
func getModified<Data>(modifiers: [(AnyView) -> AnyView], type: Data.Type) -> AnyView where Data: ViewRenderData {
|
||||
var modified: AnyView = self
|
||||
for modifier in modifiers {
|
||||
modified = modifier(modified)
|
||||
}
|
||||
if let dummy = modified as? DummyEitherView {
|
||||
modified = type.EitherViewType(dummy.condition) { dummy.view1 ?? [] } else: { dummy.view2 ?? [] }
|
||||
}
|
||||
return modified
|
||||
}
|
||||
|
||||
@ -55,19 +58,19 @@ extension AnyView {
|
||||
/// - Parameter modifiers: Modify views before being updated.
|
||||
/// - Returns: The widget.
|
||||
func widget<Data>(modifiers: [(AnyView) -> AnyView], type: Data.Type) -> Widget where Data: ViewRenderData {
|
||||
let modified = getModified(modifiers: modifiers)
|
||||
let modified = getModified(modifiers: modifiers, type: type)
|
||||
if let peer = modified as? Widget {
|
||||
return peer
|
||||
}
|
||||
if let array = modified as? Body {
|
||||
return Data.WrapperType { array }
|
||||
}
|
||||
return Data.WrapperType { viewContent.map { $0.getModified(modifiers: modifiers) } }
|
||||
return Data.WrapperType { viewContent.map { $0.getModified(modifiers: modifiers, type: type) } }
|
||||
}
|
||||
|
||||
/// Whether the view can be rendered in a certain environment.
|
||||
func renderable<Data>(type: Data.Type, modifiers: [(AnyView) -> AnyView]) -> Bool where Data: ViewRenderData {
|
||||
let result = getModified(modifiers: modifiers)
|
||||
let result = getModified(modifiers: modifiers, type: type)
|
||||
return result as? Data.WidgetType != nil
|
||||
|| result as? SimpleView != nil
|
||||
|| result as? View != nil
|
||||
|
||||
22
Sources/Model/User Interface/View/EitherView.swift
Normal file
22
Sources/Model/User Interface/View/EitherView.swift
Normal file
@ -0,0 +1,22 @@
|
||||
//
|
||||
// EitherView.swift
|
||||
// Meta
|
||||
//
|
||||
// Created by david-swift on 06.08.24.
|
||||
//
|
||||
|
||||
/// A view building conditional bodies.
|
||||
public protocol EitherView: AnyView {
|
||||
|
||||
/// Initialize the either view.
|
||||
/// - Parameters:
|
||||
/// - condition: Whether the first view is visible-
|
||||
/// - view1: The first view, visible if true.
|
||||
/// - view2: The second view, visible if false.
|
||||
init(
|
||||
_ condition: Bool,
|
||||
@ViewBuilder view1: () -> Body,
|
||||
@ViewBuilder else view2: () -> Body
|
||||
)
|
||||
|
||||
}
|
||||
@ -53,6 +53,27 @@ public enum ViewBuilder {
|
||||
component
|
||||
}
|
||||
|
||||
/// 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(DummyEitherView(condition: component != nil, view1: buildFinalResult(component ?? .element([]))))
|
||||
}
|
||||
|
||||
/// Enables support for `if`-`else` and `switch` statements.
|
||||
/// - Parameter component: A component.
|
||||
/// - Returns: The component.
|
||||
public static func buildEither(first component: Component) -> Component {
|
||||
.element(DummyEitherView(condition: true, view1: 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(DummyEitherView(condition: false, view2: buildFinalResult(component)))
|
||||
}
|
||||
|
||||
/// Convert a component to an array of elements.
|
||||
/// - Parameter component: The component to convert.
|
||||
/// - Returns: The generated array of elements.
|
||||
|
||||
@ -12,5 +12,7 @@ public protocol ViewRenderData {
|
||||
associatedtype WidgetType
|
||||
/// The wrapper widget.
|
||||
associatedtype WrapperType: Wrapper
|
||||
/// The type replacing dummy either views.
|
||||
associatedtype EitherViewType: EitherView
|
||||
|
||||
}
|
||||
|
||||
21
Sources/View/DummyEitherView.swift
Normal file
21
Sources/View/DummyEitherView.swift
Normal file
@ -0,0 +1,21 @@
|
||||
//
|
||||
// DummyEitherView.swift
|
||||
// Meta
|
||||
//
|
||||
// Created by david-swift on 06.08.24.
|
||||
//
|
||||
|
||||
/// A dummy either view. This will be replaced by the platform-specific either view.
|
||||
struct DummyEitherView: SimpleView {
|
||||
|
||||
/// Whether to present the first view.
|
||||
var condition: Bool
|
||||
/// The first view.
|
||||
var view1: Body?
|
||||
/// The second view.
|
||||
var view2: Body?
|
||||
|
||||
/// By default, show the first view.
|
||||
var view: Body { view1 ?? view2 ?? [] }
|
||||
|
||||
}
|
||||
@ -33,9 +33,14 @@ struct DemoView: View {
|
||||
|
||||
@State private var model = TestModel()
|
||||
var app: any AppStorage
|
||||
let condition = false
|
||||
|
||||
var view: Body {
|
||||
Backend1.TestWidget1()
|
||||
if condition {
|
||||
Backend1.TestWidget1()
|
||||
} else {
|
||||
Backend1.TestWidget3()
|
||||
}
|
||||
Backend1.Button(model.test) {
|
||||
Task {
|
||||
app.addSceneElement("main")
|
||||
|
||||
@ -131,10 +131,25 @@ public enum Backend1 {
|
||||
|
||||
}
|
||||
|
||||
public struct EitherView: BackendWidget, Meta.EitherView {
|
||||
|
||||
public init(_ condition: Bool, view1: () -> Body, else view2: () -> Body) {
|
||||
}
|
||||
|
||||
public func container<Data>(modifiers: [(any AnyView) -> any AnyView], type: Data.Type) -> ViewStorage where Data : ViewRenderData {
|
||||
.init(nil)
|
||||
}
|
||||
|
||||
public func update<Data>(_ storage: ViewStorage, modifiers: [(any AnyView) -> any AnyView], updateProperties: Bool, type: Data.Type) where Data : ViewRenderData {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public struct MainViewRenderData: ViewRenderData {
|
||||
|
||||
public typealias WidgetType = BackendWidget
|
||||
public typealias WrapperType = Wrapper
|
||||
public typealias EitherViewType = EitherView
|
||||
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user