Add support for keypaths where sensible #74
This commit is contained in:
parent
c08a9dc3bd
commit
2072c16040
@ -17,27 +17,40 @@ extension DropDown {
|
||||
|
||||
/// Initialize a combo row.
|
||||
/// - Parameters:
|
||||
/// - title: The row's title.
|
||||
/// - selection: The selected value.
|
||||
/// - values: The available values.
|
||||
public init<Element>(
|
||||
selection: Binding<Element.ID>,
|
||||
values: [Element]
|
||||
) where Element: Identifiable, Element: CustomStringConvertible {
|
||||
self.init(selection: selection, values: values, id: \.id, description: \.description)
|
||||
}
|
||||
|
||||
/// Initialize a combo row.
|
||||
/// - Parameters:
|
||||
/// - title: The row's title.
|
||||
/// - selection: The selected value.
|
||||
/// - values: The available values.
|
||||
public init<Element, Identifier>(
|
||||
selection: Binding<Identifier>,
|
||||
values: [Element],
|
||||
id: KeyPath<Element, Identifier>,
|
||||
description: KeyPath<Element, String>
|
||||
) where Identifier: Equatable {
|
||||
self.init()
|
||||
self = self.selected(.init {
|
||||
.init(values.firstIndex { $0.id == selection.wrappedValue } ?? 0)
|
||||
.init(values.firstIndex { $0[keyPath: id] == selection.wrappedValue } ?? 0)
|
||||
} set: { index in
|
||||
if let id = values[safe: .init(index)]?.id {
|
||||
if let id = values[safe: .init(index)]?[keyPath: id] {
|
||||
selection.wrappedValue = id
|
||||
}
|
||||
})
|
||||
appearFunctions.append { storage, _ in
|
||||
storage.fields[Self.stringList] = gtk_drop_down_get_model(storage.opaquePointer)
|
||||
Self.updateContent(storage: storage, values: values, element: Element.self)
|
||||
Self.updateContent(storage: storage, values: values, id: id, description: description)
|
||||
}
|
||||
updateFunctions.append { storage, _, _ in
|
||||
Self.updateContent(storage: storage, values: values, element: Element.self)
|
||||
Self.updateContent(storage: storage, values: values, id: id, description: description)
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,20 +58,23 @@ extension DropDown {
|
||||
/// - Parameters:
|
||||
/// - storage: The view storage.
|
||||
/// - values: The elements.
|
||||
/// - element: The type of the elements.
|
||||
static func updateContent<Element>(
|
||||
/// - id: The keypath to the id.
|
||||
/// - description: The keypath to the description.
|
||||
static func updateContent<Element, Identifier>(
|
||||
storage: ViewStorage,
|
||||
values: [Element],
|
||||
element: Element.Type
|
||||
) where Element: Identifiable, Element: CustomStringConvertible {
|
||||
id: KeyPath<Element, Identifier>,
|
||||
description: KeyPath<Element, String>
|
||||
) where Identifier: Equatable {
|
||||
if let list = storage.fields[Self.stringList] as? OpaquePointer {
|
||||
let old = storage.fields[Self.values] as? [Element] ?? []
|
||||
old.identifiableTransform(
|
||||
old.transform(
|
||||
to: values,
|
||||
id: id,
|
||||
functions: .init { index in
|
||||
gtk_string_list_remove(list, .init(index))
|
||||
} insert: { _, element in
|
||||
gtk_string_list_append(list, element.description)
|
||||
gtk_string_list_append(list, element[keyPath: description])
|
||||
}
|
||||
)
|
||||
storage.fields[Self.values] = values
|
||||
|
||||
@ -17,19 +17,21 @@ extension FlowBox {
|
||||
/// Initialize `FlowBox`.
|
||||
/// - Parameters:
|
||||
/// - elements: The elements.
|
||||
/// - id: The element identifier keypath.
|
||||
/// - selection: The identifier of the selected element. Selection disabled if `nil`.
|
||||
/// - content: The view for an element.
|
||||
public init(
|
||||
_ elements: [Element],
|
||||
selection: Binding<Element.ID>? = nil,
|
||||
id: KeyPath<Element, Identifier>,
|
||||
selection: Binding<Identifier>? = nil,
|
||||
@ViewBuilder content: @escaping (Element) -> Body
|
||||
) {
|
||||
self.init(elements, content: content)
|
||||
let id: (ViewStorage, [Element]) -> Element.ID? = { storage, elements in
|
||||
self.init(elements, id: id, content: content)
|
||||
let getID: (ViewStorage, [Element]) -> Identifier? = { storage, elements in
|
||||
if let child = g_list_nth_data(gtk_flow_box_get_selected_children(storage.opaquePointer), 0) {
|
||||
let element = gtk_flow_box_child_get_child(child.cast())
|
||||
return elements[safe: storage.content[.mainContent]?
|
||||
.firstIndex { $0.opaquePointer?.cast() == element }]?.id
|
||||
.firstIndex { $0.opaquePointer?.cast() == element }]?[keyPath: id]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -37,12 +39,12 @@ extension FlowBox {
|
||||
updateFunctions.append { storage, _, _ in
|
||||
storage.connectSignal(name: "selected_children_changed", id: Self.selectionField) {
|
||||
if let elements = storage.fields[Self.elementsField] as? [Element],
|
||||
let id = id(storage, elements) {
|
||||
let id = getID(storage, elements) {
|
||||
selection.wrappedValue = id
|
||||
}
|
||||
}
|
||||
if selection.wrappedValue != id(storage, elements),
|
||||
let index = elements.firstIndex(where: { $0.id == selection.wrappedValue })?.cInt {
|
||||
if selection.wrappedValue != getID(storage, elements),
|
||||
let index = elements.firstIndex(where: { $0[keyPath: id] == selection.wrappedValue })?.cInt {
|
||||
gtk_flow_box_select_child(
|
||||
storage.opaquePointer,
|
||||
gtk_flow_box_get_child_at_index(storage.opaquePointer, index)
|
||||
@ -57,3 +59,20 @@ extension FlowBox {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension FlowBox where Element: Identifiable, Identifier == Element.ID {
|
||||
|
||||
/// Initialize `FlowBox`.
|
||||
/// - Parameters:
|
||||
/// - elements: The elements.
|
||||
/// - selection: The identifier of the selected element. Selection disabled if `nil`.
|
||||
/// - content: The view for an element.
|
||||
public init(
|
||||
_ elements: [Element],
|
||||
selection: Binding<Element.ID>? = nil,
|
||||
@ViewBuilder content: @escaping (Element) -> Body
|
||||
) {
|
||||
self.init(elements, id: \.id, selection: selection, content: content)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ import CAdw
|
||||
import LevenshteinTransformations
|
||||
|
||||
/// A dynamic list but without a list design in the user interface.
|
||||
public struct ForEach<Element>: AdwaitaWidget where Element: Identifiable {
|
||||
public struct ForEach<Element, Identifier>: AdwaitaWidget where Identifier: Equatable {
|
||||
|
||||
/// The dynamic widget elements.
|
||||
var elements: [Element]
|
||||
@ -19,12 +19,20 @@ public struct ForEach<Element>: AdwaitaWidget where Element: Identifiable {
|
||||
var horizontal: Bool
|
||||
/// Whether the children should all be the same size.
|
||||
var homogeneous: Bool?
|
||||
/// The path to the identifier.
|
||||
var id: KeyPath<Element, Identifier>
|
||||
|
||||
/// Initialize `ForEach`.
|
||||
public init(_ elements: [Element], horizontal: Bool = false, @ViewBuilder content: @escaping (Element) -> Body) {
|
||||
public init(
|
||||
_ elements: [Element],
|
||||
id: KeyPath<Element, Identifier>,
|
||||
horizontal: Bool = false,
|
||||
@ViewBuilder content: @escaping (Element) -> Body
|
||||
) {
|
||||
self.elements = elements
|
||||
self.content = content
|
||||
self.horizontal = horizontal
|
||||
self.id = id
|
||||
}
|
||||
|
||||
/// The view storage.
|
||||
@ -56,8 +64,9 @@ public struct ForEach<Element>: AdwaitaWidget where Element: Identifiable {
|
||||
var contentStorage: [ViewStorage] = storage.content[.mainContent] ?? []
|
||||
let old = storage.fields["element"] as? [Element] ?? []
|
||||
let widget: UnsafeMutablePointer<GtkBox>? = storage.opaquePointer?.cast()
|
||||
old.identifiableTransform(
|
||||
old.transform(
|
||||
to: elements,
|
||||
id: id,
|
||||
functions: .init { index in
|
||||
let child = contentStorage[safe: index]?.opaquePointer
|
||||
gtk_box_remove(widget, child?.cast())
|
||||
@ -105,3 +114,15 @@ public struct ForEach<Element>: AdwaitaWidget where Element: Identifiable {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ForEach where Element: Identifiable, Identifier == Element.ID {
|
||||
|
||||
/// Initialize `ForEach`.
|
||||
public init(_ elements: [Element], horizontal: Bool = false, @ViewBuilder content: @escaping (Element) -> Body) {
|
||||
self.elements = elements
|
||||
self.content = content
|
||||
self.horizontal = horizontal
|
||||
self.id = \.id
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -26,11 +26,26 @@ extension ComboRow {
|
||||
selection: Binding<Element.ID>,
|
||||
values: [Element]
|
||||
) where Element: Identifiable, Element: CustomStringConvertible {
|
||||
self.init(title, selection: selection, values: values, id: \.id, description: \.description)
|
||||
}
|
||||
|
||||
/// Initialize a combo row.
|
||||
/// - Parameters:
|
||||
/// - title: The row's title.
|
||||
/// - selection: The selected value.
|
||||
/// - values: The available values.
|
||||
public init<Element, Identifier>(
|
||||
_ title: String,
|
||||
selection: Binding<Identifier>,
|
||||
values: [Element],
|
||||
id: KeyPath<Element, Identifier>,
|
||||
description: KeyPath<Element, String>
|
||||
) where Identifier: Equatable {
|
||||
self = self.title(title)
|
||||
self = self.selected(.init {
|
||||
.init(values.firstIndex { $0.id == selection.wrappedValue } ?? 0)
|
||||
.init(values.firstIndex { $0[keyPath: id] == selection.wrappedValue } ?? 0)
|
||||
} set: { index in
|
||||
if let id = values[safe: .init(index)]?.id {
|
||||
if let id = values[safe: .init(index)]?[keyPath: id] {
|
||||
selection.wrappedValue = id
|
||||
}
|
||||
})
|
||||
@ -39,34 +54,10 @@ extension ComboRow {
|
||||
storage.fields[Self.stringList] = list
|
||||
adw_combo_row_set_model(storage.opaquePointer?.cast(), list)
|
||||
g_object_unref(list?.cast())
|
||||
Self.updateContent(storage: storage, values: values, element: Element.self)
|
||||
DropDown.updateContent(storage: storage, values: values, id: id, description: description)
|
||||
}
|
||||
updateFunctions.append { storage, _, _ in
|
||||
Self.updateContent(storage: storage, values: values, element: Element.self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Update the combo row's content.
|
||||
/// - Parameters:
|
||||
/// - storage: The view storage.
|
||||
/// - values: The elements.
|
||||
/// - element: The type of the elements.
|
||||
static func updateContent<Element>(
|
||||
storage: ViewStorage,
|
||||
values: [Element],
|
||||
element: Element.Type
|
||||
) where Element: Identifiable, Element: CustomStringConvertible {
|
||||
if let list = storage.fields[Self.stringList] as? OpaquePointer {
|
||||
let old = storage.fields[Self.values] as? [Element] ?? []
|
||||
old.identifiableTransform(
|
||||
to: values,
|
||||
functions: .init { index in
|
||||
gtk_string_list_remove(list, .init(index))
|
||||
} insert: { _, element in
|
||||
gtk_string_list_append(list, element.description)
|
||||
}
|
||||
)
|
||||
storage.fields[Self.values] = values
|
||||
DropDown.updateContent(storage: storage, values: values, id: id, description: description)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// ActionRow.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// AspectFrame.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// Avatar.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// Banner.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// Bin.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// Box.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// Button.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// ButtonContent.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// Carousel.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
@ -19,7 +19,7 @@ import LevenshteinTransformations
|
||||
/// to provide page indicators for `AdwCarousel`.
|
||||
///
|
||||
///
|
||||
public struct Carousel<Element>: AdwaitaWidget where Element: Identifiable {
|
||||
public struct Carousel<Element, Identifier>: AdwaitaWidget where Identifier: Equatable {
|
||||
|
||||
#if exposeGeneratedAppearUpdateFunctions
|
||||
/// Additional update functions for type extensions.
|
||||
@ -70,11 +70,14 @@ public struct Carousel<Element>: AdwaitaWidget where Element: Identifiable {
|
||||
var elements: [Element]
|
||||
/// The dynamic widget content.
|
||||
var content: (Element) -> Body
|
||||
/// The dynamic widget identifier key path.
|
||||
var id: KeyPath<Element, Identifier>
|
||||
|
||||
/// Initialize `Carousel`.
|
||||
public init(_ elements: [Element], @ViewBuilder content: @escaping (Element) -> Body) {
|
||||
public init(_ elements: [Element], id: KeyPath<Element, Identifier>, @ViewBuilder content: @escaping (Element) -> Body) {
|
||||
self.elements = elements
|
||||
self.content = content
|
||||
self.id = id
|
||||
}
|
||||
|
||||
/// The view storage.
|
||||
@ -126,8 +129,9 @@ public struct Carousel<Element>: AdwaitaWidget where Element: Identifiable {
|
||||
|
||||
var contentStorage: [ViewStorage] = storage.content[.mainContent] ?? []
|
||||
let old = storage.fields["element"] as? [Element] ?? []
|
||||
old.identifiableTransform(
|
||||
old.transform(
|
||||
to: elements,
|
||||
id: id,
|
||||
functions: .init { index in
|
||||
adw_carousel_remove(widget, adw_carousel_get_nth_page(widget, UInt(index).cInt))
|
||||
contentStorage.remove(at: index)
|
||||
@ -212,3 +216,14 @@ public struct Carousel<Element>: AdwaitaWidget where Element: Identifiable {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Carousel where Element: Identifiable, Identifier == Element.ID {
|
||||
|
||||
/// Initialize `Carousel`.
|
||||
public init(_ elements: [Element], @ViewBuilder content: @escaping (Element) -> Body) {
|
||||
self.elements = elements
|
||||
self.content = content
|
||||
self.id = \.id
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// CenterBox.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// CheckButton.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// Clamp.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// ComboRow.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// DropDown.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// Entry.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// EntryRow.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// ExpanderRow.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// Fixed.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// FlowBox.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
@ -37,7 +37,7 @@ import LevenshteinTransformations
|
||||
/// Also see `Gtk.ListBox`.
|
||||
///
|
||||
///
|
||||
public struct FlowBox<Element>: AdwaitaWidget where Element: Identifiable {
|
||||
public struct FlowBox<Element, Identifier>: AdwaitaWidget where Identifier: Equatable {
|
||||
|
||||
#if exposeGeneratedAppearUpdateFunctions
|
||||
/// Additional update functions for type extensions.
|
||||
@ -130,11 +130,14 @@ public struct FlowBox<Element>: AdwaitaWidget where Element: Identifiable {
|
||||
var elements: [Element]
|
||||
/// The dynamic widget content.
|
||||
var content: (Element) -> Body
|
||||
/// The dynamic widget identifier key path.
|
||||
var id: KeyPath<Element, Identifier>
|
||||
|
||||
/// Initialize `FlowBox`.
|
||||
init(_ elements: [Element], @ViewBuilder content: @escaping (Element) -> Body) {
|
||||
init(_ elements: [Element], id: KeyPath<Element, Identifier>, @ViewBuilder content: @escaping (Element) -> Body) {
|
||||
self.elements = elements
|
||||
self.content = content
|
||||
self.id = id
|
||||
}
|
||||
|
||||
/// The view storage.
|
||||
@ -216,8 +219,9 @@ public struct FlowBox<Element>: AdwaitaWidget where Element: Identifiable {
|
||||
|
||||
var contentStorage: [ViewStorage] = storage.content[.mainContent] ?? []
|
||||
let old = storage.fields["element"] as? [Element] ?? []
|
||||
old.identifiableTransform(
|
||||
old.transform(
|
||||
to: elements,
|
||||
id: id,
|
||||
functions: .init { index in
|
||||
gtk_flow_box_remove(widget, gtk_flow_box_get_child_at_index(widget, index.cInt)?.cast())
|
||||
contentStorage.remove(at: index)
|
||||
@ -377,3 +381,14 @@ public struct FlowBox<Element>: AdwaitaWidget where Element: Identifiable {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension FlowBox where Element: Identifiable, Identifier == Element.ID {
|
||||
|
||||
/// Initialize `FlowBox`.
|
||||
public init(_ elements: [Element], @ViewBuilder content: @escaping (Element) -> Body) {
|
||||
self.elements = elements
|
||||
self.content = content
|
||||
self.id = \.id
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// HeaderBar.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// Image.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// Label.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// LevelBar.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// LinkButton.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// ListBox.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
@ -34,7 +34,7 @@ import LevenshteinTransformations
|
||||
/// as selected when the user tries to select it.
|
||||
///
|
||||
///
|
||||
public struct ListBox<Element>: AdwaitaWidget where Element: Identifiable {
|
||||
public struct ListBox<Element, Identifier>: AdwaitaWidget where Identifier: Equatable {
|
||||
|
||||
#if exposeGeneratedAppearUpdateFunctions
|
||||
/// Additional update functions for type extensions.
|
||||
@ -107,11 +107,14 @@ public struct ListBox<Element>: AdwaitaWidget where Element: Identifiable {
|
||||
var elements: [Element]
|
||||
/// The dynamic widget content.
|
||||
var content: (Element) -> Body
|
||||
/// The dynamic widget identifier key path.
|
||||
var id: KeyPath<Element, Identifier>
|
||||
|
||||
/// Initialize `ListBox`.
|
||||
public init(_ elements: [Element], @ViewBuilder content: @escaping (Element) -> Body) {
|
||||
public init(_ elements: [Element], id: KeyPath<Element, Identifier>, @ViewBuilder content: @escaping (Element) -> Body) {
|
||||
self.elements = elements
|
||||
self.content = content
|
||||
self.id = id
|
||||
}
|
||||
|
||||
/// The view storage.
|
||||
@ -186,8 +189,9 @@ public struct ListBox<Element>: AdwaitaWidget where Element: Identifiable {
|
||||
|
||||
var contentStorage: [ViewStorage] = storage.content[.mainContent] ?? []
|
||||
let old = storage.fields["element"] as? [Element] ?? []
|
||||
old.identifiableTransform(
|
||||
old.transform(
|
||||
to: elements,
|
||||
id: id,
|
||||
functions: .init { index in
|
||||
gtk_list_box_remove(widget, gtk_list_box_get_row_at_index(widget, index.cInt)?.cast())
|
||||
contentStorage.remove(at: index)
|
||||
@ -320,3 +324,14 @@ public struct ListBox<Element>: AdwaitaWidget where Element: Identifiable {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ListBox where Element: Identifiable, Identifier == Element.ID {
|
||||
|
||||
/// Initialize `ListBox`.
|
||||
public init(_ elements: [Element], @ViewBuilder content: @escaping (Element) -> Body) {
|
||||
self.elements = elements
|
||||
self.content = content
|
||||
self.id = \.id
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// Menu.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// NavigationView.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// Overlay.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// OverlaySplitView.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// PasswordEntryRow.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// Picture.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// Popover.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// PreferencesGroup.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// PreferencesPage.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// PreferencesRow.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// ProgressBar.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// ScrolledWindow.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SearchBar.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SearchEntry.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// Separator.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SpinRow.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// Spinner.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SplitButton.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// StatusPage.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SwitchRow.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// ToastOverlay.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// ToggleButton.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// ToggleGroup.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// ToolbarView.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// WindowTitle.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by auto-generation on 03.02.26.
|
||||
// Created by auto-generation on 04.02.26.
|
||||
//
|
||||
|
||||
import CAdw
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
//
|
||||
// List+.swift
|
||||
// Adwaita
|
||||
//
|
||||
// Created by david-swift on 16.10.24.
|
||||
//
|
||||
|
||||
extension List {
|
||||
|
||||
/// Add the "navigation-sidebar" style class.
|
||||
/// - Parameter active: Whether the style is applied.
|
||||
/// - Returns: A view.
|
||||
public func sidebarStyle(_ active: Bool = true) -> AnyView {
|
||||
style("navigation-sidebar", active: active)
|
||||
}
|
||||
|
||||
/// Apply the boxed list style class.
|
||||
/// - Parameter active: Whether the style is applied.
|
||||
/// - Returns: A view.
|
||||
public func boxedList(_ active: Bool = true) -> AnyView {
|
||||
style("boxed-list", active: active)
|
||||
}
|
||||
|
||||
}
|
||||
@ -21,17 +21,19 @@ extension List {
|
||||
/// Initialize `List`.
|
||||
/// - Parameters:
|
||||
/// - elements: The elements.
|
||||
/// - id: The key path to the elements' identifiers.
|
||||
/// - selection: The identifier of the selected element. Selection disabled if `nil`.
|
||||
/// - content: The view for an element.
|
||||
public init(
|
||||
_ elements: [Element],
|
||||
selection: Binding<Element.ID>?,
|
||||
id: KeyPath<Element, Identifier>,
|
||||
selection: Binding<Identifier>?,
|
||||
@ViewBuilder content: @escaping (Element) -> Body
|
||||
) {
|
||||
self.init(elements, content: content)
|
||||
let id: (ViewStorage, [Element]) -> Element.ID? = { storage, elements in
|
||||
self.init(elements, id: id, content: content)
|
||||
let getID: (ViewStorage, [Element]) -> Identifier? = { storage, elements in
|
||||
if let row = gtk_list_box_get_selected_row(storage.opaquePointer) {
|
||||
return elements[safe: .init(gtk_list_box_row_get_index(row))]?.id
|
||||
return elements[safe: .init(gtk_list_box_row_get_index(row))]?[keyPath: id]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -39,13 +41,13 @@ extension List {
|
||||
updateFunctions.append { storage, _, _ in
|
||||
storage.connectSignal(name: "selected_rows_changed", id: Self.selectionField) {
|
||||
if let elements = storage.fields[Self.elementsField] as? [Element],
|
||||
let id = id(storage, elements),
|
||||
let id = getID(storage, elements),
|
||||
selection.wrappedValue != id {
|
||||
selection.wrappedValue = id
|
||||
}
|
||||
}
|
||||
if selection.wrappedValue != id(storage, elements),
|
||||
let index = elements.firstIndex(where: { $0.id == selection.wrappedValue })?.cInt {
|
||||
if selection.wrappedValue != getID(storage, elements),
|
||||
let index = elements.firstIndex(where: { $0[keyPath: id] == selection.wrappedValue })?.cInt {
|
||||
gtk_list_box_select_row(
|
||||
storage.opaquePointer,
|
||||
gtk_list_box_get_row_at_index(storage.opaquePointer, index)
|
||||
@ -59,4 +61,35 @@ extension List {
|
||||
}
|
||||
}
|
||||
|
||||
/// Add the "navigation-sidebar" style class.
|
||||
/// - Parameter active: Whether the style is applied.
|
||||
/// - Returns: A view.
|
||||
public func sidebarStyle(_ active: Bool = true) -> AnyView {
|
||||
style("navigation-sidebar", active: active)
|
||||
}
|
||||
|
||||
/// Apply the boxed list style class.
|
||||
/// - Parameter active: Whether the style is applied.
|
||||
/// - Returns: A view.
|
||||
public func boxedList(_ active: Bool = true) -> AnyView {
|
||||
style("boxed-list", active: active)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension List where Element: Identifiable, Element.ID == Identifier {
|
||||
|
||||
/// Initialize `List`.
|
||||
/// - Parameters:
|
||||
/// - elements: The elements.
|
||||
/// - selection: The identifier of the selected element. Selection disabled if `nil`.
|
||||
/// - content: The view for an element.
|
||||
public init(
|
||||
_ elements: [Element],
|
||||
selection: Binding<Element.ID>?,
|
||||
@ViewBuilder content: @escaping (Element) -> Body
|
||||
) {
|
||||
self.init(elements, id: \.id, selection: selection, content: content)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -23,72 +23,103 @@ extension ToggleGroup {
|
||||
selection: Binding<Element.ID>,
|
||||
values: [Element]
|
||||
) where Element: ToggleGroupItem {
|
||||
self.init(
|
||||
selection: selection,
|
||||
values: values,
|
||||
id: \.id,
|
||||
label: \.id.description,
|
||||
icon: \.icon,
|
||||
showLabel: \.showLabel
|
||||
)
|
||||
}
|
||||
|
||||
/// Initialize a toggle group.
|
||||
/// - Parameters:
|
||||
/// - selection: The selected value.
|
||||
/// - values: The available values.
|
||||
/// - id: The path to the identifier.
|
||||
/// - label: The path to the label.
|
||||
/// - icon: The path to the icon.
|
||||
/// - showLabel: The path to the boolean that defines whether to show an element's label.
|
||||
public init<Element, Identifier>(
|
||||
selection: Binding<Identifier>,
|
||||
values: [Element],
|
||||
id: KeyPath<Element, Identifier>,
|
||||
label: KeyPath<Element, String>,
|
||||
icon: KeyPath<Element, Icon?>? = nil,
|
||||
showLabel: KeyPath<Element, Bool>? = nil
|
||||
) where Identifier: Equatable {
|
||||
self.init()
|
||||
appearFunctions.append { storage, _ in
|
||||
storage.notify(name: "active-name", id: "init") {
|
||||
if let name = adw_toggle_group_get_active_name(storage.opaquePointer),
|
||||
let values = storage.fields[Self.values] as? [Element],
|
||||
let value = values.first(where: { $0.id.description == String(cString: name) }) {
|
||||
selection.wrappedValue = value.id
|
||||
let identifier = values
|
||||
.map({ $0[keyPath: label] }).first(where: { $0.description == String(cString: name) }),
|
||||
let value = values.first(where: { $0[keyPath: label] == identifier }) {
|
||||
selection.wrappedValue = value[keyPath: id]
|
||||
}
|
||||
}
|
||||
Self.updateContent(
|
||||
storage: storage,
|
||||
selection: selection.wrappedValue,
|
||||
values: values,
|
||||
updateProperties: true
|
||||
)
|
||||
}
|
||||
updateFunctions.append { storage, _, updateProperties in
|
||||
Self.updateContent(
|
||||
storage: storage,
|
||||
selection: selection.wrappedValue,
|
||||
values: values,
|
||||
id: id,
|
||||
label: label,
|
||||
icon: icon,
|
||||
showLabel: showLabel,
|
||||
updateProperties: updateProperties
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// swiftlint:disable function_parameter_count
|
||||
/// Update the combo row's content.
|
||||
/// - Parameters:
|
||||
/// - storage: The view storage.
|
||||
/// - values: The elements.
|
||||
/// - updateProperties: Whether to update the properties.
|
||||
static func updateContent<Element>(
|
||||
static func updateContent<Element, Identifier>(
|
||||
storage: ViewStorage,
|
||||
selection: Element.ID,
|
||||
selection: Identifier,
|
||||
values: [Element],
|
||||
id: KeyPath<Element, Identifier>,
|
||||
label: KeyPath<Element, String>,
|
||||
icon: KeyPath<Element, Icon?>?,
|
||||
showLabel: KeyPath<Element, Bool>?,
|
||||
updateProperties: Bool
|
||||
) where Element: ToggleGroupItem {
|
||||
) where Identifier: Equatable {
|
||||
guard updateProperties else {
|
||||
return
|
||||
}
|
||||
let old = storage.fields[Self.values] as? [Element] ?? []
|
||||
old.identifiableTransform(
|
||||
old.transform(
|
||||
to: values,
|
||||
id: id,
|
||||
functions: .init { index in
|
||||
if let id = old[safe: index]?.id.description,
|
||||
if let id = old[safe: index]?[keyPath: label],
|
||||
let toggle = storage.fields[Self.toggle + id] as? OpaquePointer {
|
||||
adw_toggle_group_remove(storage.opaquePointer, toggle)
|
||||
}
|
||||
} insert: { _, element in
|
||||
let toggle = adw_toggle_new()
|
||||
adw_toggle_set_name(toggle, element.id.description)
|
||||
if element.showLabel {
|
||||
adw_toggle_set_label(toggle, element.id.description)
|
||||
adw_toggle_set_name(toggle, element[keyPath: label])
|
||||
if let showLabel, !element[keyPath: showLabel] {
|
||||
adw_toggle_set_tooltip(toggle, element[keyPath: label])
|
||||
} else {
|
||||
adw_toggle_set_tooltip(toggle, element.id.description)
|
||||
adw_toggle_set_label(toggle, element[keyPath: label])
|
||||
}
|
||||
if let icon = element.icon {
|
||||
if let icon, let icon = element[keyPath: icon] {
|
||||
adw_toggle_set_icon_name(toggle, icon.string)
|
||||
}
|
||||
storage.fields[Self.toggle + element.id.description] = toggle
|
||||
storage.fields[Self.toggle + element[keyPath: label]] = toggle
|
||||
adw_toggle_group_add(storage.opaquePointer, toggle)
|
||||
}
|
||||
)
|
||||
storage.fields[Self.values] = values
|
||||
adw_toggle_group_set_active_name(storage.opaquePointer, selection.description)
|
||||
if let selection = values.first(where: { $0[keyPath: id] == selection }) {
|
||||
adw_toggle_group_set_active_name(storage.opaquePointer, selection[keyPath: label])
|
||||
}
|
||||
}
|
||||
// swiftlint:enable function_parameter_count
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -15,7 +15,12 @@ struct ToggleGroupDemo: View {
|
||||
@State private var selection: Subview = .view1
|
||||
|
||||
var view: Body {
|
||||
ToggleGroup(selection: $selection, values: Subview.allCases)
|
||||
ToggleGroup(
|
||||
selection: $selection,
|
||||
values: Subview.allCases,
|
||||
id: \.self,
|
||||
label: \.rawValue
|
||||
)
|
||||
.padding()
|
||||
VStack {
|
||||
Text(selection.rawValue)
|
||||
@ -26,19 +31,11 @@ struct ToggleGroupDemo: View {
|
||||
.padding()
|
||||
}
|
||||
|
||||
enum Subview: String, ToggleGroupItem, CaseIterable, CustomStringConvertible {
|
||||
enum Subview: String, CaseIterable, Equatable {
|
||||
|
||||
case view1 = "View 1"
|
||||
case view2 = "View 2"
|
||||
|
||||
var id: Self { self }
|
||||
|
||||
var description: String { rawValue }
|
||||
|
||||
var icon: Icon? { nil }
|
||||
|
||||
var showLabel: Bool { true }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ extension Class {
|
||||
.filter { config.requiredProperties.contains($0.name) }
|
||||
var initializer = "\(config.internalInitializer ? "" : "public ")init("
|
||||
if config.dynamicWidget != nil {
|
||||
initializer.append("_ elements: [Element], ")
|
||||
initializer.append("_ elements: [Element], id: KeyPath<Element, Identifier>, ")
|
||||
}
|
||||
for property in requiredProperties {
|
||||
initializer.append("\(property.parameter(config: config, genConfig: genConfig)), ")
|
||||
@ -46,6 +46,7 @@ extension Class {
|
||||
|
||||
self.elements = elements
|
||||
self.content = content
|
||||
self.id = id
|
||||
"""
|
||||
)
|
||||
}
|
||||
@ -167,6 +168,8 @@ extension Class {
|
||||
var elements: [Element]
|
||||
/// The dynamic widget content.
|
||||
var content: (Element) -> Body
|
||||
/// The dynamic widget identifier key path.
|
||||
var id: KeyPath<Element, Identifier>
|
||||
"""
|
||||
}
|
||||
content += staticWidgetProperties(namespace: namespace, configs: configs)
|
||||
@ -226,8 +229,9 @@ extension Class {
|
||||
return """
|
||||
var contentStorage: [ViewStorage] = storage.content[.mainContent] ?? []
|
||||
let old = storage.fields["element"] as? [Element] ?? []
|
||||
old.identifiableTransform(
|
||||
old.transform(
|
||||
to: elements,
|
||||
id: id,
|
||||
functions: .init { index in
|
||||
\(dynamicWidget.remove)(\(widget), \(dynamicWidget.getElement))
|
||||
contentStorage.remove(at: index)
|
||||
|
||||
@ -64,10 +64,25 @@ struct Class: ClassLike, Decodable {
|
||||
dateFormatter.dateFormat = "dd.MM.yy"
|
||||
let widgetName = config.name ?? config.class
|
||||
let definition: String
|
||||
var extensions = ""
|
||||
if config.dynamicWidget == nil {
|
||||
definition = "\(widgetName): AdwaitaWidget"
|
||||
} else {
|
||||
definition = "\(widgetName)<Element>: AdwaitaWidget where Element: Identifiable"
|
||||
definition = "\(widgetName)<Element, Identifier>: AdwaitaWidget where Identifier: Equatable"
|
||||
extensions += """
|
||||
|
||||
extension \(widgetName) where Element: Identifiable, Identifier == Element.ID {
|
||||
|
||||
/// Initialize `\(widgetName)`.
|
||||
public init(_ elements: [Element], @ViewBuilder content: @escaping (Element) -> Body) {
|
||||
self.elements = elements
|
||||
self.content = content
|
||||
self.id = \\.id
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
"""
|
||||
}
|
||||
return """
|
||||
//
|
||||
@ -135,7 +150,7 @@ struct Class: ClassLike, Decodable {
|
||||
}
|
||||
\(generateModifiers(config: config, genConfig: genConfig, namespace: namespace, configs: configs))
|
||||
}
|
||||
|
||||
\(extensions)
|
||||
"""
|
||||
}
|
||||
// swiftlint:enable function_body_length line_length
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user