Add docc documentation

This commit is contained in:
david-swift 2024-03-29 22:57:42 +01:00
parent 409dfb625d
commit e5783e9049
21 changed files with 697 additions and 3 deletions

View File

@ -1,3 +1,4 @@
version: 1
external_links:
documentation: "https://david-swift.gitbook.io/adwaita"
builder:
configs:
- documentation_targets: [Adwaita]

View File

@ -162,4 +162,5 @@ type_contents_order:
- other_method
excluded:
- Sources/Adwaita/View/Generated/
- Sources/Adwaita/View/Generated/
- Sources/Adwaita/Adwaita.docc/

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 KiB

View File

@ -0,0 +1,83 @@
# ``Adwaita``
_Adwaita for Swift_ is a framework for creating user interfaces for GNOME with an API similar to SwiftUI.
## Overview
Write user interfaces in a declarative way.
As an example, the following code defines a _view_ (more information: ``View``).
```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
}
}
}
}
```
A view can be implemented in different ways, the following screenshot showing an example.
![Screenshot of the counter app](Counter.png)
## Goals
_Adwaita for Swift_'s main goal is to provide an easy-to-use interface for creating apps for the GNOME ecosystem.
An article about the project's motivation is available on the [website of the Swift programming language](https://www.swift.org/blog/adwaita-swift/).
## Installation
### Dependencies
#### Flatpak
It is recommended to develop apps inside of a Flatpak.
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
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](https://brew.sh).
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.
2. Open the `Package.swift` file.
3. Into the `Package` initializer, under `dependencies`, paste:
```swift
.package(url: "https://github.com/AparokshaUI/Adwaita", from: "0.1.0")
```
## Template repository
It is recommended to develop apps on Linux inside a Flatpak.
Find more information in the [template repository](https://github.com/AparokshaUI/AdwaitaTemplate).
## Topics
### Tutorials
- <doc:Table-of-Contents>

View File

@ -0,0 +1,156 @@
# Creating views
Views are the building blocks of your application.
A view can be as simple as the ``Text`` widget, or as complex as the whole content of a single window.
## Add views to a window
You can add views to a window:
```swift
import Adwaita
@main
struct HelloWorld: App {
let id = "io.github.david_swift.HelloWorld"
var app: GTUIApp!
var scene: Scene {
Window(id: "content") { _ in
// These are the views:
HeaderBar.empty()
Text("Hello, world!")
.padding()
}
}
}
```
In this example, the widgets ``HeaderBar`` and ``Text`` are used.
`padding` is a view modifier, a function that modifies a view, which adds some padding around the text.
## Create custom views
While directly adding widgets into the `Window`'s body might work for very simple apps,
it can get messy very quickly.
Create custom views by declaring types that conform to the ``View`` protocol:
```swift
// A custom view named "ContentView":
struct ContentView: View {
var view: Body {
HeaderBar.empty()
Text("Hello, world!")
.padding()
}
}
```
## Properties
As every structure in Swift, custom views can have properties:
```swift
struct HelloView: View {
// The property "text":
var text: String
var view: Body {
Text("Hello, \(text)!")
.padding()
}
}
```
This view can be called via `HelloView(text: "world")` in another view.
## State
Whenever you want to modify a property that is stored in the view's structure from within your view,
wrap the property with the ``State`` property wrapper:
```swift
struct MyView: View {
// This property can be modified form within the view:
@State private var text = "world"
var view: Body {
Text("Hello, \(text)!")
.padding()
Button("Change Text") {
text = Bool.random() ? "world" : "John"
}
.padding(10, .horizontal.add(.bottom))
}
}
```
In this example, the text property is set whenever you press the "Change Text" button.
## Change the state in child views
You can access state properties in child views in the same way as you would access any other property
if the child view cannot modify the state (`HelloView` is defined above):
```swift
struct MyView: View {
@State private var text = "world"
var view: Body {
// "HelloView" can read the "text" property:
HelloView(text: text)
Button("Change Text") {
text = Bool.random() ? "world" : "John"
}
.padding(10, .horizontal.add(.bottom))
}
}
```
If the child view should be able to modify the state, use the ``Binding`` property wrapper in the child view
and pass the property with a dollar sign (`$`) to that view.
```swift
struct MyView: View {
@State private var text = "world"
var view: Body {
HelloView(text: text)
// Pass the editable text property to the child view:
ChangeTextView(text: $text)
}
}
struct ChangeTextView: View {
// Accept the editable text property:
@Binding var text: String
var view: Body {
Button("Change Text") {
// Binding properties can be used the same way as state properties:
text = Bool.random() ? "world" : "John"
}
.padding(10, .horizontal.add(.bottom))
}
}
```
If you have a more complex type and want to pass a property of the type as a binding,
you can simply access the property on the binding.
```swift
HelloView(text: $complexType.text)
```
Whenever you modify a state property (directly or indirectly through bindings),
the user interface gets automatically updated to reflect that change.
## Save state values between app launches
It's possible to automatically save a value that conforms to `Codable` whenever it changes to a file.
The value in the file is read when the view containing the state value appears for the first time (e.g. when the user launches the app).
Use the following syntax, where `"text"` is a unique identifier.
```swift
@State("text") private var text = "world"
```
You can organize your content by specifying a custom folder path which will be appended to the XDG data home directory.
```swift
@State("text", folder: "io.github.david_swift.HelloWorld/my-view") private var text = "world"
```

View File

@ -0,0 +1,82 @@
@Tutorial {
@Intro(title: "The template") {
This is a beginner tutorial. It shows how to create a simple "Hello, world!" app using ``Adwaita``.
While there are instructions for building on macOS, _Adwaita for Swift_ works best on Linux.
}
@Section(title: "Installation") {
@ContentAndMedia {
Learn how to set up your Linux system or your Mac.
}
@Steps {
@Step {
**If you are on Linux,** install the [GNOME Builder IDE](https://flathub.org/apps/org.gnome.Builder).
@Image(source: "Builder.png", alt: "GNOME Builder in the GNOME Software app store.")
}
@Step {
**If you are on macOS,** install [Xcode](https://developer.apple.com/xcode/).
Open your terminal client and follow the [installation instructions for Homebrew](https://brew.sh).
Then, run `brew install libadwaita`.
@Image(source: "InstallLibadwaita.png", alt: "The macOS Terminal application.")
}
}
}
@Section(title: "Clone the template repository") {
@ContentAndMedia {
The template repository provides a simple, working app that can be used as a starting point for your own app.
In this section, you'll create a simple "Hello, world!" app and run the app.
}
@Steps {
@Step {
Open your terminal client and navigate to a directory you want to create the package in (e.g. `~/Documents/`).
@Image(source: "ChangeDirectory.png", alt: "The GNOME Console app.")
}
@Step {
Clone the template repository into the `HelloWorld` directory using `git clone https://github.com/AparokshaUI/AdwaitaTemplate HelloWorld`.
This creates a directory `HelloWorld` containing the content of the [Adwaita Template](https://github.com/AparokshaUI/AdwaitaTemplate).
@Image(source: "GitClone.png", alt: "The GNOME Console app.")
}
@Step {
**If you are on Linux,** use the `Select a Folder...` button in the welcome window of GNOME Builder to open the `HelloWorld` directory.
It will start to install the dependencies automatically.
@Image(source: "OpenFolder.png", alt: "GNOME Builder's welcome view.")
}
@Step {
**If you are on macOS,** use the `Open Existing Project...` button in the welcome window of Xcode to open the `HelloWorld` directory.
@Image(source: "OpenXcode.png", alt: "Xcode's welcome view.")
}
@Step {
Select the `Package.swift` file in the sidebar.
This file defines that this Swift _package_ contains an executable, and lists the dependencies required by the executable.
One can see that the Swift files that are part of the executable are located in the `Sources` folder.
@Code(name: "Package.swift", file: "Package.swift")
}
@Step {
Open the `io.github.AparokshaUI.AdwaitaTemplate.json` file.
This file is relevant for Linux only.
It informs the GNOME Builder about the required dependencies of your app, and how to build and install your app.
It is called a [Flatpak manifest](https://docs.flatpak.org/en/latest/manifests.html).
@Code(name: "io.github.AparokshaUI.AdwaitaTemplate.json", file: "io.github.AparokshaUI.AdwaitaTemplate.json")
}
@Step {
The `Sources` folder contains the actual Swift code of your app.
Open the `AdwaitaTemplate.swift` file to see the definition of an app and its user interface.
@Code(name: "AdwaitaTemplate.swift", file: "AdwaitaTemplate.swift")
}
@Step {
Run the app using the play button in Xcode or GNOME Builder.
A window should open.
On macOS, the window will look slightly different from the one in the screenshot. Note that libadwaita is built for Linux and therefore works best on Linux.
@Image(source: "AdwaitaTemplate.png", alt: "The result.")
}
}
}
}

View File

@ -0,0 +1,115 @@
# Keyboard shortcuts
Keyboard shortcuts can be attached to individual windows or whole applications.
## About keyboard shortcuts
Keyboard shortcuts are represented as a `String`.
You can add a single character by adding itself to the string, e.g. `"n"`.
The F keys are written as `"F1"`, `"F2"`, etc.
For character keys, write the lowercase name instead of the symbol, such as `"minus"` instead of `"-"`.
Add modifiers to the shortcut using the following string modifiers:
- `.shift()`
- `.ctrl()`
- `.alt()`
- `.meta()`
- `.super()`
- `.hyper()`
As an example, the following syntax represents the `Ctrl + N` shortcut: `"n".ctrl()`.
## Add shortcuts to a window
Add a keyboard shortcut to an invividual window. It is only available in that window.
```swift
import Adwaita
@main
struct HelloWorld: App {
let id = "io.github.david_swift.HelloWorld"
var app: GTUIApp!
var scene: Scene {
Window(id: "content") { _ in
HeaderBar.empty()
Text("Hello, world!")
.padding()
}
// Add the shortcut "Ctrl + W" for closing the window
.keyboardShortcut("w".ctrl()) { window in
window.close()
}
}
}
```
## Add shortcuts to an app
Add a keyboard to an app so that the shortcut is available in every top-level window.
```swift
import Adwaita
@main
struct HelloWorld: App {
let id = "io.github.david_swift.HelloWorld"
var app: GTUIApp!
var scene: Scene {
Window(id: "content") { _ in
HeaderBar.empty()
Text("Hello, world!")
.padding()
}
// Add the shortcut "Ctrl + Q" for terminating the app
.appKeyboardShortcut("q".ctrl()) { app in
app.quit()
}
}
}
```
## Create shortcuts from a menu
The most elegant way for adding keyboard shortcuts is in many cases adding them via menus.
Here is an example using a menu button:
```swift
struct TestView: View {
var app: GTUIApp
var view: Body {
Menu(icon: .default(icon: .openMenu), app: app) {
MenuButton("New Window", window: false) {
app.addWindow("main")
}
// Add a keyboard shortcut to the app.
.keyboardShortcut("n".ctrl())
}
}
}
```
Add the keyboard shortcut to a single window by specifying the `window` parameter in the initializer of `Menu`,
and removing `window: false` in the initializer of `MenuButton`.
## Create shortcuts from a button
It's possible to easily create a keyboard shortcut from a button.
Use `appKeyboardShortcut` instead of `keyboardShortcut` for shortcuts on an application level.
Note that the shortcut gets activated after presenting the view for the first time.
```swift
struct HelloView: View {
var window: GTUIWindow
var view: Body {
Button("New Item") {
print("New Item")
}
// Add a keyboard shortcut to the window "window".
.keyboardShortcut("n".ctrl().shift(), window: window)
}
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

View File

@ -0,0 +1,23 @@
// The Swift Programming Language
// https://docs.swift.org/swift-book
import Adwaita
@main
struct AdwaitaTemplate: App {
let id = "io.github.AparokshaUI.AdwaitaTemplate"
var app: GTUIApp!
var scene: Scene {
Window(id: "main") { window in
Text(Loc.helloWorld)
.padding()
.topToolbar {
ToolbarView(app: app, window: window)
}
}
.defaultSize(width: 450, height: 300)
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 KiB

View File

@ -0,0 +1,31 @@
// swift-tools-version: 5.8
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Adwaita Template",
platforms: [
.macOS(.v13)
],
dependencies: [
.package(url: "https://github.com/AparokshaUI/Adwaita", from: "0.2.0"),
.package(url: "https://github.com/AparokshaUI/Localized", from: "0.2.0")
],
targets: [
.executableTarget(
name: "AdwaitaTemplate",
dependencies: [
.product(name: "Adwaita", package: "Adwaita"),
.product(name: "Localized", package: "Localized")
],
path: "Sources",
resources: [
.process("Localized.yml")
],
plugins: [
.plugin(name: "GenerateLocalized", package: "Localized")
]
)
]
)

View File

@ -0,0 +1,52 @@
{
"app-id": "io.github.AparokshaUI.AdwaitaTemplate",
"runtime": "org.gnome.Platform",
"runtime-version": "46",
"sdk": "org.gnome.Sdk",
"sdk-extensions": [
"org.freedesktop.Sdk.Extension.swift5"
],
"command": "AdwaitaTemplate",
"finish-args": [
"--share=ipc",
"--socket=fallback-x11",
"--device=dri",
"--socket=wayland"
],
"build-options": {
"append-path": "/usr/lib/sdk/swift5/bin",
"prepend-ld-library-path": "/usr/lib/sdk/swift5/lib"
},
"cleanup": [
"/include",
"/lib/pkgconfig",
"/man",
"/share/doc",
"/share/gtk-doc",
"/share/man",
"/share/pkgconfig",
"*.la",
"*.a"
],
"modules": [
{
"name": "AdwaitaTemplate",
"builddir": true,
"buildsystem": "simple",
"sources": [
{
"type": "dir",
"path": "."
}
],
"build-commands": [
"swift build -c release --static-swift-stdlib",
"install -Dm755 .build/release/AdwaitaTemplate /app/bin/AdwaitaTemplate",
"install -Dm644 data/io.github.AparokshaUI.AdwaitaTemplate.metainfo.xml $DESTDIR/app/share/metainfo/io.github.AparokshaUI.AdwaitaTemplate.metainfo.xml",
"install -Dm644 data/io.github.AparokshaUI.AdwaitaTemplate.desktop $DESTDIR/app/share/applications/io.github.AparokshaUI.AdwaitaTemplate.desktop",
"install -Dm644 data/icons/io.github.AparokshaUI.AdwaitaTemplate.svg $DESTDIR/app/share/icons/hicolor/scalable/apps/io.github.AparokshaUI.AdwaitaTemplate.svg",
"install -Dm644 data/icons/io.github.AparokshaUI.AdwaitaTemplate-symbolic.svg $DESTDIR/app/share/icons/hicolor/symbolic/apps/io.github.AparokshaUI.AdwaitaTemplate-symbolic.svg"
]
}
]
}

View File

@ -0,0 +1,13 @@
@Tutorials(name: "Develop Apps for GNOME") {
@Intro(title: "Develop Apps for GNOME") {
Learn the basics of _Adwaita for Swift_ to create beautiful apps for the GNOME desktop.
}
@Chapter(name: "Adwaita for Swift essentials") {
Get to know the most important principles of the _Adwaita for Swift_ framework.
@TutorialReference(tutorial: "doc:HelloWorld")
@Image(source: "AdwaitaIcon.png", alt: "The Adwaita for Swift icon.")
}
}

View File

@ -0,0 +1,137 @@
# Windows
Windows in _Adwaita_ are not actually single windows in the user interface,
but rather instructions on how to create one type of window.
## The simplest case
A single window app is an app having exactly one window, and when this window is closed, the app terminates.
We can add multiple windows to an app as well.
Whenever the last one disappears, the app terminates.
```swift
@main
struct HelloWorld: App {
let id = "io.github.david_swift.HelloWorld"
var app: GTUIApp!
var scene: Scene {
Window(id: "content") { _ in
HeaderBar.empty()
Text("Hello, world!")
.padding()
}
// Add a second window:
Window(id: "window-2") { _ in
HeaderBar.empty()
Text("Window 2")
.padding()
}
}
}
```
## Showing windows
Every app contains the property `app`.
You can use this property for running functions that affect the whole app, e.g. quitting the app.
Another use case is showing a window:
```swift
@main
struct HelloWorld: App {
let id = "io.github.david_swift.HelloWorld"
var app: GTUIApp!
var scene: Scene {
Window(id: "content") { _ in
HeaderBar.empty()
Text("Hello, world!")
.padding()
}
Window(id: "control") { _ in
HeaderBar.empty()
Button("Show Window") {
// Show the window with the identifier "content":
app.showWindow("content")
}
.padding()
}
}
}
```
"Showing" a window means creating an instance of the window type if there isn't one,
or focusing the window that already exists of that type otherwise.
It should be used for opening windows that cannot be presented more than once
and for moving a window that is already open into the foreground.
## Adding windows
You can call the `addWindow(_:parent:)` function instead of `showWindow(_:)`
if you want to add and focus another instance of a window type:
```swift
@main
struct HelloWorld: App {
let id = "io.github.david_swift.HelloWorld"
var app: GTUIApp!
var scene: Scene {
Window(id: "content") { _ in
HeaderBar.empty()
Text("Hello, world!")
.padding()
}
Window(id: "control") { _ in
HeaderBar.empty()
Button("Add Window") {
// Add a new instance of the "content" window type
app.addWindow("content")
}
.padding()
}
}
}
```
It can be used to add an overlay window to a certain instance of a window type
by specifying the `parent` parameter, e.g. in the example above:
```swift
Window(id: "control") { window in
HeaderBar.empty()
Button("Add Child Window") {
// Add the new instance as a child window of this window
app.addWindow("content", parent: window)
}
.padding()
}
```
## Customizing the initial number of windows
By default, every window type of the app's scene appears once when the app starts.
It's possible to customize how many windows are being presented at the app's startup:
```swift
@main
struct HelloWorld: App {
let id = "io.github.david_swift.HelloWorld"
var app: GTUIApp!
var scene: Scene {
// Open no window of the "content" type
Window(id: "content", open: 0) { _ in
HeaderBar.empty()
Text("Hello, world!")
.padding()
}
// Open two windows of the "control" type
Window(id: "control", open: 2) { _ in
HeaderBar.empty()
Button("Show Window") {
app.addWindow("content")
}
.padding()
}
}
}
```