Skip to content

Bind ModalWideNavigationRail (issue #5 follow-up)#50

Merged
jonathanpeppers merged 2 commits into
mainfrom
jonathanpeppers/bind-misc-compose-apis
Jun 4, 2026
Merged

Bind ModalWideNavigationRail (issue #5 follow-up)#50
jonathanpeppers merged 2 commits into
mainfrom
jonathanpeppers/bind-misc-compose-apis

Conversation

@jonathanpeppers

Copy link
Copy Markdown
Owner

Completes the remaining actionable item from #5 that was deferred in #33.

#33 already shipped CircularProgressIndicator, LinearProgressIndicator,
SegmentedButton + both rows, WideNavigationRail, and
WideNavigationRailItem. This change adds ModalWideNavigationRail
the modal-overlay variant. SecureTextField is still deferred on the
TextFieldState story (out of scope).

What's added

  • Bridge. [ComposeBridge] ModalWideNavigationRail targets the
    stripped androidx/compose/material3/WideNavigationRailKt::ModalWideNavigationRail-k3FuEkE
    JVM name. The hash comes from the Dp @JvmInline value class on
    collapsedShadowElevation; once [generator] Phase 2: Kotlin @JvmInline value class projection dotnet/java-interop#1440 lands the
    bridge can be swapped for a direct binding call.
  • Defaults enum. [ComposeDefaults] ModalWideNavigationRailDefault
    with state and content marked ! (the facade always supplies
    these — they are not enum members and not in All).
  • Facade. New ModalWideNavigationRail class (ComposableContainer
    with optional Header slot). Uses the bound (non-stripped)
    WideNavigationRailStateKt.RememberWideNavigationRailState for the
    state holder, so no extra bridge is needed there.
  • Sample. A "Modal rail" button on the Misc tab demonstrates the
    visibility-toggle pattern with an internal "Close" item.

Documented limitations

WideNavigationRailStates expand / collapse / snapTo methods are
Kotlin suspend functions. We don't have a LaunchedEffect /
coroutine story for C# yet, so:

  1. The facade always remembers state with
    WideNavigationRailValue.Expanded, so the rail opens immediately
    when mounted.
  2. Scrim-tap dismissal hides the rail visually (because
    hideOnCollapse = true) but cannot notify C#. Callers gate
    visibility on their own MutableState<bool> and add an internal
    close button — the sample shows the pattern, and the XML doc on
    ModalWideNavigationRail calls this out explicitly.

Known risk

The Misc tab still trips compose-net#42 ("LayoutNode insertAt
ArrayIndexOutOfBoundsException") when switching tabs after interacting
with several Misc widgets. ModalWideNavigationRail may share the same
underlying $changed = 0 / lambda-identity story; tracked separately
in that issue.

Verified

  • dotnet test src/ComposeNet.SourceGenerators.Tests — 32/32 pass.
  • dotnet build src/ComposeNet.Compose — 0 errors.
  • dotnet build src/ComposeNet.Sample — 0 errors, 0 warnings.

Closes the modal-rail part of #5.

Copilot AI review requested due to automatic review settings June 4, 2026 19:55

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new facade + JNI bridge for Material3 ModalWideNavigationRail (the modal-overlay variant of WideNavigationRail) to complete the remaining actionable follow-up from issue #5, along with a sample usage in the Misc tab.

Changes:

  • Introduces a new ModalWideNavigationRail composable container facade with an optional Header slot and documented limitations around dismissal/coroutines.
  • Adds a [ComposeBridge] entry for the stripped WideNavigationRailKt::ModalWideNavigationRail-k3FuEkE JVM method plus a corresponding [ComposeDefaults] declaration.
  • Extends the sample app’s Misc tab to demonstrate mounting/unmounting a modal rail with a “Close” item.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/ComposeNet.Sample/MainActivity.cs Adds a Misc-tab demo for ModalWideNavigationRail and a visibility gate state.
src/ComposeNet.Compose/ModalWideNavigationRail.cs New facade container that remembers rail state and calls the JNI bridge with appropriate $default masking.
src/ComposeNet.Compose/ComposeDefaults.cs Declares ModalWideNavigationRailDefault bit positions for generator-produced defaults enum.
src/ComposeNet.Compose/ComposeBridges.cs Adds the [ComposeBridge] stub for ModalWideNavigationRail-k3FuEkE targeting the stripped overload.

Comment thread src/ComposeNet.Compose/ModalWideNavigationRail.cs Outdated
Comment thread src/ComposeNet.Sample/MainActivity.cs
PR #33 already shipped CircularProgressIndicator, LinearProgressIndicator,
SegmentedButton + both rows, WideNavigationRail, and WideNavigationRailItem
for issue #5. This change completes the remaining actionable item from
that issue, `ModalWideNavigationRail`. SecureTextField is still deferred
on the `TextFieldState` story.

- Add `[ComposeBridge] ModalWideNavigationRail` targeting the stripped
  `ModalWideNavigationRail-k3FuEkE` JVM name (hashed because of the `Dp`
  `@JvmInline value class` on `collapsedShadowElevation`).
- Add `[ComposeDefaults] ModalWideNavigationRailDefault` enum, marking
  `state` and `content` as `!` (always supplied by the facade).
- New `ModalWideNavigationRail` facade (ComposableContainer with
  optional `Header` slot). Uses the bound (non-stripped)
  `WideNavigationRailStateKt.RememberWideNavigationRailState` so no
  extra bridge is needed for the state holder.
- Sample: add a "Modal" button to the Misc tab demonstrating the
  visibility-toggle pattern with an internal "Close" item.

The facade documents two limitations callers should know about:
1. The rail always remembers state with `WideNavigationRailValue.Expanded`
   because the state's `expand`/`collapse`/`snapTo` methods are Kotlin
   suspend functions (no coroutine story in C# yet).
2. Scrim-tap dismissal hides the rail visually but cannot notify C#;
   callers gate visibility on their own `MutableState<bool>` and add an
   internal close button.

Once dotnet/java-interop#1440 lands the bridge can be swapped for a
direct call to the binding.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers jonathanpeppers force-pushed the jonathanpeppers/bind-misc-compose-apis branch from 668da58 to 3d51fda Compare June 4, 2026 20:18
- ModalWideNavigationRail XML doc: use `tab.Value == 0` (was `tab == 0`, which doesn't compile against MutableNumberState<int>).

- Sample Misc tab: turn the `Open modal rail` button into a toggle so users can re-mount the rail after a scrim dismiss (the internal Close item is still there for the common case).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers jonathanpeppers merged commit f43cbf7 into main Jun 4, 2026
@jonathanpeppers jonathanpeppers deleted the jonathanpeppers/bind-misc-compose-apis branch June 4, 2026 20:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants