Add support for AdwViewSwitcher

This commit is contained in:
david-swift 2024-01-03 15:07:36 +01:00
parent 03d259811b
commit e94885f48f
8 changed files with 273 additions and 0 deletions

View File

@ -7,6 +7,7 @@
- [MenuItemGroup](protocols/MenuItemGroup.md)
- [StateProtocol](protocols/StateProtocol.md)
- [View](protocols/View.md)
- [ViewSwitcherOption](protocols/ViewSwitcherOption.md)
- [Widget](protocols/Widget.md)
- [WindowScene](protocols/WindowScene.md)
- [WindowSceneGroup](protocols/WindowSceneGroup.md)
@ -45,6 +46,7 @@
- [ToolbarView](structs/ToolbarView.md)
- [VStack](structs/VStack.md)
- [ViewStack](structs/ViewStack.md)
- [ViewSwitcher](structs/ViewSwitcher.md)
- [Window](structs/Window.md)
## Classes

View File

@ -0,0 +1,19 @@
**PROTOCOL**
# `ViewSwitcherOption`
The protocol an element type for view switcher has to conform to.
## Properties
### `title`
The title displayed in the switcher and used for identification.
### `icon`
A symbolic representation in the view switcher.
## Methods
### `init(title:)`
Get the element from the title.

View File

@ -0,0 +1,46 @@
**STRUCT**
# `ViewSwitcher`
A picker used for indicating multiple views.
It normally controls a `ViewStack` (e.g. via `switch` statements).
## Properties
### `selection`
The selected element.
### `wide`
Whether the wide style is used, that means the icons and titles are on the same line.
## Methods
### `init(selection:)`
Initialize a view switcher.
- Parameter selection: The selected element.
### `container(modifiers:)`
Get a view switcher's view storage.
- Parameter modifiers: Modify views before being updated.
- Returns: The view storage.
### `update(_:modifiers:)`
Update a view switcher's view storage.
- Parameters:
- storage: The view storage.
- modifiers: Modify views before being updated.
### `updateSwitcher(switcher:)`
Update a view switcher's style and selection.
- Parameter switcher: The view switcher.
### `wideDesign(_:)`
Set whether to use the wide design.
- Parameter wide: Whether to use the wide design.
- Returns: The view switcher.

View File

@ -0,0 +1,83 @@
//
// ViewSwitcher.swift
// Adwaita
//
// Created by david-swift on 03.01.24.
//
import Libadwaita
/// A picker used for indicating multiple views.
///
/// It normally controls a `ViewStack` (e.g. via `switch` statements).
public struct ViewSwitcher<Element>: Widget where Element: ViewSwitcherOption {
/// The selected element.
@Binding var selection: Element
/// Whether the wide style is used, that means the icons and titles are on the same line.
var wide = false
/// Initialize a view switcher.
/// - Parameter selection: The selected element.
public init(selection: Binding<Element>) {
self._selection = selection
}
/// Get a view switcher's view storage.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let switcher = Libadwaita.ViewSwitcher()
for option in Element.allCases {
_ = switcher.addOption(title: option.title, icon: option.icon)
}
_ = switcher.onSelect {
let selection = switcher.getSelection()
if let element = Element(title: selection) {
self.selection = element
}
}
updateSwitcher(switcher: switcher)
return .init(switcher)
}
/// Update a view switcher's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let switcher = storage.view as? Libadwaita.ViewSwitcher {
updateSwitcher(switcher: switcher)
}
}
/// Update a view switcher's style and selection.
/// - Parameter switcher: The view switcher.
func updateSwitcher(switcher: Libadwaita.ViewSwitcher) {
_ = switcher.wideDesign(wide)
switcher.select(title: selection.title)
}
/// Set whether to use the wide design.
/// - Parameter wide: Whether to use the wide design.
/// - Returns: The view switcher.
public func wideDesign(_ wide: Bool = true) -> Self {
var newSelf = self
newSelf.wide = wide
return newSelf
}
}
/// The protocol an element type for view switcher has to conform to.
public protocol ViewSwitcherOption: CaseIterable {
/// The title displayed in the switcher and used for identification.
var title: String { get }
/// A symbolic representation in the view switcher.
var icon: Icon { get }
/// Get the element from the title.
init?(title: String)
}

View File

@ -49,6 +49,13 @@ struct Demo: App {
.closeShortcut()
.defaultSize(width: 400, height: 250)
.title("Toolbar Demo")
Window(id: "switcher-demo", open: 0) { _ in
ViewSwitcherDemo.WindowContent()
}
.closeShortcut()
.defaultSize(width: 600, height: 400)
.resizable(false)
.title("View Switcher Demo")
}
}

View File

@ -22,6 +22,7 @@ enum Page: String, Identifiable, CaseIterable, Codable {
case toast
case list
case carousel
case viewSwitcher
var id: Self {
self
@ -31,6 +32,8 @@ enum Page: String, Identifiable, CaseIterable, Codable {
switch self {
case .overlayWindow:
return "Overlay Window"
case .viewSwitcher:
return "View Switcher"
default:
return rawValue.capitalized
}
@ -67,9 +70,12 @@ enum Page: String, Identifiable, CaseIterable, Codable {
return "Organize content in multiple rows."
case .carousel:
return "Scroll horizontally on a touchpad or touchscreen, or scroll down on your mouse wheel."
case .viewSwitcher:
return "Switch the window's view."
}
}
// swiftlint:disable cyclomatic_complexity
@ViewBuilder
func view(app: GTUIApp!, window: GTUIApplicationWindow, toast: Signal) -> Body {
switch self {
@ -93,8 +99,11 @@ enum Page: String, Identifiable, CaseIterable, Codable {
ListDemo()
case .carousel:
CarouselDemo()
case .viewSwitcher:
ViewSwitcherDemo(app: app)
}
}
// swiftlint:enable cyclomatic_complexity
}

View File

@ -0,0 +1,101 @@
//
// ToolbarDemo.swift
// Adwaita
//
// Created by david-swift on 03.01.24.
//
// swiftlint:disable missing_docs
import Adwaita
import Libadwaita
struct ViewSwitcherDemo: View {
var app: GTUIApp
var view: Body {
VStack {
Button("View Demo") {
app.showWindow("switcher-demo")
}
.style("suggested-action")
.frame(maxSize: 100)
}
}
struct WindowContent: View {
@State private var selection: ViewSwitcherView = .albums
@State private var bottom = false
var view: Body {
VStack {
Text(selection.title)
.padding()
HStack {
Button(bottom ? "Show Top Bar" : "Show Bottom Bar") {
bottom.toggle()
}
}
.halign(.center)
}
.valign(.center)
.topToolbar {
if bottom {
HeaderBar
.empty()
} else {
toolbar
}
}
.bottomToolbar(visible: bottom) {
toolbar
}
}
var toolbar: View {
HeaderBar(titleButtons: !bottom) { } end: { }
.headerBarTitle {
ViewSwitcher(selection: $selection)
.wideDesign(!bottom)
}
}
}
enum ViewSwitcherView: String, ViewSwitcherOption {
case albums
case artists
case songs
case playlists
var title: String {
rawValue.capitalized
}
var icon: Icon {
.default(icon: {
switch self {
case .albums:
return .mediaOpticalCdAudio
case .artists:
return .avatarDefault
case .songs:
return .emblemMusic
case .playlists:
return .viewList
}
}())
}
init?(title: String) {
self.init(rawValue: title.lowercased())
}
}
}
// swiftlint:enable missing_docs

View File

@ -19,6 +19,7 @@ This is an overview of the available widgets and other components in _Adwaita_.
| StatusPage | A page with an icon, title, and optionally description and widget. | AdwStatusPage |
| Container | Supports any widget conforming to `Libadwaita.InsertableContainer`. | Multiple widgets |
| Carousel | A paginated scrolling widget. | AdwCarousel |
| ViewSwitcher | A control for switching between different views. | AdwViewSwitcher |
| StateWrapper | A wrapper not affecting the UI which stores state information. | - |
### View Modifiers
@ -67,6 +68,11 @@ This is an overview of the available widgets and other components in _Adwaita_.
| ---------------------------- | --------------------------------------------------------------------------------------- |
| `trailingSidebar(_:)` | Whether the sidebar is trailing to the content view. |
### `ViewSwitcher` Modifiers
| Syntax | Description |
| ---------------------------- | --------------------------------------------------------------------------------------- |
| `wideDesign(_:)` | Whether the wide view switcher design is used. |
### Window Types
| Name | Description | Widget |
| -------------------- | ----------------------------------------------------------------- | ---------------------- |