Add support for AdwViewSwitcher
This commit is contained in:
parent
03d259811b
commit
e94885f48f
@ -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
|
||||
|
||||
19
Documentation/Reference/protocols/ViewSwitcherOption.md
Normal file
19
Documentation/Reference/protocols/ViewSwitcherOption.md
Normal 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.
|
||||
46
Documentation/Reference/structs/ViewSwitcher.md
Normal file
46
Documentation/Reference/structs/ViewSwitcher.md
Normal 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.
|
||||
83
Sources/Adwaita/View/ViewSwitcher.swift
Normal file
83
Sources/Adwaita/View/ViewSwitcher.swift
Normal 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)
|
||||
|
||||
}
|
||||
@ -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")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
}
|
||||
|
||||
|
||||
101
Tests/ViewSwitcherDemo.swift
Normal file
101
Tests/ViewSwitcherDemo.swift
Normal 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
|
||||
@ -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 |
|
||||
| -------------------- | ----------------------------------------------------------------- | ---------------------- |
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user