Move Adwaita.docc to separate repository
6
.github/workflows/docs.yml
vendored
@ -26,6 +26,12 @@ jobs:
|
|||||||
brew update
|
brew update
|
||||||
brew install libadwaita
|
brew install libadwaita
|
||||||
sed -i '' 's/-I..includedir.//g' $(brew --prefix)/Library/Homebrew/os/mac/pkgconfig/*/libffi.pc
|
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 \
|
||||||
|
|||||||
@ -1,63 +0,0 @@
|
|||||||
# Creating widgets
|
|
||||||
|
|
||||||
Widgets are special views that do not provide a collection of other views as a content,
|
|
||||||
but have functions that are called when creating or updating the view.
|
|
||||||
Normally, a widget manages a GTK or Libadwaita widget using the C API.
|
|
||||||
|
|
||||||
## Recreate the Text widget
|
|
||||||
In this tutorial, we will recreate the ``Text`` widget.
|
|
||||||
A widget conforms to the ``Widget`` protocol:
|
|
||||||
```swift
|
|
||||||
struct CustomText: Widget { }
|
|
||||||
```
|
|
||||||
You can add properties to the widget:
|
|
||||||
```swift
|
|
||||||
struct CustomText: Widget {
|
|
||||||
|
|
||||||
var text: String
|
|
||||||
|
|
||||||
}
|
|
||||||
```
|
|
||||||
This widget can be called in a view body using `CustomText(text: "Hello, world!")`.
|
|
||||||
Now, add the two functions required by the protocol:
|
|
||||||
```swift
|
|
||||||
import CAdw
|
|
||||||
|
|
||||||
struct CustomText: Widget {
|
|
||||||
|
|
||||||
var text: String
|
|
||||||
|
|
||||||
public func container(modifiers: [(View) -> View]) -> ViewStorage { }
|
|
||||||
public func update(_ storage: ViewStorage, modifiers: [(View) -> View], updateProperties: Bool) { }
|
|
||||||
|
|
||||||
}
|
|
||||||
```
|
|
||||||
Import CAdw which exposes the whole C Libadwaita and Gtk API to Swift.
|
|
||||||
|
|
||||||
## The `container(modifiers:)` function
|
|
||||||
This function initializes the widget when the widget appears for the first time.
|
|
||||||
It expects a ``ViewStorage`` as the return type.
|
|
||||||
In our case, this function is very simple:
|
|
||||||
```swift
|
|
||||||
func container(modifiers: [(View) -> View]) -> ViewStorage {
|
|
||||||
.init(gtk_label_new(text)?.opaque())
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## The `update(_:modifiers:updateProperties:)` function
|
|
||||||
Whenever a state of the app changes, the ``Widget/update(_:modifiers:updateProperties:)`` function of the widget gets called.
|
|
||||||
You get the view storage that you have previously initialized as a parameter.
|
|
||||||
Update the storage to reflect the current state of the widget:
|
|
||||||
```swift
|
|
||||||
func update(_ storage: ViewStorage, modifiers: [(View) -> View], updateProperties: Bool) {
|
|
||||||
if updateProperties {
|
|
||||||
gtk_label_set_label(storage.pointer, text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Containers
|
|
||||||
Some widgets act as containers that accept other widgets as children.
|
|
||||||
In that case, use the ``ViewStorage``'s `content` property for storing their view storages.
|
|
||||||
In the ``Widget/update(_:modifiers:updateProperties:)`` function, update the children's storages.
|
|
||||||
Take a look at the code of the container widgets in this library as a reference.
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
# Publishing apps
|
|
||||||
|
|
||||||
Learn how to publish your apps using Flatpak.
|
|
||||||
|
|
||||||
Once you feel ready to publish your app to [Flathub](https://flathub.org/), or
|
|
||||||
to a [self-hosted repository](https://docs.flatpak.org/en/latest/hosting-a-repository.html),
|
|
||||||
you can follow this step-by-step guide.
|
|
||||||
|
|
||||||
## Create a Flatpak manifest
|
|
||||||
You have to create a Flatpak manifest, similar to the one [here](https://github.com/flathub/io.github.david_swift.Flashcards/blob/master/io.github.david_swift.Flashcards.json).
|
|
||||||
Find detailed information in the [Flatpak documentation](https://docs.flatpak.org/en/latest/manifests.html).
|
|
||||||
This is the only code that should be submitted to Flathub.
|
|
||||||
There will be a new repository created under `flathub/app-id` that hosts the manifest.
|
|
||||||
|
|
||||||
### SDK Extension for Swift 5
|
|
||||||
I recommend using the SDK Extension for building the app.
|
|
||||||
Add the following snippet.
|
|
||||||
|
|
||||||
```json
|
|
||||||
"sdk-extensions": [
|
|
||||||
"org.freedesktop.Sdk.Extension.swift5"
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Generate sources for the Swift Package Manager
|
|
||||||
You cannot access the web while building the app.
|
|
||||||
Therefore, you need to add all the dependencies as modules to the manifest file.
|
|
||||||
This can be automated using the [Flatpak builder tool for SPM](https://github.com/flatpak/flatpak-builder-tools/tree/master/spm).
|
|
||||||
|
|
||||||
## MetaInfo file
|
|
||||||
In the Flatpak Manifest file, under the build commands, you should add the [code to install the app's
|
|
||||||
MetaInfo file](https://github.com/flathub/io.github.david_swift.Flashcards/blob/c5c0421ffb5589641ddb44a269a6e7e07d430581/io.github.david_swift.Flashcards.json#L49).
|
|
||||||
The MetaInfo file is located in the app's main repository (not in the Flathub repository).
|
|
||||||
Take a look at the example [here](https://github.com/david-swift/Memorize/blob/main/data/io.github.david_swift.Flashcards.metainfo.xml).
|
|
||||||
|
|
||||||
## Desktop entry file
|
|
||||||
[This line](https://github.com/flathub/io.github.david_swift.Flashcards/blob/c5c0421ffb5589641ddb44a269a6e7e07d430581/io.github.david_swift.Flashcards.json#L50) in the example installs the Desktop Entry file.
|
|
||||||
It is located in the [main repository](https://github.com/david-swift/Memorize/blob/main/data/io.github.david_swift.Flashcards.desktop).
|
|
||||||
|
|
||||||
## Check the requirements
|
|
||||||
Before submitting an app to Flathub, make sure to check the [requirements](https://docs.flathub.org/docs/for-app-authors/requirements),
|
|
||||||
[MetaInfo guidelines](https://docs.flathub.org/docs/for-app-authors/metainfo-guidelines/), and [quality guidelines](https://docs.flathub.org/docs/for-app-authors/metainfo-guidelines/quality-guidelines).
|
|
||||||
Then, test and submit the app following the [submission instructions](https://docs.flathub.org/docs/for-app-authors/submission).
|
|
||||||
|
|
||||||
## Get the badges
|
|
||||||
Use the [Flathub badges](https://flathub.org/badges) to inform users about the simple installation option.
|
|
||||||
Even more assets are available [here](https://github.com/flathub-infra/assets).
|
|
||||||
|
|
||||||
@ -1,163 +0,0 @@
|
|||||||
# ``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.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## 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>
|
|
||||||
|
|
||||||
### Basics
|
|
||||||
|
|
||||||
- <doc:CreatingViews>
|
|
||||||
- <doc:Windows>
|
|
||||||
- <doc:KeyboardShortcuts>
|
|
||||||
|
|
||||||
### Advanced
|
|
||||||
|
|
||||||
- <doc:CreatingWidgets>
|
|
||||||
- <doc:PublishingApps>
|
|
||||||
|
|
||||||
### Views
|
|
||||||
|
|
||||||
- ``ActionRow``
|
|
||||||
- ``Avatar``
|
|
||||||
- ``Banner``
|
|
||||||
- ``Bin``
|
|
||||||
- ``Box``
|
|
||||||
- ``Button``
|
|
||||||
- ``ButtonContent``
|
|
||||||
- ``Carousel``
|
|
||||||
- ``CenterBox``
|
|
||||||
- ``CheckButton``
|
|
||||||
- ``Clamp``
|
|
||||||
- ``ComboRow``
|
|
||||||
- ``EntryRow``
|
|
||||||
- ``ExpanderRow``
|
|
||||||
- ``FlowBox``
|
|
||||||
- ``ForEach``
|
|
||||||
- ``Form``
|
|
||||||
- ``FormSection``
|
|
||||||
- ``HStack``
|
|
||||||
- ``HeaderBar``
|
|
||||||
- ``Label``
|
|
||||||
- ``LevelBar``
|
|
||||||
- ``LinkButton``
|
|
||||||
- ``List``
|
|
||||||
- ``ListBox``
|
|
||||||
- ``Menu``
|
|
||||||
- ``NavigationSplitView``
|
|
||||||
- ``NavigationView``
|
|
||||||
- ``Overlay``
|
|
||||||
- ``OverlaySplitView``
|
|
||||||
- ``PasswordEntryRow``
|
|
||||||
- ``Popover``
|
|
||||||
- ``PreferencesGroup``
|
|
||||||
- ``PreferencesPage``
|
|
||||||
- ``PreferencesRow``
|
|
||||||
- ``ProgressBar``
|
|
||||||
- ``ScrolledWindow``
|
|
||||||
- ``ScrollView``
|
|
||||||
- ``SearchBar``
|
|
||||||
- ``SearchEntry``
|
|
||||||
- ``SpinRow``
|
|
||||||
- ``Spinner``
|
|
||||||
- ``SplitButton``
|
|
||||||
- ``StatusPage``
|
|
||||||
- ``SwitchRow``
|
|
||||||
- ``Text``
|
|
||||||
- ``ToastOverlay``
|
|
||||||
- ``Toggle``
|
|
||||||
- ``ToggleButton``
|
|
||||||
- ``ToolbarView``
|
|
||||||
- ``ViewStack``
|
|
||||||
- ``ViewSwitcher``
|
|
||||||
- ``VStack``
|
|
||||||
- ``WindowTitle``
|
|
||||||
|
|
||||||
### Windows
|
|
||||||
|
|
||||||
- ``AboutWindow``
|
|
||||||
- ``FileDialog``
|
|
||||||
- ``Window``
|
|
||||||
|
|
||||||
### Menus
|
|
||||||
|
|
||||||
- ``MenuButton``
|
|
||||||
- ``MenuSection``
|
|
||||||
- ``Submenu``
|
|
||||||
@ -1,156 +0,0 @@
|
|||||||
# 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"
|
|
||||||
```
|
|
||||||
@ -1,115 +0,0 @@
|
|||||||
# 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
@ -1,137 +0,0 @@
|
|||||||
# 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/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 ``GTUIApp/addWindow(_:parent:)`` function instead of ``GTUIApp/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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
```
|
|
||||||
@ -1,82 +0,0 @@
|
|||||||
@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.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 169 KiB |
@ -1,23 +0,0 @@
|
|||||||
// 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 240 KiB |
|
Before Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 411 KiB |
@ -1,31 +0,0 @@
|
|||||||
// 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")
|
|
||||||
]
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
@ -1,52 +0,0 @@
|
|||||||
{
|
|
||||||
"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"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
@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.")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
{
|
|
||||||
"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"
|
|
||||||
},
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||