david-swift 8f6a83dfc3
Some checks are pending
Deploy Docs / publish (push) Waiting to run
SwiftLint / SwiftLint (push) Waiting to run
Move update responsibility to constructor
When constructing views, the top-level constructor should now update
those views directly after the construction process. In adwaita-swift,
this applies only for EitherViews (as Meta will now automatically update
when constructing new scene elements).
2026-02-02 22:44:44 +01:00

142 lines
4.3 KiB
Swift

//
// AboutDialog.swift
// Adwaita
//
// Created by david-swift on 21.03.24.
//
import CAdw
import Foundation
/// The about dialog widget.
struct AboutDialog: AdwaitaWidget {
/// Whether the dialog is visible.
@Binding var visible: Bool
/// The wrapped view.
var child: AnyView
/// The app's name.
var appName: String?
/// The developer's name.
var developer: String?
/// The app version.
var version: String?
/// The app icon.
var icon: Icon?
/// The app's website.
var website: URL?
/// The link for opening issues.
var issues: URL?
/// The ID for the dialog's storage.
let dialogID = "dialog"
/// Initialize the about dialog wrapper.
/// - Parameters:
/// - visible: The visibility.
/// - child: The child view.
/// - appName: The app's name.
/// - developer: The developer's name.
/// - version: The version.
/// - icon: The icon.
/// - website: The website's URL.
/// - issues: The link for opening issues.
init(
visible: Binding<Bool>,
child: AnyView,
appName: String? = nil,
developer: String? = nil,
version: String? = nil,
icon: Icon? = nil,
website: URL? = nil,
issues: URL? = nil
) {
self._visible = visible
self.child = child
self.appName = appName
self.developer = developer
self.version = version
self.icon = icon
self.website = website
self.issues = issues
}
/// The view storage.
/// - Parameters:
/// - modifiers: Modify views before being updated.
/// - type: The view render data type.
/// - Returns: The view storage.
func container<Data>(data: WidgetData, type: Data.Type) -> ViewStorage where Data: ViewRenderData {
child.storage(data: data, type: type)
}
/// Update the stored content.
/// - Parameters:
/// - storage: The storage to update.
/// - modifiers: Modify views before being updated
/// - updateProperties: Whether to update the view's properties.
/// - type: The view render data type.
func update<Data>(
_ storage: ViewStorage,
data: WidgetData,
updateProperties: Bool,
type: Data.Type
) where Data: ViewRenderData {
child.updateStorage(storage, data: data, updateProperties: updateProperties, type: type)
guard updateProperties else {
return
}
if visible {
if storage.content[dialogID]?.first == nil {
createDialog(storage: storage)
adw_dialog_present(
storage.content[dialogID]?.first?.opaquePointer?.cast(),
storage.opaquePointer?.cast()
)
}
let dialog = storage.content[dialogID]?.first?.opaquePointer
if let appName {
adw_about_dialog_set_application_name(dialog, appName)
}
if let developer {
adw_about_dialog_set_developer_name(dialog, developer)
}
if let version {
adw_about_dialog_set_version(dialog, version)
}
if let icon {
adw_about_dialog_set_application_icon(dialog, icon.string)
}
if let website {
adw_about_dialog_set_website(dialog, website.absoluteString)
}
if let issues {
adw_about_dialog_set_issue_url(dialog, issues.absoluteString)
}
adw_dialog_set_content_height(dialog?.cast(), -1)
} else {
if storage.content[dialogID]?.first != nil {
let dialog = storage.content[dialogID]?.first?.opaquePointer
adw_dialog_close(dialog?.cast())
storage.content[dialogID] = []
}
}
}
/// Create a new instance of the dialog.
/// - Parameter storage: The wrapped view's storage.
func createDialog(storage: ViewStorage) {
let pointer = adw_about_dialog_new()
let dialog = ViewStorage(pointer?.opaque())
storage.content[dialogID] = [dialog]
dialog.connectSignal(name: "closed") {
storage.content[dialogID] = []
if visible {
visible = false
}
}
}
}