Replace EitherView by the more powerful ViewStack

This commit is contained in:
david-swift 2023-12-30 21:22:57 +01:00
parent b9cdec32c9
commit 37252f7b8f
6 changed files with 120 additions and 113 deletions

View File

@ -20,7 +20,6 @@
- [Button](structs/Button.md)
- [Clamp](structs/Clamp.md)
- [ContentModifier](structs/ContentModifier.md)
- [EitherView](structs/EitherView.md)
- [FileDialog](structs/FileDialog.md)
- [HStack](structs/HStack.md)
- [HeaderBar](structs/HeaderBar.md)
@ -43,6 +42,7 @@
- [Toggle](structs/Toggle.md)
- [ToolbarView](structs/ToolbarView.md)
- [VStack](structs/VStack.md)
- [ViewStack](structs/ViewStack.md)
- [Window](structs/Window.md)
## Classes

View File

@ -0,0 +1,42 @@
**STRUCT**
# `ViewStack`
A widget holding multiple children but only displaying one.
## Properties
### `content`
The stack's active content.
### `id`
The stack's active identifier.
## Methods
### `init(id:view:)`
Initialize the stack.
- Parameters:
- id: The identifier of the current view.
- view: The current view.
### `init(element:view:)`
Initialize the stack.
- Parameters:
- element: The current identifiable element.
- view: The current view.
### `container(modifiers:)`
Get a stack's view storage.
- Parameter modifiers: Modify views before being updated.
- Returns: The stack's view storage.
### `update(_:modifiers:)`
Update a stack's view storage.
- Parameters:
- storage: The view storage.
- modifiers: Modify views before being updated.

View File

@ -58,9 +58,9 @@ public enum ViewBuilder {
/// - Returns: A nonoptional component.
public static func buildOptional(_ component: Component?) -> Component {
if let component {
return .element(EitherView(true, { buildFinalResult(component) }, else: nil))
return .element(ViewStack(id: true) { _ in buildFinalResult(component) })
} else {
return .element(EitherView(false, nil) { [] })
return .element(ViewStack(id: false) { _ in [] })
}
}
@ -68,14 +68,14 @@ public enum ViewBuilder {
/// - Parameter component: A component.
/// - Returns: The component.
public static func buildEither(first component: Component) -> Component {
.element(EitherView(true, { buildFinalResult(component) }, else: nil))
.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(EitherView(false, nil) { buildFinalResult(component) })
.element(ViewStack(id: false) { _ in buildFinalResult(component) })
}
/// Convert a component to an array of elements.

View File

@ -1,107 +0,0 @@
//
// EitherView.swift
// Adwaita
//
// Created by david-swift on 22.08.23.
//
import Libadwaita
/// An equivalent to GtkStack for two views.
public struct EitherView: Widget {
/// The view that is displayed when `isTrue` is true.
var trueView: Body?
/// The view that is displayed when `isTrue` is false.
var falseView: Body?
/// The state.
var isTrue: Bool
/// Initialize an `EitherView`.
/// - Parameters:
/// - isTrue: The state.
/// - _: The view that is presented if `isTrue` is true.
/// - else: The view that is presented if `isTrue` is false.
public init(
_ isTrue: Bool,
@ViewBuilder _ trueView: @escaping () -> Body,
@ViewBuilder else falseView: @escaping () -> Body
) {
self.init(isTrue, .some(trueView), else: .some(falseView))
}
/// Initialize an `EitherView`.
/// - Parameters:
/// - isTrue: The state.
/// - trueView: The view that is presented if `isTrue` is true.
/// - falseView: The view that is presented if `isTrue` is false.
init(_ isTrue: Bool, _ trueView: (() -> Body)? = nil, else falseView: (() -> Body)? = nil) {
self.trueView = trueView?()
self.falseView = falseView?()
self.isTrue = isTrue
}
/// Update an `EitherView`'s storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
let stack = storage.view as? Stack
updateContent(storage, state: true, stack: stack, modifiers: modifiers)
updateContent(storage, state: false, stack: stack, modifiers: modifiers)
if isTrue, let trueView = storage.content["\(true)"]?.last?.view {
setVisible(stack, view: trueView)
} else if !isTrue, let falseView = storage.content["\(false)"]?.last?.view {
setVisible(stack, view: falseView)
}
}
/// Update the content of a view in the view storage.
/// - Parameters:
/// - storage: The view storage.
/// - state: Whether it is the true or false view.
/// - stack: The stack.
/// - modifiers: Modify views before being updated.
private func updateContent(_ storage: ViewStorage, state: Bool, stack: Stack?, modifiers: [(View) -> View]) {
let activeView = (state ? trueView : falseView)?.widget(modifiers: modifiers)
if let view = storage.content["\(state)"]?[safe: 0] {
activeView?.updateStorage(view, modifiers: modifiers)
} else if let view = activeView?.storage(modifiers: modifiers) {
_ = stack?.append(view.view)
storage.content["\(state)"] = [view]
}
}
/// Set the visible content page.
/// - Parameters:
/// - stack: The stack.
/// - view: The visible view.
private func setVisible(_ stack: Stack?, view: NativeWidgetPeer) {
stack?.setVisible(view, transition: view.fields[.transition] as? Transition)
}
/// Get a GtkStack view storage.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let stack = Stack()
var content: [String: [ViewStorage]] = [:]
if let trueView {
let view = trueView.widget(modifiers: modifiers).storage(modifiers: modifiers)
_ = stack.append(view.view)
content["\(true)"] = [view]
}
if let falseView {
let view = falseView.widget(modifiers: modifiers).storage(modifiers: modifiers)
_ = stack.append(view.view)
content["\(false)"] = [view]
}
if isTrue, let trueView = content["\(true)"]?.last?.view {
stack.setVisible(trueView)
} else if let falseView = content["\(false)"]?.last?.view {
stack.setVisible(falseView)
}
return .init(stack, content: content)
}
}

View File

@ -0,0 +1,72 @@
//
// ViewStack.swift
// Adwaita
//
// Created by david-swift on 30.12.23.
//
import Libadwaita
/// A widget holding multiple children but only displaying one.
public struct ViewStack: Widget {
/// The stack's active content.
var content: Body
/// The stack's active identifier.
var id: CustomStringConvertible
/// Initialize the stack.
/// - Parameters:
/// - id: The identifier of the current view.
/// - view: The current view.
public init<Identifier>(
id: Identifier,
@ViewBuilder view: @escaping (Identifier) -> Body
) where Identifier: CustomStringConvertible {
content = view(id)
self.id = id
}
/// Initialize the stack.
/// - Parameters:
/// - element: The current identifiable element.
/// - view: The current view.
public init<Element>(
element: Element,
@ViewBuilder view: @escaping (Element) -> Body
) where Element: Identifiable, Element.ID: CustomStringConvertible {
content = view(element)
self.id = element.id
}
/// Get a stack's view storage.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The stack's view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let stack = Stack()
let storage = ViewStorage(stack)
update(storage, modifiers: modifiers)
return storage
}
/// Update a stack's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let stack = storage.view as? Stack {
let widget = content.widget(modifiers: modifiers)
if let view = storage.content[id.description]?.first {
widget.updateStorage(view, modifiers: modifiers)
} else {
let view = widget.storage(modifiers: modifiers)
_ = stack.append(view.view)
storage.content[id.description] = [view]
}
if let visibleView = storage.content[id.description]?.first?.view {
_ = stack.setVisible(visibleView, transition: visibleView.fields[.transition] as? Transition)
}
}
}
}

View File

@ -5,7 +5,7 @@ This is an overview of the available widgets and other components in _Adwaita_.
| Name | Description | Widget |
| -------------------- | ----------------------------------------------------------------- | ---------------------- |
| Button | A widget that triggers a function when being clicked. | GtkButton |
| EitherView | A widget that displays one of its child views based on a boolean. | GtkStack |
| ViewStack | A widget that displays one of its child views based on an id. | GtkStack |
| HeaderBar | A widget for creating custom title bars for windows. | GtkHeaderBar |
| Text | A widget for displaying a small amount of text. | GtkLabel |
| VStack | A widget which arranges child widgets into a single column. | GtkBox |