Set up documentation
This commit is contained in:
parent
83a03441b5
commit
2551c0a14d
29
.github/ISSUE_TEMPLATE/component_request.yml
vendored
29
.github/ISSUE_TEMPLATE/component_request.yml
vendored
@ -1,29 +0,0 @@
|
|||||||
name: Components request
|
|
||||||
description: Suggest an idea for a new component
|
|
||||||
title: Description of the component request
|
|
||||||
labels: enhancement
|
|
||||||
|
|
||||||
body:
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Why would you like to add a new component?
|
|
||||||
placeholder: >-
|
|
||||||
A clear and concise description of why the component should be added.
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Describe your idea for the implementation.
|
|
||||||
placeholder: >-
|
|
||||||
What could the implementation be like in Adwaita?
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Additional context
|
|
||||||
placeholder: >-
|
|
||||||
Add any other context about the component request here.
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,5 +1,4 @@
|
|||||||
## Steps
|
## Steps
|
||||||
- [ ] Add your name or username and a link to your GitHub profile into the [Contributors.md][1] file.
|
|
||||||
- [ ] Build the project on your machine. If it does not compile, fix the errors.
|
- [ ] Build the project on your machine. If it does not compile, fix the errors.
|
||||||
- [ ] Describe the purpose and approach of your pull request below.
|
- [ ] Describe the purpose and approach of your pull request below.
|
||||||
- [ ] Submit the pull request. Thank you very much for your contribution!
|
- [ ] Submit the pull request. Thank you very much for your contribution!
|
||||||
@ -10,5 +9,3 @@ _If there is a related issue, add the link._
|
|||||||
|
|
||||||
## Approach
|
## Approach
|
||||||
_Describe how this pull request solves the problem or adds the feature._
|
_Describe how this pull request solves the problem or adds the feature._
|
||||||
|
|
||||||
[1]: /Contributors.md
|
|
||||||
|
|||||||
24
.github/workflows/docs.yml
vendored
24
.github/workflows/docs.yml
vendored
@ -3,7 +3,6 @@ name: Deploy Docs
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: ["main"]
|
branches: ["main"]
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
@ -22,31 +21,20 @@ jobs:
|
|||||||
runs-on: macos-14
|
runs-on: macos-14
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Install Libadwaita
|
|
||||||
run: |
|
|
||||||
brew update
|
|
||||||
brew install libadwaita
|
|
||||||
sed -i '' 's/-I..includedir.//g' $(brew --prefix)/Library/Homebrew/os/mac/pkgconfig/*/libffi.pc
|
|
||||||
- name: Clone DocC Repo
|
|
||||||
run: |
|
|
||||||
git clone https://github.com/AparokshaUI/Adwaita.docc Sources/Adwaita/Adwaita.docc
|
|
||||||
rm Sources/Adwaita/Adwaita.docc/LICENSE.md
|
|
||||||
rm Sources/Adwaita/Adwaita.docc/README.md
|
|
||||||
y | rm -r Sources/Adwaita/Adwaita.docc/.git
|
|
||||||
- name: Build Docs
|
- name: Build Docs
|
||||||
run: |
|
run: |
|
||||||
xcrun xcodebuild docbuild \
|
xcrun xcodebuild docbuild \
|
||||||
-scheme Adwaita \
|
-scheme Meta \
|
||||||
-destination 'generic/platform=macOS' \
|
-destination 'generic/platform=macOS' \
|
||||||
-derivedDataPath "$PWD/.derivedData"
|
-derivedDataPath "$PWD/.derivedData" \
|
||||||
|
-skipPackagePluginValidation
|
||||||
xcrun docc process-archive transform-for-static-hosting \
|
xcrun docc process-archive transform-for-static-hosting \
|
||||||
"$PWD/.derivedData/Build/Products/Debug/Adwaita.doccarchive" \
|
"$PWD/.derivedData/Build/Products/Debug/Meta.doccarchive" \
|
||||||
--output-path "docs" \
|
--output-path "docs" \
|
||||||
--hosting-base-path "adwaita-swift"
|
--hosting-base-path "Meta"
|
||||||
- name: Modify Docs
|
- name: Modify Docs
|
||||||
run: |
|
run: |
|
||||||
echo "<script>window.location.href += \"/documentation/adwaita\"</script>" > docs/index.html;
|
echo "<script>window.location.href += \"/documentation/meta\"</script>" > docs/index.html;
|
||||||
sed -i '' 's/#06f/#ea3358/g' docs/css/documentation-topic~topic~tutorials-overview.d6f5411c.css
|
|
||||||
sed -i '' 's/,2px/,10px/g' docs/css/index.038e887c.css
|
sed -i '' 's/,2px/,10px/g' docs/css/index.038e887c.css
|
||||||
- name: Upload Artifact
|
- name: Upload Artifact
|
||||||
uses: actions/upload-pages-artifact@v3
|
uses: actions/upload-pages-artifact@v3
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// swift-tools-version: 5.10
|
// swift-tools-version: 5.9
|
||||||
//
|
//
|
||||||
// Package.swift
|
// Package.swift
|
||||||
// Meta
|
// Meta
|
||||||
|
|||||||
134
README.md
134
README.md
@ -1,141 +1,57 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<img width="256" alt="Adwaita Icon" src="Icons/AdwaitaIcon.png">
|
<h1 align="center">Meta</h1>
|
||||||
<h1 align="center">Adwaita for Swift</h1>
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://aparokshaui.github.io/adwaita-swift/">
|
<a href="https://aparokshaui.github.io/meta/">
|
||||||
Documentation
|
Documentation
|
||||||
</a>
|
</a>
|
||||||
·
|
·
|
||||||
<a href="https://github.com/AparokshaUI/Adwaita">
|
<a href="https://github.com/AparokshaUI/Meta">
|
||||||
GitHub
|
GitHub
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
_Adwaita_ is a framework for creating user interfaces for GNOME with an API similar to SwiftUI.
|
_Meta_ is a framework allowing the creation of user interface (UI) frameworks in Swift.
|
||||||
|
|
||||||
The following code:
|
|
||||||
|
|
||||||
```swift
|
|
||||||
struct Counter: View {
|
|
||||||
|
|
||||||
@State private var count = 0
|
|
||||||
|
|
||||||
var view: Body {
|
|
||||||
HStack {
|
|
||||||
Button(icon: .default(icon: .goPrevious)) {
|
|
||||||
count -= 1
|
|
||||||
}
|
|
||||||
Text("\(count)")
|
|
||||||
.style("title-1")
|
|
||||||
.frame(minWidth: 100)
|
|
||||||
Button(icon: .default(icon: .goNext)) {
|
|
||||||
count += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Describes a simple counter view:
|
|
||||||
|
|
||||||
![Counter Example][image-1]
|
|
||||||
|
|
||||||
More examples are available in the [demo app][1].
|
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
- [Goals][2]
|
- [Overview](#overview)
|
||||||
- [Widgets][3]
|
- [Usage](#usage)
|
||||||
- [Installation][4]
|
- [Thanks](#thanks)
|
||||||
- [Usage][5]
|
|
||||||
- [Thanks][6]
|
|
||||||
|
|
||||||
## Goals
|
## Overview
|
||||||
|
|
||||||
_Adwaita_’s main goal is to provide an easy-to-use interface for creating GNOME apps. The backend should stay as simple as possible, while not limiting the possibilities there are with [Libadwaita][7] and [GTK][8].
|
_Meta_ follows the following principles:
|
||||||
|
|
||||||
If you want to use _Adwaita_ in a project, but there are widgets missing, open an [issue on GitHub][9].
|
- It is a **declarative** framework, meaning that instead of writing _how_ to construct a user interface, you write _what_ it looks like.
|
||||||
|
- The user interface is treated as a function of its **state**. Instead of directly modifying the UI, modify its state to update views.
|
||||||
|
- Multiple UI frameworks can be used in the same code, but the **selection of the framework** happens when executing the app. This enables the creation of cross-platform UI frameworks combining several UI frameworks rendering always with the same backend.
|
||||||
|
|
||||||
Find more information about the project's motivation in [this blog post](https://www.swift.org/blog/adwaita-swift/).
|
It knows the following layers of UI:
|
||||||
|
|
||||||
## Widgets
|
- An app is the entry point of the executable, containing the windows.
|
||||||
|
- A window is a container holding one or multiple views.
|
||||||
|
- A view is a part of the actual UI inside a window, another view or a menu.
|
||||||
|
- A menu is a list of buttons, other menus, and views. Certain views (such as menu buttons) allow menus to be used.
|
||||||
|
|
||||||
An overview of the widgets supported by _Adwaita_ is available [here](user-manual/Information/Widgets.md).
|
Detailed information can be found in the [docs](https://aparokshaui.github.io/meta/).
|
||||||
|
|
||||||
## Installation
|
## Usage
|
||||||
### Dependencies
|
|
||||||
#### Flatpak
|
|
||||||
|
|
||||||
It is recommended to develop apps inside of a Flatpak.
|
_Meta_ can be used for creating UI frameworks in Swift which can then be used to create apps.
|
||||||
That way, you don't have to install Swift or any of the dependencies on your system, and you always have access to the latest versions.
|
|
||||||
Take a look at the [template repository](https://github.com/AparokshaUI/AdwaitaTemplate).
|
|
||||||
This works on Linux only.
|
|
||||||
|
|
||||||
#### Directly on System
|
Follow those steps if you want to create a UI framework.
|
||||||
|
|
||||||
You can also run your apps directly on the system.
|
|
||||||
|
|
||||||
If you are using a Linux distribution, install `libadwaita-devel` or `libadwaita` (or something similar, based on the package manager) as well as `gtk4-devel`, `gtk4` or similar.
|
|
||||||
|
|
||||||
On macOS, follow these steps:
|
|
||||||
1. Install [Homebrew][11].
|
|
||||||
2. Install Libadwaita (and thereby GTK 4):
|
|
||||||
```
|
|
||||||
brew install libadwaita
|
|
||||||
```
|
|
||||||
|
|
||||||
### Swift Package
|
|
||||||
1. Open your Swift package in GNOME Builder, Xcode, or any other IDE.
|
1. Open your Swift package in GNOME Builder, Xcode, or any other IDE.
|
||||||
2. Open the `Package.swift` file.
|
2. Open the `Package.swift` file.
|
||||||
3. Into the `Package` initializer, under `dependencies`, paste:
|
3. Into the `Package` initializer, under `dependencies`, paste:
|
||||||
```swift
|
```swift
|
||||||
.package(url: "https://github.com/AparokshaUI/Adwaita", from: "0.1.0")
|
.package(url: "https://github.com/AparokshaUI/Meta", from: "0.1.0")
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
I recommend using the [template repository](https://github.com/AparokshaUI/AdwaitaTemplate) as a starting point.
|
|
||||||
|
|
||||||
Follow the [interactive tutorial](https://aparokshaui.github.io/adwaita-swift/tutorials/table-of-contents) or [read the docs](https://aparokshaui.github.io/adwaita-swift/documentation/adwaita) in order to get to know _Adwaita for Swift_.
|
|
||||||
|
|
||||||
## Thanks
|
## Thanks
|
||||||
|
|
||||||
### Dependencies
|
- [DocC](https://github.com/apple/swift-docc) used for the documentation
|
||||||
- [XMLCoder][18] licensed under the [MIT license][19]
|
- [SwiftLint](https://github.com/realm/SwiftLint) for checking whether code style conventions are violated
|
||||||
- [Levenshtein Transformations](https://github.com/david-swift/LevenshteinTransformations) licensed under the [MIT license](https://github.com/david-swift/LevenshteinTransformations/blob/main/LICENSE.md)
|
- The programming language [Swift](https://github.com/swiftlang/swift)
|
||||||
|
|
||||||
### Other Thanks
|
|
||||||
- The [contributors][20]
|
|
||||||
- The auto-generation of widgets is based on [Swift Cross UI](https://github.com/stackotter/swift-cross-ui)
|
|
||||||
- [SwiftLint][21] for checking whether code style conventions are violated
|
|
||||||
- The programming language [Swift][22]
|
|
||||||
|
|
||||||
[1]: Tests/
|
|
||||||
[2]: #goals
|
|
||||||
[3]: #widgets
|
|
||||||
[4]: #installation
|
|
||||||
[5]: #usage
|
|
||||||
[6]: #thanks
|
|
||||||
[7]: https://gnome.pages.gitlab.gnome.org/libadwaita/doc/1-latest/index.html
|
|
||||||
[8]: https://docs.gtk.org/gtk4/
|
|
||||||
[9]: https://github.com/AparokshaUI/Adwaita/issues
|
|
||||||
[10]: https://github.com/AparokshaUI/Libadwaita
|
|
||||||
[11]: https://brew.sh
|
|
||||||
[12]: user-manual/GettingStarted.md
|
|
||||||
[13]: user-manual/Basics/HelloWorld.md
|
|
||||||
[14]: user-manual/Basics/CreatingViews.md
|
|
||||||
[15]: user-manual/Basics/Windows.md
|
|
||||||
[16]: user-manual/Basics/KeyboardShortcuts.md
|
|
||||||
[17]: user-manual/Advanced/CreatingWidgets.md
|
|
||||||
[18]: https://github.com/CoreOffice/XMLCoder
|
|
||||||
[19]: https://github.com/CoreOffice/XMLCoder/blob/main/LICENSE
|
|
||||||
[20]: Contributors.md
|
|
||||||
[21]: https://github.com/realm/SwiftLint
|
|
||||||
[22]: https://github.com/apple/swift
|
|
||||||
[23]: https://github.com/SourceDocs/SourceDocs
|
|
||||||
|
|
||||||
[image-1]: Icons/Counter.png
|
|
||||||
[image-2]: Icons/Demo.png
|
|
||||||
|
|||||||
18
Sources/Meta.docc/Meta.md
Normal file
18
Sources/Meta.docc/Meta.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# ``Meta``
|
||||||
|
|
||||||
|
_Meta_ is a framework allowing the creation of user interface (UI) frameworks in Swift.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
_Meta_ follows the following principles:
|
||||||
|
|
||||||
|
- It is a **declarative** framework, meaning that instead of writing _how_ to construct a user interface, you write _what_ it looks like.
|
||||||
|
- The user interface is treated as a function of its **state**. Instead of directly modifying the UI, modify its state to update views.
|
||||||
|
- Multiple UI frameworks can be used in the same code, but the **selection of the framework** happens when executing the app. This enables the creation of cross-platform UI frameworks combining several UI frameworks rendering always with the same backend.
|
||||||
|
|
||||||
|
It knows the following layers of UI:
|
||||||
|
|
||||||
|
- An app is the entry point of the executable, containing the windows.
|
||||||
|
- A window is a container holding one or multiple views.
|
||||||
|
- A view is a part of the actual UI inside a window, another view or a menu.
|
||||||
|
- A menu is a list of buttons, other menus, and views. Certain views (such as menu buttons) allow menus to be used.
|
||||||
46
Sources/Meta.docc/theme-settings.json
Normal file
46
Sources/Meta.docc/theme-settings.json
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"theme": {
|
||||||
|
"border-radius": "10px",
|
||||||
|
"button": {
|
||||||
|
"border-radius": "20px"
|
||||||
|
},
|
||||||
|
"color": {
|
||||||
|
"button-background": "#ea3358",
|
||||||
|
"button-background-active": "#ea3358",
|
||||||
|
"button-background-hover": "#fc557a",
|
||||||
|
"button-text": "#ffffff",
|
||||||
|
"header": "#7f313b",
|
||||||
|
"documentation-intro-accent": "var(--color-header)",
|
||||||
|
"documentation-intro-fill": "radial-gradient(circle at top, var(--color-header) 30%, #000 100%)",
|
||||||
|
"link": "#ea3358",
|
||||||
|
"nav-link-color": "#ea3358",
|
||||||
|
"nav-dark-link-color": "#ea3358",
|
||||||
|
"tutorials-overview-link": "#fb4469",
|
||||||
|
"step-background": {
|
||||||
|
"light": "#fffaff",
|
||||||
|
"dark": "#302c2d"
|
||||||
|
},
|
||||||
|
"step-focused": "#ea3358",
|
||||||
|
"tabnav-item-border-color": "#ea3358",
|
||||||
|
"tutorial-background": {
|
||||||
|
"light": "",
|
||||||
|
"dark": "#1d1d1f"
|
||||||
|
},
|
||||||
|
"tutorials-overview-background": "linear-gradient(180deg, rgba(43,20,23,1) 0%, rgba(41, 3, 8, 0.808) 60%, rgba(0,0,0,1) 100%)",
|
||||||
|
"fill-light-blue-secondary": "#ea3358",
|
||||||
|
"fill-blue": "#ea3358",
|
||||||
|
"figure-blue": "#ea3358",
|
||||||
|
"standard-blue-documentation-intro-fill": "#ea3358",
|
||||||
|
"figure-blue": "#ea3358",
|
||||||
|
"tutorial-hero-background": "#100a0b",
|
||||||
|
"navigator-item-hover": {
|
||||||
|
"light": "#ea335815",
|
||||||
|
"dark": "#7f313b"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": "#ea3358",
|
||||||
|
"tutorial-step": {
|
||||||
|
"border-radius": "15px"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -71,7 +71,7 @@ public struct Binding<Value> {
|
|||||||
private var handlers: [(Value) -> Void] = []
|
private var handlers: [(Value) -> Void] = []
|
||||||
|
|
||||||
/// Get a property of any content of a `Binding` as a `Binding`.
|
/// Get a property of any content of a `Binding` as a `Binding`.
|
||||||
/// - Parameter dynamicMember: The path to the member.
|
/// - Parameter keyPath: The path to the member.
|
||||||
/// - Returns: The binding.
|
/// - Returns: The binding.
|
||||||
public subscript<Subject>(dynamicMember keyPath: WritableKeyPath<Value, Subject>) -> Binding<Subject> {
|
public subscript<Subject>(dynamicMember keyPath: WritableKeyPath<Value, Subject>) -> Binding<Subject> {
|
||||||
.init {
|
.init {
|
||||||
|
|||||||
@ -54,6 +54,7 @@ extension Array: AnyView where Element == AnyView {
|
|||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - modifiers: Modify views before generating the storages.
|
/// - modifiers: Modify views before generating the storages.
|
||||||
/// - type: The type of the widgets.
|
/// - type: The type of the widgets.
|
||||||
|
/// - Returns: The storages.
|
||||||
public func storages<WidgetType>(
|
public func storages<WidgetType>(
|
||||||
modifiers: [(AnyView) -> AnyView],
|
modifiers: [(AnyView) -> AnyView],
|
||||||
type: WidgetType.Type
|
type: WidgetType.Type
|
||||||
|
|||||||
@ -1,35 +0,0 @@
|
|||||||
//
|
|
||||||
// DefaultStringInterpolation.swift
|
|
||||||
// Meta
|
|
||||||
//
|
|
||||||
// Created by david-swift on 26.05.24.
|
|
||||||
//
|
|
||||||
// Thanks to Eneko Alonso, Pyry Jahkola, cukr for the comments in this Swift forum discussion:
|
|
||||||
// "Multi-line string nested indentation with interpolation"
|
|
||||||
// https://forums.swift.org/t/multi-line-string-nested-indentation-with-interpolation/36933
|
|
||||||
//
|
|
||||||
|
|
||||||
extension DefaultStringInterpolation {
|
|
||||||
|
|
||||||
/// Preserve the indentation in a multi line string.
|
|
||||||
/// - Parameter string: The string.
|
|
||||||
///
|
|
||||||
/// Use it the following way:
|
|
||||||
/// """
|
|
||||||
/// Hello
|
|
||||||
/// \(indented: "World\n Test")
|
|
||||||
/// """
|
|
||||||
public mutating func appendInterpolation(indented string: String) {
|
|
||||||
// swiftlint:disable compiler_protocol_init
|
|
||||||
let indent = String(stringInterpolation: self).reversed().prefix { " \t".contains($0) }
|
|
||||||
// swiftlint:enable compiler_protocol_init
|
|
||||||
if indent.isEmpty {
|
|
||||||
appendInterpolation(string)
|
|
||||||
} else {
|
|
||||||
appendLiteral(
|
|
||||||
string.split(separator: "\n", omittingEmptySubsequences: false).joined(separator: "\n" + indent)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
extension String {
|
extension String {
|
||||||
|
|
||||||
/// A label for main content in a view storage.
|
/// An identifier for main content in a view storage.
|
||||||
static var mainContent: Self { "main" }
|
public static var mainContent: Self { "main" }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,7 +51,7 @@ extension AnyView {
|
|||||||
/// Wrap the view into a widget.
|
/// Wrap the view into a widget.
|
||||||
/// - Parameter modifiers: Modify views before being updated.
|
/// - Parameter modifiers: Modify views before being updated.
|
||||||
/// - Returns: The widget.
|
/// - Returns: The widget.
|
||||||
public func widget(modifiers: [(AnyView) -> AnyView]) -> Widget {
|
func widget(modifiers: [(AnyView) -> AnyView]) -> Widget {
|
||||||
let modified = getModified(modifiers: modifiers)
|
let modified = getModified(modifiers: modifiers)
|
||||||
if let peer = modified as? Widget {
|
if let peer = modified as? Widget {
|
||||||
return peer
|
return peer
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import Foundation
|
|||||||
@resultBuilder
|
@resultBuilder
|
||||||
public enum ViewBuilder {
|
public enum ViewBuilder {
|
||||||
|
|
||||||
/// A component used in the ``ArrayBuilder``.
|
/// A component used in the ``ViewBuilder``.
|
||||||
public enum Component {
|
public enum Component {
|
||||||
|
|
||||||
/// A view as a component.
|
/// A view as a component.
|
||||||
|
|||||||
@ -5,19 +5,22 @@
|
|||||||
// Created by david-swift on 26.05.24.
|
// Created by david-swift on 26.05.24.
|
||||||
//
|
//
|
||||||
|
|
||||||
/// Store a rendered view in a view storage.
|
/// Store a reference to a rendered view in a view storage.
|
||||||
public class ViewStorage {
|
public class ViewStorage {
|
||||||
|
|
||||||
/// The pointer.
|
/// 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?
|
public var pointer: Any?
|
||||||
/// The view's content.
|
/// The view's content for container widgets.
|
||||||
public var content: [String: [ViewStorage]]
|
public var content: [String: [ViewStorage]]
|
||||||
/// The view's state (used in `StateWrapper`).
|
/// The view's state (used in `StateWrapper`).
|
||||||
var state: [String: StateProtocol] = [:]
|
var state: [String: StateProtocol] = [:]
|
||||||
/// Other properties.
|
/// Various properties of a widget.
|
||||||
public var fields: [String: Any] = [:]
|
public var fields: [String: Any] = [:]
|
||||||
|
|
||||||
/// The pointer as an opaque pointer.
|
/// The pointer as an opaque pointer, as this is needed with backends interoperating with C or C++.
|
||||||
public var opaquePointer: OpaquePointer? {
|
public var opaquePointer: OpaquePointer? {
|
||||||
get {
|
get {
|
||||||
pointer as? OpaquePointer
|
pointer as? OpaquePointer
|
||||||
@ -30,7 +33,7 @@ public class ViewStorage {
|
|||||||
/// Initialize a view storage.
|
/// Initialize a view storage.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - pointer: The pointer to the widget, its type depends on the backend.
|
/// - pointer: The pointer to the widget, its type depends on the backend.
|
||||||
/// - content: The view's content.
|
/// - content: The view's content for container widgets.
|
||||||
public init(
|
public init(
|
||||||
_ pointer: Any?,
|
_ pointer: Any?,
|
||||||
content: [String: [ViewStorage]] = [:]
|
content: [String: [ViewStorage]] = [:]
|
||||||
|
|||||||
@ -5,7 +5,10 @@
|
|||||||
// Created by david-swift on 26.05.24.
|
// Created by david-swift on 26.05.24.
|
||||||
//
|
//
|
||||||
|
|
||||||
/// A widget is a view that know about its GTUI widget.
|
/// A widget is a view that know about its native backend widget.
|
||||||
|
///
|
||||||
|
/// It enables the translation from the declarative definition to the creation
|
||||||
|
/// and updating of widgets in an imperative way.
|
||||||
public protocol Widget: AnyView {
|
public protocol Widget: AnyView {
|
||||||
|
|
||||||
/// The view storage.
|
/// The view storage.
|
||||||
|
|||||||
@ -8,19 +8,16 @@
|
|||||||
import Observation
|
import Observation
|
||||||
|
|
||||||
/// A storage for `@State` properties.
|
/// A storage for `@State` properties.
|
||||||
public struct StateWrapper: ConvenienceWidget {
|
struct StateWrapper: ConvenienceWidget {
|
||||||
|
|
||||||
/// The content.
|
/// The content.
|
||||||
var content: () -> Body
|
var content: () -> Body
|
||||||
/// The state information (from properties with the `State` wrapper).
|
/// The state information (from properties with the `State` wrapper).
|
||||||
var state: [String: StateProtocol] = [:]
|
var state: [String: StateProtocol] = [:]
|
||||||
|
|
||||||
/// The identifier of the field storing whether to update the wrapper's content.
|
|
||||||
private var updateID: String { "update" }
|
|
||||||
|
|
||||||
/// Initialize a `StateWrapper`.
|
/// Initialize a `StateWrapper`.
|
||||||
/// - Parameter content: The view content.
|
/// - Parameter content: The view content.
|
||||||
public init(@ViewBuilder content: @escaping () -> Body) {
|
init(@ViewBuilder content: @escaping () -> Body) {
|
||||||
self.content = content
|
self.content = content
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,14 +36,13 @@ public struct StateWrapper: ConvenienceWidget {
|
|||||||
/// - modifiers: Modify views before being updated.
|
/// - modifiers: Modify views before being updated.
|
||||||
/// - updateProperties: Whether to update properties.
|
/// - updateProperties: Whether to update properties.
|
||||||
/// - type: The type of the widgets.
|
/// - type: The type of the widgets.
|
||||||
public func update<WidgetType>(
|
func update<WidgetType>(
|
||||||
_ storage: ViewStorage,
|
_ storage: ViewStorage,
|
||||||
modifiers: [(AnyView) -> AnyView],
|
modifiers: [(AnyView) -> AnyView],
|
||||||
updateProperties: Bool,
|
updateProperties: Bool,
|
||||||
type: WidgetType.Type
|
type: WidgetType.Type
|
||||||
) {
|
) {
|
||||||
var updateProperties = updateProperties ? true : (storage.fields[updateID] as? Bool ?? false)
|
var updateProperties = updateProperties
|
||||||
storage.fields[updateID] = false
|
|
||||||
for property in state {
|
for property in state {
|
||||||
if let oldID = storage.state[property.key]?.id {
|
if let oldID = storage.state[property.key]?.id {
|
||||||
StateManager.changeID(old: oldID, new: property.value.id)
|
StateManager.changeID(old: oldID, new: property.value.id)
|
||||||
@ -68,7 +64,7 @@ public struct StateWrapper: ConvenienceWidget {
|
|||||||
/// - modifiers: Modify views before being updated.
|
/// - modifiers: Modify views before being updated.
|
||||||
/// - type: The type of the widgets.
|
/// - type: The type of the widgets.
|
||||||
/// - Returns: The view storage.
|
/// - Returns: The view storage.
|
||||||
public func container<WidgetType>(modifiers: [(AnyView) -> AnyView], type: WidgetType.Type) -> ViewStorage {
|
func container<WidgetType>(modifiers: [(AnyView) -> AnyView], type: WidgetType.Type) -> ViewStorage {
|
||||||
let content = content().storages(modifiers: modifiers, type: type)
|
let content = content().storages(modifiers: modifiers, type: type)
|
||||||
let storage = ViewStorage(nil, content: [.mainContent: content])
|
let storage = ViewStorage(nil, content: [.mainContent: content])
|
||||||
storage.state = state
|
storage.state = state
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
// Created by david-swift on 27.05.24.
|
// Created by david-swift on 27.05.24.
|
||||||
//
|
//
|
||||||
|
|
||||||
/// Wrap a view into a single widget.
|
/// Wrap a body into a single widget.
|
||||||
public struct Wrapper: ConvenienceWidget {
|
public struct Wrapper: ConvenienceWidget {
|
||||||
|
|
||||||
/// The content.
|
/// The content.
|
||||||
|
|||||||
@ -65,12 +65,11 @@ struct DemoApp {
|
|||||||
DemoView().updateStorage(storage, modifiers: [], updateProperties: true, type: backendType)
|
DemoView().updateStorage(storage, modifiers: [], updateProperties: true, type: backendType)
|
||||||
}
|
}
|
||||||
|
|
||||||
StateManager.addUpdateHandler { _ in
|
StateManager.addUpdateHandler { force in
|
||||||
DemoView().updateStorage(storage, modifiers: [], updateProperties: false, type: backendType)
|
DemoView().updateStorage(storage, modifiers: [], updateProperties: force, type: backendType)
|
||||||
}
|
}
|
||||||
|
|
||||||
sleep(2)
|
sleep(2)
|
||||||
DemoView().updateStorage(storage, modifiers: [], updateProperties: true, type: backendType)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user