Add support for toasts
Add the new concept of signals
This commit is contained in:
parent
5ab9387317
commit
36e61255f8
@ -13,6 +13,7 @@
|
||||
|
||||
## Structs
|
||||
|
||||
- [AppearObserver](structs/AppearObserver.md)
|
||||
- [Binding](structs/Binding.md)
|
||||
- [Button](structs/Button.md)
|
||||
- [Clamp](structs/Clamp.md)
|
||||
@ -28,11 +29,13 @@
|
||||
- [ModifierStopper](structs/ModifierStopper.md)
|
||||
- [NavigationSplitView](structs/NavigationSplitView.md)
|
||||
- [ScrollView](structs/ScrollView.md)
|
||||
- [Signal](structs/Signal.md)
|
||||
- [State](structs/State.md)
|
||||
- [StateWrapper](structs/StateWrapper.md)
|
||||
- [StatusPage](structs/StatusPage.md)
|
||||
- [Submenu](structs/Submenu.md)
|
||||
- [Text](structs/Text.md)
|
||||
- [ToastOverlay](structs/ToastOverlay.md)
|
||||
- [ToolbarView](structs/ToolbarView.md)
|
||||
- [VStack](structs/VStack.md)
|
||||
- [Window](structs/Window.md)
|
||||
|
||||
@ -24,6 +24,12 @@ Get a storage.
|
||||
|
||||
### `getModified(modifiers:)`
|
||||
|
||||
### `onAppear(_:)`
|
||||
|
||||
Run a function when the view appears for the first time.
|
||||
- Parameter closure: The function.
|
||||
- Returns: A view.
|
||||
|
||||
### `frame(maxSize:)`
|
||||
|
||||
Set the view's maximal size.
|
||||
@ -113,6 +119,24 @@ Run a function when the view gets an update.
|
||||
Remove all of the content modifiers for the wrapped views.
|
||||
- Returns: A view.
|
||||
|
||||
### `toast(_:signal:)`
|
||||
|
||||
Present a toast when the signal gets activated.
|
||||
- Parameters:
|
||||
- title: The title of the toast.
|
||||
- signal: The signal which activates the presentation of a toast.
|
||||
- Returns: A view.
|
||||
|
||||
### `toast(_:signal:button:handler:)`
|
||||
|
||||
Present a toast with a button when the signal gets activated.
|
||||
- Parameters:
|
||||
- title: The title of the toast.
|
||||
- signal: The signal which activates the presentation of a toast.
|
||||
- button: The button's label.
|
||||
- handler: The handler for the button.
|
||||
- Returns: A view.
|
||||
|
||||
### `topToolbar(visible:_:)`
|
||||
|
||||
Add a top toolbar to the view.
|
||||
|
||||
28
Documentation/Reference/structs/AppearObserver.md
Normal file
28
Documentation/Reference/structs/AppearObserver.md
Normal file
@ -0,0 +1,28 @@
|
||||
**STRUCT**
|
||||
|
||||
# `AppearObserver`
|
||||
|
||||
A widget which executes a custom code when being rendered for the first time.
|
||||
|
||||
## Properties
|
||||
### `onAppear`
|
||||
|
||||
The function.
|
||||
|
||||
### `content`
|
||||
|
||||
The content.
|
||||
|
||||
## Methods
|
||||
### `container(modifiers:)`
|
||||
|
||||
Get the content's container.
|
||||
- Parameter modifiers: Modify views before being updated.
|
||||
- Returns: The content's container.
|
||||
|
||||
### `update(_:modifiers:)`
|
||||
|
||||
Update the content.
|
||||
- Parameters:
|
||||
- storage: The content's storage.
|
||||
- modifiers: Modify views before being updated.
|
||||
23
Documentation/Reference/structs/Signal.md
Normal file
23
Documentation/Reference/structs/Signal.md
Normal file
@ -0,0 +1,23 @@
|
||||
**STRUCT**
|
||||
|
||||
# `Signal`
|
||||
|
||||
A type that signalizes an action.
|
||||
|
||||
## Properties
|
||||
### `boolean`
|
||||
|
||||
An action is signalized by toggling a boolean to `true` and back to `false`.
|
||||
|
||||
### `update`
|
||||
|
||||
Whether the action has caused an update.
|
||||
|
||||
## Methods
|
||||
### `init()`
|
||||
|
||||
Initialize a signal.
|
||||
|
||||
### `signal()`
|
||||
|
||||
Activate a signal.
|
||||
41
Documentation/Reference/structs/ToastOverlay.md
Normal file
41
Documentation/Reference/structs/ToastOverlay.md
Normal file
@ -0,0 +1,41 @@
|
||||
**STRUCT**
|
||||
|
||||
# `ToastOverlay`
|
||||
|
||||
A wrapper around a view presenting toasts.
|
||||
|
||||
## Properties
|
||||
### `signal`
|
||||
|
||||
The signal for showing the toast./// Present a toast when the signal gets activated.
|
||||
|
||||
### `child`
|
||||
|
||||
The child view.
|
||||
|
||||
### `title`
|
||||
|
||||
The title of the toast.
|
||||
|
||||
### `button`
|
||||
|
||||
Information about the button if available (label and handler).
|
||||
|
||||
## Methods
|
||||
### `container(modifiers:)`
|
||||
|
||||
Get the overlay's view storage.
|
||||
- Parameter modifiers: The view modifiers.
|
||||
- Returns: The view storage.
|
||||
|
||||
### `update(_:modifiers:)`
|
||||
|
||||
Update the overlay's view storage.
|
||||
- Parameters:
|
||||
- storage: The view storage.
|
||||
- modifiers: The view modifiers.
|
||||
|
||||
### `setVisibility(_:)`
|
||||
|
||||
Add a toast if the signal is active.
|
||||
- Parameter overlay: The toast overlay.
|
||||
BIN
Icons/Demo.png
BIN
Icons/Demo.png
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
40
README.md
40
README.md
@ -86,25 +86,27 @@ If you want to use _Adwaita_ in a project, but there are widgets missing, open a
|
||||
|
||||
### View Modifiers
|
||||
|
||||
| Syntax | Description |
|
||||
| ---------------------------- | --------------------------------------------------------------------------------------- |
|
||||
| `inspect(_:)` | Edit the underlying [Libadwaita][10] widget. |
|
||||
| `padding(_:_:)` | Add empty space around a view. |
|
||||
| `hexpand(_:)` | Enable or disable the horizontal expansion of a view. |
|
||||
| `vexpand(_:)` | Enable or disable the vertical expansion of a view. |
|
||||
| `halign(_:)` | Set the horizontal alignment of a view. |
|
||||
| `valign(_:)` | Set the vertical alignment of a view. |
|
||||
| `frame(minWidth:minHeight:)` | Set the view’s minimal width or height. |
|
||||
| `frame(maxSize:)` | Set the view’s maximal size. |
|
||||
| `transition(_:)` | Assign a transition with the view that is used if it is a direct child of an EitherView.|
|
||||
| `onUpdate(_:)` | Run a function every time a view gets updated. |
|
||||
| `navigationTitle(_:)` | Add a title that is used if the view is a direct child of a NavigationView. |
|
||||
| `style(_:)` | Add a style class to the view. |
|
||||
| `onAppear(_:)` | Run when the view is rendered for the first time. |
|
||||
| `topToolbar(visible:_:)` | Add a native toolbar to the view. Normally, it contains a HeaderBar. |
|
||||
| `bottomToolbar(visible:_:)` | Add a native bottom toolbar to the view. |
|
||||
| `modifyContent(_:modify:)` | Replace all occurrences of a certain view type with another view. |
|
||||
| `stopModifiers()` | Ignore all the `modifyContent(_:modify:)` modifiers from higher above in the view tree. |
|
||||
| Syntax | Description |
|
||||
| --------------------------------- | --------------------------------------------------------------------------------------- |
|
||||
| `inspect(_:)` | Edit the underlying [Libadwaita][10] widget. |
|
||||
| `padding(_:_:)` | Add empty space around a view. |
|
||||
| `hexpand(_:)` | Enable or disable the horizontal expansion of a view. |
|
||||
| `vexpand(_:)` | Enable or disable the vertical expansion of a view. |
|
||||
| `halign(_:)` | Set the horizontal alignment of a view. |
|
||||
| `valign(_:)` | Set the vertical alignment of a view. |
|
||||
| `frame(minWidth:minHeight:)` | Set the view’s minimal width or height. |
|
||||
| `frame(maxSize:)` | Set the view’s maximal size. |
|
||||
| `transition(_:)` | Assign a transition with the view that is used if it is a direct child of an EitherView.|
|
||||
| `onUpdate(_:)` | Run a function every time a view gets updated. |
|
||||
| `navigationTitle(_:)` | Add a title that is used if the view is a direct child of a NavigationView. |
|
||||
| `style(_:)` | Add a style class to the view. |
|
||||
| `onAppear(_:)` | Run when the view is rendered for the first time. |
|
||||
| `topToolbar(visible:_:)` | Add a native toolbar to the view. Normally, it contains a HeaderBar. |
|
||||
| `bottomToolbar(visible:_:)` | Add a native bottom toolbar to the view. |
|
||||
| `modifyContent(_:modify:)` | Replace all occurrences of a certain view type with another view. |
|
||||
| `stopModifiers()` | Ignore all the `modifyContent(_:modify:)` modifiers from higher above in the view tree. |
|
||||
| `toast(_:signal:)` | Show a toast on top of the view whenever the signal gets activated. |
|
||||
| `toast(_:signal:button:handler:)` | Show a toast with a button on top of the view whenever the signal gets activated. |
|
||||
|
||||
### `Button` Modifiers
|
||||
| Syntax | Description |
|
||||
|
||||
26
Sources/Adwaita/Model/Data Flow/Signal.swift
Normal file
26
Sources/Adwaita/Model/Data Flow/Signal.swift
Normal file
@ -0,0 +1,26 @@
|
||||
//
|
||||
// Signal.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by david-swift on 30.11.23.
|
||||
//
|
||||
|
||||
/// A type that signalizes an action.
|
||||
public struct Signal {
|
||||
|
||||
/// An action is signalized by toggling a boolean to `true` and back to `false`.
|
||||
@State var boolean = false
|
||||
|
||||
/// Whether the action has caused an update.
|
||||
public var update: Bool { boolean }
|
||||
|
||||
/// Initialize a signal.
|
||||
public init() { }
|
||||
|
||||
/// Activate a signal.
|
||||
public func signal() {
|
||||
boolean = true
|
||||
boolean = false
|
||||
}
|
||||
|
||||
}
|
||||
83
Sources/Adwaita/View/Modifiers/ToastOverlay.swift
Normal file
83
Sources/Adwaita/View/Modifiers/ToastOverlay.swift
Normal file
@ -0,0 +1,83 @@
|
||||
//
|
||||
// ToastOverlay.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by david-swift on 30.11.23.
|
||||
//
|
||||
|
||||
import Libadwaita
|
||||
|
||||
/// A wrapper around a view presenting toasts.
|
||||
struct ToastOverlay: Widget {
|
||||
|
||||
/// The signal for showing the toast./// Present a toast when the signal gets activated.
|
||||
var signal: Signal
|
||||
/// The child view.
|
||||
var child: View
|
||||
/// The title of the toast.
|
||||
var title: String
|
||||
/// Information about the button if available (label and handler).
|
||||
var button: (String, () -> Void)?
|
||||
|
||||
/// Get the overlay's view storage.
|
||||
/// - Parameter modifiers: The view modifiers.
|
||||
/// - Returns: The view storage.
|
||||
func container(modifiers: [(View) -> View]) -> ViewStorage {
|
||||
let contentStorage = child.widget(modifiers: modifiers).storage(modifiers: modifiers)
|
||||
let overlay = Libadwaita.ToastOverlay(contentStorage.view)
|
||||
setVisibility(overlay)
|
||||
return .init(overlay, content: [.mainContent: [contentStorage]])
|
||||
}
|
||||
|
||||
/// Update the overlay's view storage.
|
||||
/// - Parameters:
|
||||
/// - storage: The view storage.
|
||||
/// - modifiers: The view modifiers.
|
||||
func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
|
||||
if let overlay = storage.view as? Libadwaita.ToastOverlay {
|
||||
setVisibility(overlay)
|
||||
}
|
||||
if let storage = storage.content[.mainContent]?.first {
|
||||
child.widget(modifiers: modifiers).update(storage, modifiers: modifiers)
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a toast if the signal is active.
|
||||
/// - Parameter overlay: The toast overlay.
|
||||
func setVisibility(_ overlay: Libadwaita.ToastOverlay) {
|
||||
if signal.update {
|
||||
let toast = Toast(title)
|
||||
if let button {
|
||||
_ = toast
|
||||
.buttonLabel(button.0)
|
||||
.buttonHandler(button.1)
|
||||
}
|
||||
overlay.addToast(toast)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension View {
|
||||
|
||||
/// Present a toast when the signal gets activated.
|
||||
/// - Parameters:
|
||||
/// - title: The title of the toast.
|
||||
/// - signal: The signal which activates the presentation of a toast.
|
||||
/// - Returns: A view.
|
||||
public func toast(_ title: String, signal: Signal) -> View {
|
||||
ToastOverlay(signal: signal, child: self, title: title)
|
||||
}
|
||||
|
||||
/// Present a toast with a button when the signal gets activated.
|
||||
/// - Parameters:
|
||||
/// - title: The title of the toast.
|
||||
/// - signal: The signal which activates the presentation of a toast.
|
||||
/// - button: The button's label.
|
||||
/// - handler: The handler for the button.
|
||||
/// - Returns: A view.
|
||||
public func toast(_ title: String, signal: Signal, button: String, handler: @escaping () -> Void) -> View {
|
||||
ToastOverlay(signal: signal, child: self, title: title, button: (button, handler))
|
||||
}
|
||||
|
||||
}
|
||||
@ -46,7 +46,8 @@ struct Demo: App {
|
||||
|
||||
struct DemoContent: View {
|
||||
|
||||
@State private var selection: Page = .transition
|
||||
@State private var selection: Page = .welcome
|
||||
@State private var toast: Signal = .init()
|
||||
var window: GTUIApplicationWindow
|
||||
var app: GTUIApp!
|
||||
|
||||
@ -87,11 +88,12 @@ struct Demo: App {
|
||||
icon: selection.icon,
|
||||
description: selection.description
|
||||
) {
|
||||
selection.view(app: app)
|
||||
selection.view(app: app, toast: toast)
|
||||
}
|
||||
.topToolbar {
|
||||
HeaderBar.empty()
|
||||
}
|
||||
.toast("This is a toast!", signal: toast)
|
||||
}
|
||||
.onAppear {
|
||||
window.setDefaultSize(width: 650, height: 450)
|
||||
|
||||
@ -19,6 +19,7 @@ enum Page: String, Identifiable, CaseIterable {
|
||||
case transition
|
||||
case dice
|
||||
case overlayWindow
|
||||
case toast
|
||||
|
||||
var id: Self {
|
||||
self
|
||||
@ -36,7 +37,7 @@ enum Page: String, Identifiable, CaseIterable {
|
||||
var icon: Libadwaita.Icon? {
|
||||
switch self {
|
||||
case .welcome:
|
||||
return .default(icon: .gnomeAdwaita1Demo)
|
||||
return .default(icon: .emojiNature)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
@ -58,11 +59,13 @@ enum Page: String, Identifiable, CaseIterable {
|
||||
return "Roll the dice."
|
||||
case .overlayWindow:
|
||||
return "A window on top of another window."
|
||||
case .toast:
|
||||
return "Show a notification inside of your app."
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func view(app: GTUIApp!) -> Body {
|
||||
func view(app: GTUIApp!, toast: Signal) -> Body {
|
||||
switch self {
|
||||
case .welcome:
|
||||
[]
|
||||
@ -78,6 +81,8 @@ enum Page: String, Identifiable, CaseIterable {
|
||||
DiceDemo()
|
||||
case .overlayWindow:
|
||||
OverlayWindowDemo(app: app)
|
||||
case .toast:
|
||||
ToastDemo(toast: toast)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
28
Tests/ToastDemo.swift
Normal file
28
Tests/ToastDemo.swift
Normal file
@ -0,0 +1,28 @@
|
||||
//
|
||||
// ToastDemo.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by david-swift on 30.11.23.
|
||||
//
|
||||
|
||||
// swiftlint:disable missing_docs
|
||||
|
||||
import Adwaita
|
||||
|
||||
struct ToastDemo: View {
|
||||
|
||||
var toast: Signal
|
||||
|
||||
var view: Body {
|
||||
VStack {
|
||||
Button("Add Toast") {
|
||||
toast.signal()
|
||||
}
|
||||
.style("suggested-action")
|
||||
.frame(maxSize: 100)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// swiftlint:enable missing_docs
|
||||
Loading…
x
Reference in New Issue
Block a user