forked from aparoksha/adwaita-swift
Add support for toasts
Add the new concept of signals
This commit is contained in:
parent
5ab9387317
commit
36e61255f8
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
## Structs
|
## Structs
|
||||||
|
|
||||||
|
- [AppearObserver](structs/AppearObserver.md)
|
||||||
- [Binding](structs/Binding.md)
|
- [Binding](structs/Binding.md)
|
||||||
- [Button](structs/Button.md)
|
- [Button](structs/Button.md)
|
||||||
- [Clamp](structs/Clamp.md)
|
- [Clamp](structs/Clamp.md)
|
||||||
@ -28,11 +29,13 @@
|
|||||||
- [ModifierStopper](structs/ModifierStopper.md)
|
- [ModifierStopper](structs/ModifierStopper.md)
|
||||||
- [NavigationSplitView](structs/NavigationSplitView.md)
|
- [NavigationSplitView](structs/NavigationSplitView.md)
|
||||||
- [ScrollView](structs/ScrollView.md)
|
- [ScrollView](structs/ScrollView.md)
|
||||||
|
- [Signal](structs/Signal.md)
|
||||||
- [State](structs/State.md)
|
- [State](structs/State.md)
|
||||||
- [StateWrapper](structs/StateWrapper.md)
|
- [StateWrapper](structs/StateWrapper.md)
|
||||||
- [StatusPage](structs/StatusPage.md)
|
- [StatusPage](structs/StatusPage.md)
|
||||||
- [Submenu](structs/Submenu.md)
|
- [Submenu](structs/Submenu.md)
|
||||||
- [Text](structs/Text.md)
|
- [Text](structs/Text.md)
|
||||||
|
- [ToastOverlay](structs/ToastOverlay.md)
|
||||||
- [ToolbarView](structs/ToolbarView.md)
|
- [ToolbarView](structs/ToolbarView.md)
|
||||||
- [VStack](structs/VStack.md)
|
- [VStack](structs/VStack.md)
|
||||||
- [Window](structs/Window.md)
|
- [Window](structs/Window.md)
|
||||||
|
|||||||
@ -24,6 +24,12 @@ Get a storage.
|
|||||||
|
|
||||||
### `getModified(modifiers:)`
|
### `getModified(modifiers:)`
|
||||||
|
|
||||||
|
### `onAppear(_:)`
|
||||||
|
|
||||||
|
Run a function when the view appears for the first time.
|
||||||
|
- Parameter closure: The function.
|
||||||
|
- Returns: A view.
|
||||||
|
|
||||||
### `frame(maxSize:)`
|
### `frame(maxSize:)`
|
||||||
|
|
||||||
Set the view's maximal size.
|
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.
|
Remove all of the content modifiers for the wrapped views.
|
||||||
- Returns: A view.
|
- 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:_:)`
|
### `topToolbar(visible:_:)`
|
||||||
|
|
||||||
Add a top toolbar to the view.
|
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
|
### View Modifiers
|
||||||
|
|
||||||
| Syntax | Description |
|
| Syntax | Description |
|
||||||
| ---------------------------- | --------------------------------------------------------------------------------------- |
|
| --------------------------------- | --------------------------------------------------------------------------------------- |
|
||||||
| `inspect(_:)` | Edit the underlying [Libadwaita][10] widget. |
|
| `inspect(_:)` | Edit the underlying [Libadwaita][10] widget. |
|
||||||
| `padding(_:_:)` | Add empty space around a view. |
|
| `padding(_:_:)` | Add empty space around a view. |
|
||||||
| `hexpand(_:)` | Enable or disable the horizontal expansion of a view. |
|
| `hexpand(_:)` | Enable or disable the horizontal expansion of a view. |
|
||||||
| `vexpand(_:)` | Enable or disable the vertical expansion of a view. |
|
| `vexpand(_:)` | Enable or disable the vertical expansion of a view. |
|
||||||
| `halign(_:)` | Set the horizontal alignment of a view. |
|
| `halign(_:)` | Set the horizontal alignment of a view. |
|
||||||
| `valign(_:)` | Set the vertical alignment of a view. |
|
| `valign(_:)` | Set the vertical alignment of a view. |
|
||||||
| `frame(minWidth:minHeight:)` | Set the view’s minimal width or height. |
|
| `frame(minWidth:minHeight:)` | Set the view’s minimal width or height. |
|
||||||
| `frame(maxSize:)` | Set the view’s maximal size. |
|
| `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.|
|
| `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. |
|
| `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. |
|
| `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. |
|
| `style(_:)` | Add a style class to the view. |
|
||||||
| `onAppear(_:)` | Run when the view is rendered for the first time. |
|
| `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. |
|
| `topToolbar(visible:_:)` | Add a native toolbar to the view. Normally, it contains a HeaderBar. |
|
||||||
| `bottomToolbar(visible:_:)` | Add a native bottom toolbar to the view. |
|
| `bottomToolbar(visible:_:)` | Add a native bottom toolbar to the view. |
|
||||||
| `modifyContent(_:modify:)` | Replace all occurrences of a certain view type with another 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. |
|
| `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
|
### `Button` Modifiers
|
||||||
| Syntax | Description |
|
| 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 {
|
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 window: GTUIApplicationWindow
|
||||||
var app: GTUIApp!
|
var app: GTUIApp!
|
||||||
|
|
||||||
@ -87,11 +88,12 @@ struct Demo: App {
|
|||||||
icon: selection.icon,
|
icon: selection.icon,
|
||||||
description: selection.description
|
description: selection.description
|
||||||
) {
|
) {
|
||||||
selection.view(app: app)
|
selection.view(app: app, toast: toast)
|
||||||
}
|
}
|
||||||
.topToolbar {
|
.topToolbar {
|
||||||
HeaderBar.empty()
|
HeaderBar.empty()
|
||||||
}
|
}
|
||||||
|
.toast("This is a toast!", signal: toast)
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
window.setDefaultSize(width: 650, height: 450)
|
window.setDefaultSize(width: 650, height: 450)
|
||||||
|
|||||||
@ -19,6 +19,7 @@ enum Page: String, Identifiable, CaseIterable {
|
|||||||
case transition
|
case transition
|
||||||
case dice
|
case dice
|
||||||
case overlayWindow
|
case overlayWindow
|
||||||
|
case toast
|
||||||
|
|
||||||
var id: Self {
|
var id: Self {
|
||||||
self
|
self
|
||||||
@ -36,7 +37,7 @@ enum Page: String, Identifiable, CaseIterable {
|
|||||||
var icon: Libadwaita.Icon? {
|
var icon: Libadwaita.Icon? {
|
||||||
switch self {
|
switch self {
|
||||||
case .welcome:
|
case .welcome:
|
||||||
return .default(icon: .gnomeAdwaita1Demo)
|
return .default(icon: .emojiNature)
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -58,11 +59,13 @@ enum Page: String, Identifiable, CaseIterable {
|
|||||||
return "Roll the dice."
|
return "Roll the dice."
|
||||||
case .overlayWindow:
|
case .overlayWindow:
|
||||||
return "A window on top of another window."
|
return "A window on top of another window."
|
||||||
|
case .toast:
|
||||||
|
return "Show a notification inside of your app."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
func view(app: GTUIApp!) -> Body {
|
func view(app: GTUIApp!, toast: Signal) -> Body {
|
||||||
switch self {
|
switch self {
|
||||||
case .welcome:
|
case .welcome:
|
||||||
[]
|
[]
|
||||||
@ -78,6 +81,8 @@ enum Page: String, Identifiable, CaseIterable {
|
|||||||
DiceDemo()
|
DiceDemo()
|
||||||
case .overlayWindow:
|
case .overlayWindow:
|
||||||
OverlayWindowDemo(app: app)
|
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