From 36e61255f86125c1a1e61084d90b7fc4b60a66da Mon Sep 17 00:00:00 2001 From: david-swift Date: Thu, 30 Nov 2023 21:14:45 +0100 Subject: [PATCH] Add support for toasts Add the new concept of signals --- Documentation/Reference/README.md | 3 + Documentation/Reference/extensions/View.md | 24 +++++ .../Reference/structs/AppearObserver.md | 28 ++++++ Documentation/Reference/structs/Signal.md | 23 +++++ .../Reference/structs/ToastOverlay.md | 41 +++++++++ Icons/Demo.png | Bin 24046 -> 24856 bytes README.md | 40 +++++---- Sources/Adwaita/Model/Data Flow/Signal.swift | 26 ++++++ .../Adwaita/View/Modifiers/ToastOverlay.swift | 83 ++++++++++++++++++ Tests/Demo.swift | 6 +- Tests/Page.swift | 9 +- Tests/ToastDemo.swift | 28 ++++++ 12 files changed, 288 insertions(+), 23 deletions(-) create mode 100644 Documentation/Reference/structs/AppearObserver.md create mode 100644 Documentation/Reference/structs/Signal.md create mode 100644 Documentation/Reference/structs/ToastOverlay.md create mode 100644 Sources/Adwaita/Model/Data Flow/Signal.swift create mode 100644 Sources/Adwaita/View/Modifiers/ToastOverlay.swift create mode 100644 Tests/ToastDemo.swift diff --git a/Documentation/Reference/README.md b/Documentation/Reference/README.md index bf5a34c..fa93be1 100644 --- a/Documentation/Reference/README.md +++ b/Documentation/Reference/README.md @@ -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) diff --git a/Documentation/Reference/extensions/View.md b/Documentation/Reference/extensions/View.md index 3322c3e..6d2be92 100644 --- a/Documentation/Reference/extensions/View.md +++ b/Documentation/Reference/extensions/View.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. diff --git a/Documentation/Reference/structs/AppearObserver.md b/Documentation/Reference/structs/AppearObserver.md new file mode 100644 index 0000000..5c9b85f --- /dev/null +++ b/Documentation/Reference/structs/AppearObserver.md @@ -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. diff --git a/Documentation/Reference/structs/Signal.md b/Documentation/Reference/structs/Signal.md new file mode 100644 index 0000000..cb4a10d --- /dev/null +++ b/Documentation/Reference/structs/Signal.md @@ -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. diff --git a/Documentation/Reference/structs/ToastOverlay.md b/Documentation/Reference/structs/ToastOverlay.md new file mode 100644 index 0000000..13161cf --- /dev/null +++ b/Documentation/Reference/structs/ToastOverlay.md @@ -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. diff --git a/Icons/Demo.png b/Icons/Demo.png index 77ac2c2fddb20990083fcd9941f53c8b8dc00cf0..b3f1a90baf2fb6d866f9d727414802808bcfc369 100644 GIT binary patch literal 24856 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 L`njxgN@xNA5}ouV diff --git a/README.md b/README.md index 6470205..8c7526f 100644 --- a/README.md +++ b/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 | diff --git a/Sources/Adwaita/Model/Data Flow/Signal.swift b/Sources/Adwaita/Model/Data Flow/Signal.swift new file mode 100644 index 0000000..ebcc2da --- /dev/null +++ b/Sources/Adwaita/Model/Data Flow/Signal.swift @@ -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 + } + +} diff --git a/Sources/Adwaita/View/Modifiers/ToastOverlay.swift b/Sources/Adwaita/View/Modifiers/ToastOverlay.swift new file mode 100644 index 0000000..5266519 --- /dev/null +++ b/Sources/Adwaita/View/Modifiers/ToastOverlay.swift @@ -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)) + } + +} diff --git a/Tests/Demo.swift b/Tests/Demo.swift index b0b3142..8346fab 100644 --- a/Tests/Demo.swift +++ b/Tests/Demo.swift @@ -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) diff --git a/Tests/Page.swift b/Tests/Page.swift index 0bbd06b..86aa7c6 100644 --- a/Tests/Page.swift +++ b/Tests/Page.swift @@ -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) } } diff --git a/Tests/ToastDemo.swift b/Tests/ToastDemo.swift new file mode 100644 index 0000000..12ce935 --- /dev/null +++ b/Tests/ToastDemo.swift @@ -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