Skip to main content

Module present

Module present 

Source
Expand description

Native presentations: platform-owned modal UI (an alert, and on iOS/iPadOS a sheet) requested imperatively from Rust and resolved to exactly one terminal outcome.

§Why not a platform-view slot

A control is a platform_view slot the differ owns: it disposes a slot that goes missing from the ingest stream and knows nothing about modal stacking. A modal belongs to the host instead — the resumed Android Activity, the topmost iOS view controller, the macOS key window — so a presentation is a request (show_alert, show_sheet) answered by a Presentation future, never a node in the tree.

§The contract

  • One in flight, process-wide — across every kind. A second request while one is live resolves PresentError::Busy immediately — no queueing, no replacing. The slot is shared by every presentation kind: an alert and a sheet can never both be live, so a show_sheet while an alert is up (or the reverse) is refused Busy too.
  • Exactly one terminal outcome. Each accepted request is stamped with a fresh, never-zero generation, and resolves through a one-shot channel whose sending half is consumed by its first use: an action, a cancellation, a programmatic dismiss, or the host going away (AlertOutcome::HostLost, SheetOutcome::HostLost). A platform callback arriving for any other generation finds no live entry and is dropped. A sheet’s detent changes are not outcomes: they stream through SheetSpec::on_detent while the sheet stays live.
  • The slot frees itself. It is released when the outcome is sent (before the caller is woken, so the caller’s continuation may present again), when an arm drops its sender without sending (resolving PresentError::Platform), or when the caller drops the Presentation. Dropping the future frees only this module’s bookkeeping: the platform UI stays up until the user answers it, and that answer is discarded.
  • Awaitable anywhere. Presentation is a plain Future with no executor dependency: resolution is driven by the platform’s main thread, so it can be polled from frust::spawn_local or any other executor. Nothing ever blocks waiting for a modal result.

§Platform arms

AlertHost is the alert seam, selected by cfg per OS:

  • iOS/iPadOS — apple_alert: a UIAlertController (alert or action sheet, an iPad action sheet anchored as a popover) built over apple_host’s shared helpers.
  • macOS — appkit_alert: an NSAlert presented as a window sheet (beginSheetModalForWindow:completionHandler:) on the key/main window, also built over apple_host’s shared helpers. macOS has no action-sheet idiom, so AlertStyle::ActionSheet presents the same sheet as AlertStyle::Alert and AlertSpec::anchor is ignored.
  • Android — android_alert: an android.app.AlertDialog, over android_host’s shared JNI plumbing (the dev.frust.nativewidgets.FrustNativePresenter Kotlin object that tracks the resumed Activity, its one nativeOnOutcome callback and the live-presentation guard).
  • Every other target — unsupported: PresentError::Unsupported.

SheetHost is the sheet seam: iOS/iPadOS — apple_sheet, a plugin-owned UIViewController subclass presented as a page sheet under UISheetPresentationController (detents, grabber, adaptive dismissal); every other target — this module’s own UnsupportedSheet (PresentError::Unsupported; a macOS NSPopover or Android BottomSheetDialog arm is follow-up work).

apple_host holds what every Apple arm shares: host discovery, the main-queue hop and the live-presentation guard.

Structs§

AlertAction
One alert button.
AlertSpec
What an alert asks: a title, a message, up to MAX_ALERT_ACTIONS actions, and how it is presented.
AnchorRect
A rectangle in logical points of the presenting window’s coordinate space, origin top-left — where an action sheet’s popover points from.
Presentation
The future a presentation request answers with — see the module doc’s The contract.
PresentationHandle
Names one accepted presentation, for dismiss. Stale once that presentation has resolved: dismissing it then does nothing.
SheetAction
One sheet action row — a system button.
SheetContent
A sheet’s content — the constrained schema a native sheet renders with platform views only (decision D4): a title, a message, an optional image and up to MAX_SHEET_ACTIONS action rows, laid out top to bottom in that order. Arbitrary frust content is deliberately not accepted: frust has a single render root, and a platform_view slot never mounts inside a presented controller.
SheetHandle
Names one accepted sheet: take it down or move it between detents. Stale once that sheet has resolved — both calls then do nothing.
SheetSpec
What a sheet asks: its SheetContent, the detents it rests at and how its sheet chrome behaves.

Enums§

ActionRole
An action’s semantic role, mapped onto each platform’s own button styles.
AlertOutcome
How an alert ended — exactly one per accepted show_alert.
AlertStyle
How an alert is presented.
Detent
A height a sheet rests at.
DismissReason
Why a sheet went away without an action.
PresentError
Why a presentation could not be shown or did not complete.
SheetOutcome
How a sheet ended — exactly one per accepted show_sheet.

Constants§

MAX_ALERT_ACTIONS
The most actions one alert takes — the common ceiling of the three platforms (Android’s AlertDialog has exactly three button slots).
MAX_SHEET_ACTIONS
The most actions one sheet takes — the same ceiling as an alert’s (MAX_ALERT_ACTIONS): a sheet’s action rows are a short choice, not a menu.

Functions§

dismiss
Take the presentation handle names down; it resolves AlertOutcome::Dismissed — or, for a sheet, SheetOutcome::Dismissed(DismissReason::Programmatic) — exactly once. A stale handle — its presentation already resolved, or superseded — is ignored.
show_alert
Present a native alert — see the module doc’s The contract.
show_sheet
Present a native sheet — see the module doc’s The contract.