74 lines
3.9 KiB
Swift
74 lines
3.9 KiB
Swift
import Adw
|
|
import Gtk
|
|
|
|
extension View {
|
|
@MainActor private func mountDialog(_ view: Dialog, _ ctx: MountContext) -> Adw.Dialog {
|
|
let widget = AnyView(view).makeWidget(ctx)
|
|
guard let dialog = widget as? Adw.Dialog else {
|
|
preconditionFailure("Dialog mounted a \(type(of: widget)); expected Adw.Dialog.")
|
|
}
|
|
return dialog
|
|
}
|
|
|
|
/// Presents a configurable `Adw.Dialog` over this view while `isPresented` is true.
|
|
///
|
|
/// Each property accepts a fixed value or a live `Binding`. Width and height use `Int32`;
|
|
/// integer literals are accepted. Use `DialogPresentationMode.bottomSheet` explicitly for
|
|
/// `presentationMode`. Setting `canClose` to false vetoes user dismissal.
|
|
///
|
|
/// - Parameters:
|
|
/// - isPresented: Two-way control over the dialog visibility.
|
|
/// - title: Optional dialog title.
|
|
/// - contentWidth: Optional content width in pixels.
|
|
/// - contentHeight: Optional content height in pixels.
|
|
/// - presentationMode: Optional dialog presentation mode.
|
|
/// - canClose: Whether user dismissal is allowed.
|
|
/// - followsContentSize: Whether the dialog follows its content size.
|
|
/// - content: Builder whose first view becomes the dialog child.
|
|
/// - Returns: This view, unchanged, with the dialog presentation attached.
|
|
public func dialog(
|
|
isPresented: Binding<Bool>,
|
|
title: (any DialogPropertySource<String>)? = nil,
|
|
contentWidth: (any DialogPropertySource<Int32>)? = nil,
|
|
contentHeight: (any DialogPropertySource<Int32>)? = nil,
|
|
presentationMode: (any DialogPropertySource<DialogPresentationMode>)? = nil,
|
|
canClose: (any DialogPropertySource<Bool>)? = nil,
|
|
followsContentSize: (any DialogPropertySource<Bool>)? = nil,
|
|
@ViewBuilder content: () -> [AnyView]
|
|
) -> AnyView {
|
|
let contentViews = content()
|
|
var configured = Dialog()
|
|
configured = appliedDialogProperty(title, to: configured, constant: { $0.title($1) }, binding: { $0.title($1) })
|
|
configured = appliedDialogProperty(contentWidth, to: configured, constant: { $0.contentWidth($1) }, binding: { $0.contentWidth($1) })
|
|
configured = appliedDialogProperty(contentHeight, to: configured, constant: { $0.contentHeight($1) }, binding: { $0.contentHeight($1) })
|
|
configured = appliedDialogProperty(presentationMode, to: configured, constant: { $0.presentationMode($1) }, binding: { $0.presentationMode($1) })
|
|
configured = appliedDialogProperty(canClose, to: configured, constant: { $0.canClose($1) }, binding: { $0.canClose($1) })
|
|
configured = appliedDialogProperty(followsContentSize, to: configured, constant: { $0.followsContentSize($1) }, binding: { $0.followsContentSize($1) })
|
|
|
|
return AnyView(makeWidget: { ctx in
|
|
let host = AnyView(self).makeWidget(ctx)
|
|
let dialog = mountDialog(configured, ctx)
|
|
if let first = contentViews.first {
|
|
dialog.setChild(child: first.makeWidget(ctx))
|
|
}
|
|
bindDialogPresentation(dialog, isPresented: isPresented, host: host, ctx: ctx)
|
|
return host
|
|
})
|
|
}
|
|
|
|
/// Presents a pre-configured `Dialog` over this view while `isPresented` is true.
|
|
///
|
|
/// Use this overload for widget-slot properties such as `defaultWidget` and `focusWidget`.
|
|
/// - Parameters:
|
|
/// - isPresented: Two-way control over the dialog visibility.
|
|
/// - dialog: The configured dialog view to mount.
|
|
/// - Returns: This view, unchanged, with the dialog presentation attached.
|
|
public func dialog(isPresented: Binding<Bool>, _ dialog: Dialog) -> AnyView {
|
|
AnyView(makeWidget: { ctx in
|
|
let host = AnyView(self).makeWidget(ctx)
|
|
let mounted = mountDialog(dialog, ctx)
|
|
bindDialogPresentation(mounted, isPresented: isPresented, host: host, ctx: ctx)
|
|
return host
|
|
})
|
|
}
|
|
}
|