diff --git a/Directory.Build.targets b/Directory.Build.targets
index d42a4023..fb04912f 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -22,6 +22,8 @@
+
+
@@ -30,12 +32,14 @@
-
-
+
+
+
+
diff --git a/samples/JetNews/README.md b/samples/JetNews/README.md
index 228b893b..82f8a9c5 100644
--- a/samples/JetNews/README.md
+++ b/samples/JetNews/README.md
@@ -62,7 +62,7 @@ feature.
| Upstream feature | Tracking issue |
|-----------------------------------------------------------------|----------------|
-| Adaptive list-detail two-pane layout on wider devices | [#143](https://github.com/jonathanpeppers/Microsoft.AndroidX.Compose/issues/143) (WindowSizeClass), plus a SharedTransitionLayout / ListDetailScene binding |
+| Adaptive list-detail two-pane layout on wider devices | `SharedTransitionLayout` / `ListDetailScene` binding (the `WindowSizeClass` read itself shipped in [#143](https://github.com/jonathanpeppers/Microsoft.AndroidX.Compose/issues/143) — see `composer.CurrentWindowAdaptiveInfo()`) |
| Real hero PNGs in card / article (currently a solid `Box` filled with a per-post `HeroColor`) | [#145](https://github.com/jonathanpeppers/Microsoft.AndroidX.Compose/issues/145) — `ContentScale.Crop` on the `Image` facade; without it small vector hero images letterbox |
| Inline-run paragraph styling (Link / Bold / Italic / Code spans inside one paragraph) | [#141](https://github.com/jonathanpeppers/Microsoft.AndroidX.Compose/issues/141) — `AnnotatedString` + `SpanStyle` |
| Top-bar elevation / collapse on scroll (`pinnedScrollBehavior`, `enterAlwaysScrollBehavior`) | [#142](https://github.com/jonathanpeppers/Microsoft.AndroidX.Compose/issues/142) — `Modifier.nestedScroll` + `TopAppBarDefaults` |
diff --git a/samples/README.md b/samples/README.md
index b2ba4283..0365135b 100644
--- a/samples/README.md
+++ b/samples/README.md
@@ -46,7 +46,6 @@ that needs the same primitive.
| [#20](https://github.com/jonathanpeppers/Microsoft.AndroidX.Compose/issues/20) | Edge-to-edge bootstrapping | Status/nav-bar overlap on every sample. |
| [#141](https://github.com/jonathanpeppers/Microsoft.AndroidX.Compose/issues/141) | `AnnotatedString` + `SpanStyle` for inline-run text styling | Link / Bold / Italic / Code spans inside paragraphs in **JetNews** article reader. |
| [#142](https://github.com/jonathanpeppers/Microsoft.AndroidX.Compose/issues/142) | `Modifier.nestedScroll` + `TopAppBarDefaults` scroll behaviors | Top-bar elevation / collapse on scroll in **JetNews**, **Reply**, **Jetcaster**. |
-| [#143](https://github.com/jonathanpeppers/Microsoft.AndroidX.Compose/issues/143) | WindowSizeClass / `currentWindowAdaptiveInfo` | Adaptive layouts; blocks **Reply** entirely and the **JetNews** list-detail screen. |
| [#144](https://github.com/jonathanpeppers/Microsoft.AndroidX.Compose/issues/144) | Custom `Layout {}` primitive — Measurable / Placeable / MeasureScope | `InterestsAdaptiveContentLayout` in **JetNews**, custom carousels in **Jetsnack**, asymmetric chat bubbles in **Jetchat**. |
| [#145](https://github.com/jonathanpeppers/Microsoft.AndroidX.Compose/issues/145) | `ContentScale` + `Alignment` slots on the `Image` facade | Hero images on cards in **JetNews** (currently solid-color `Box` placeholders). |
| [#146](https://github.com/jonathanpeppers/Microsoft.AndroidX.Compose/issues/146) | `stringResource(id)` lookup | Localizable UI strings in every sample (all currently inline literals). |
@@ -66,7 +65,8 @@ Closed gaps that previously appeared here (now usable in samples):
**#63** Modifier surface (Background/Border/Clickable/Size/Width/Height/AspectRatio/Offset/Alpha/Clip/Weight + scroll + focus + semantics + Draggable),
**#65** Compose value types (`Color`/`Dp`/`Sp`/`FontWeight`/`TextAlign`),
**#70** Row/Column `Arrangement`,
-**#140** `DrawerState.open()` / `close()` suspend bridges.
+**#140** `DrawerState.open()` / `close()` suspend bridges,
+**#143** `WindowSizeClass` predicates + `currentWindowAdaptiveInfo()` extension (NavigationSuiteScaffold, SharedTransitionLayout, and ListDetailScene bindings still missing — see [#168](https://github.com/jonathanpeppers/Microsoft.AndroidX.Compose/issues/168) for the fold-aware TwoPane piece).
## Attribution
diff --git a/samples/Reply/README.md b/samples/Reply/README.md
index f1053e2e..5ad188c3 100644
--- a/samples/Reply/README.md
+++ b/samples/Reply/README.md
@@ -50,8 +50,8 @@ links back to the tracking issues.
| Upstream feature | Status | Tracking issue |
|------------------|--------|----------------|
-| `NavigationSuiteScaffold` + `WindowSizeClass` (compact → medium → expanded switchover) | dropped — pinned to bottom nav | [#143](https://github.com/jonathanpeppers/Microsoft.AndroidX.Compose/issues/143) |
-| `NavigationRail` / `PermanentNavigationDrawer` / `ModalNavigationDrawer` content for medium and expanded sizes | dropped — bottom nav only | [#143](https://github.com/jonathanpeppers/Microsoft.AndroidX.Compose/issues/143) |
+| `NavigationSuiteScaffold` (compact → medium → expanded switchover) | dropped — pinned to bottom nav | `Xamarin.AndroidX.Compose.Material3.Adaptive.NavigationSuite` not yet referenced; would also need [#163](https://github.com/jonathanpeppers/Microsoft.AndroidX.Compose/issues/163). The size-class read itself ([#143](https://github.com/jonathanpeppers/Microsoft.AndroidX.Compose/issues/143)) shipped — see `composer.CurrentWindowAdaptiveInfo()`. |
+| `NavigationRail` / `PermanentNavigationDrawer` / `ModalNavigationDrawer` content for medium and expanded sizes | dropped — bottom nav only | [#163](https://github.com/jonathanpeppers/Microsoft.AndroidX.Compose/issues/163) (drawer-row facade) — branching on `WindowSizeClass` is unblocked by [#143](https://github.com/jonathanpeppers/Microsoft.AndroidX.Compose/issues/143). |
| `accompanist.adaptive.TwoPane` + `WindowLayoutInfo`/`FoldingFeature` (list-detail with fold avoidance) | dropped — single-pane | [#168](https://github.com/jonathanpeppers/Microsoft.AndroidX.Compose/issues/168) |
| `NavigationDrawerItem` rows inside `ModalDrawerSheet` | not used (no drawer in single-pane port) | [#163](https://github.com/jonathanpeppers/Microsoft.AndroidX.Compose/issues/163) |
| `BackHandler {}` to collapse multi-select / detail | dropped — system back falls through to the navigator | [#166](https://github.com/jonathanpeppers/Microsoft.AndroidX.Compose/issues/166) |
diff --git a/samples/Reply/ReplyApp.cs b/samples/Reply/ReplyApp.cs
index fa4cbdc8..9d9b9a34 100644
--- a/samples/Reply/ReplyApp.cs
+++ b/samples/Reply/ReplyApp.cs
@@ -8,8 +8,13 @@ namespace AndroidX.Compose.Samples.Reply;
///
/// Upstream Reply uses NavigationSuiteScaffoldLayout +
/// WindowSizeClass to pick between bottom nav (compact), nav
-/// rail (medium), and permanent drawer (expanded). That adaptive
-/// scaffold isn't bound yet (#143), so this port pins to bottom nav.
+/// rail (medium), and permanent drawer (expanded). The
+/// WindowSizeClass read itself is now available (issue #143 —
+/// see composer.CurrentWindowAdaptiveInfo()), but
+/// NavigationSuiteScaffold lives in the
+/// Xamarin.AndroidX.Compose.Material3.Adaptive.NavigationSuite
+/// package which isn't referenced yet, so this port still pins to
+/// bottom nav.
///
public static class ReplyApp
{
diff --git a/src/Microsoft.AndroidX.Compose.Gallery/Demos/LocalsMisc/WindowSizeClassDemo.cs b/src/Microsoft.AndroidX.Compose.Gallery/Demos/LocalsMisc/WindowSizeClassDemo.cs
new file mode 100644
index 00000000..de9e6813
--- /dev/null
+++ b/src/Microsoft.AndroidX.Compose.Gallery/Demos/LocalsMisc/WindowSizeClassDemo.cs
@@ -0,0 +1,62 @@
+using AndroidX.Compose.Runtime;
+using AndroidX.Compose.Gallery.Registry;
+using AndroidX.Window.Core.Layout;
+
+namespace AndroidX.Compose.Gallery.Demos.LocalsMisc;
+
+///
+/// composer.CurrentWindowAdaptiveInfo() — live readout of the upstream
+/// + Posture, plus a phone / tablet / desktop
+/// indicator that flips at the Material 3 standard breakpoints. Rotate the
+/// device or resize the split-screen window to see all values update.
+///
+public static class WindowSizeClassDemo
+{
+ /// Registry entry exposed via .
+ public static Demo Demo => new(
+ Id: "locals-window-size-class",
+ CategoryId: "locals-misc",
+ Title: "WindowAdaptiveInfo & WindowSizeClass",
+ Description: "composer.CurrentWindowAdaptiveInfo() — live size class predicates + posture for adaptive layouts. Rotate to flip the Phone/Tablet/Desktop label.",
+ Build: _ => new Column
+ {
+ new SizeClassReadout(),
+ });
+
+ sealed class SizeClassReadout : ComposableNode
+ {
+ public override void Render(IComposer composer)
+ {
+ var info = composer.CurrentWindowAdaptiveInfo();
+ var size = info.WindowSizeClass;
+ var posture = info.WindowPosture;
+
+ new Column
+ {
+ new Text($"MinWidthDp = {size.MinWidthDp}"),
+ new Text($"MinHeightDp = {size.MinHeightDp}"),
+ new Text(""),
+ new Text("Width predicates at standard breakpoints:"),
+ new Text($" IsWidthAtLeastBreakpoint(600) = {size.IsWidthAtLeastBreakpoint(WindowSizeClass.WidthDpMediumLowerBound)}"),
+ new Text($" IsWidthAtLeastBreakpoint(840) = {size.IsWidthAtLeastBreakpoint(WindowSizeClass.WidthDpExpandedLowerBound)}"),
+ new Text("Height predicates at standard breakpoints:"),
+ new Text($" IsHeightAtLeastBreakpoint(480) = {size.IsHeightAtLeastBreakpoint(WindowSizeClass.HeightDpMediumLowerBound)}"),
+ new Text($" IsHeightAtLeastBreakpoint(900) = {size.IsHeightAtLeastBreakpoint(WindowSizeClass.HeightDpExpandedLowerBound)}"),
+ new Text(""),
+ new Text($"Layout class: {DeviceLabel(size)}"),
+ new Text(""),
+ new Text("Posture (foldable / hinge state):"),
+ new Text($" IsTabletop = {posture.IsTabletop}"),
+ new Text($" Hinge count = {posture.HingeList.Count}"),
+ }.Render(composer);
+ }
+
+ // Process larger breakpoints first — IsWidthAtLeastBreakpoint is order-
+ // dependent: a 1200dp window matches the 600dp breakpoint too. Upstream
+ // docs explicitly call out this larger→smaller ordering.
+ static string DeviceLabel(WindowSizeClass size) =>
+ size.IsWidthAtLeastBreakpoint(WindowSizeClass.WidthDpExpandedLowerBound) ? "🖥️ Desktop (Expanded)" :
+ size.IsWidthAtLeastBreakpoint(WindowSizeClass.WidthDpMediumLowerBound) ? "📟 Tablet (Medium)" :
+ "📱 Phone (Compact)";
+ }
+}
diff --git a/src/Microsoft.AndroidX.Compose.Gallery/Registry/Catalog.cs b/src/Microsoft.AndroidX.Compose.Gallery/Registry/Catalog.cs
index b7cb6444..70ea7e83 100644
--- a/src/Microsoft.AndroidX.Compose.Gallery/Registry/Catalog.cs
+++ b/src/Microsoft.AndroidX.Compose.Gallery/Registry/Catalog.cs
@@ -172,6 +172,7 @@ public static class Catalog
D.LocalsMisc.BuiltInCompositionLocalsDemo.Demo,
D.LocalsMisc.CustomCompositionLocalDemo.Demo,
D.LocalsMisc.ComposeViewInteropDemo.Demo,
+ D.LocalsMisc.WindowSizeClassDemo.Demo,
D.LocalsMisc.CircularProgressIndicatorDemo.Demo,
D.LocalsMisc.LinearProgressIndicatorDemo.Demo,
D.LocalsMisc.ImageDemo.Demo,
diff --git a/src/Microsoft.AndroidX.Compose/ComposeExtensions.CurrentWindowAdaptiveInfo.cs b/src/Microsoft.AndroidX.Compose/ComposeExtensions.CurrentWindowAdaptiveInfo.cs
new file mode 100644
index 00000000..4838d165
--- /dev/null
+++ b/src/Microsoft.AndroidX.Compose/ComposeExtensions.CurrentWindowAdaptiveInfo.cs
@@ -0,0 +1,59 @@
+using AndroidX.Compose.Material3.Adaptive;
+using AndroidX.Compose.Runtime;
+
+namespace AndroidX.Compose;
+
+public static partial class ComposeExtensions
+{
+ ///
+ /// C# parity of Kotlin's currentWindowAdaptiveInfo() @Composable
+ /// from androidx.compose.material3.adaptive. Returns the live
+ /// for the host window — exposes both the
+ /// upstream
+ /// (with IsWidthAtLeastBreakpoint / IsHeightAtLeastBreakpoint
+ /// + the standard 600 / 840 / 480 / 900 dp breakpoint constants) and the
+ /// describing foldable / tabletop state.
+ ///
+ /// Use this to branch between phone / tablet / desktop layouts inside
+ /// a composable:
+ ///
+ ///
+ /// var info = composer.CurrentWindowAdaptiveInfo();
+ /// if (info.WindowSizeClass.IsWidthAtLeastBreakpoint(
+ /// AndroidX.Window.Core.Layout.WindowSizeClass.WidthDpMediumLowerBound))
+ /// return ListDetailScreen.Build(...);
+ /// else
+ /// return PhoneScreen.Build(...);
+ ///
+ ///
+ /// Re-reads on every recomposition Compose drives, so layout code
+ /// that branches off the returned reacts
+ /// naturally to rotation, multi-window resize, fold / unfold, and
+ /// activity-embedded surface changes.
+ ///
+ /// The composer for the active composition.
+ ///
+ /// When true, snaps width buckets at the additional 1200 dp
+ /// (large) and 1600 dp (extra-large) breakpoints in addition to the
+ /// standard 600 / 840 bounds. Mirrors the Kotlin parameter
+ /// of the same name; defaults to false for parity with the
+ /// no-argument Kotlin call site.
+ ///
+ ///
+ /// The bound Kotlin would have returned —
+ /// not a managed wrapper. Pass it straight to any binding API that takes
+ /// one (e.g. NavigationSuiteScaffold).
+ ///
+ public static WindowAdaptiveInfo CurrentWindowAdaptiveInfo(
+ this IComposer composer,
+ bool supportLargeAndXLargeWidth = false)
+ {
+ ArgumentNullException.ThrowIfNull(composer);
+
+ return WindowAdaptiveInfoKt.CurrentWindowAdaptiveInfo(
+ supportLargeAndXLargeWidth,
+ composer,
+ p2: 0,
+ _changed: 0);
+ }
+}
diff --git a/src/Microsoft.AndroidX.Compose/Microsoft.AndroidX.Compose.csproj b/src/Microsoft.AndroidX.Compose/Microsoft.AndroidX.Compose.csproj
index 0e7b0d8b..58263bd2 100644
--- a/src/Microsoft.AndroidX.Compose/Microsoft.AndroidX.Compose.csproj
+++ b/src/Microsoft.AndroidX.Compose/Microsoft.AndroidX.Compose.csproj
@@ -34,6 +34,8 @@
+
+
@@ -58,6 +60,8 @@
+
+
diff --git a/src/Microsoft.AndroidX.Compose/PublicAPI.Unshipped.txt b/src/Microsoft.AndroidX.Compose/PublicAPI.Unshipped.txt
index d276e26a..8108b0bc 100644
--- a/src/Microsoft.AndroidX.Compose/PublicAPI.Unshipped.txt
+++ b/src/Microsoft.AndroidX.Compose/PublicAPI.Unshipped.txt
@@ -1414,6 +1414,7 @@ static AndroidX.Compose.ComposeExtensions.CollectAsStateWithLifecycle(this Xa
static AndroidX.Compose.ComposeExtensions.CollectAsStateWithLifecycle(this Xamarin.KotlinX.Coroutines.Flow.IStateFlow! stateFlow, AndroidX.Compose.Runtime.IComposer! composer) -> AndroidX.Compose.CollectedState!
static AndroidX.Compose.ComposeExtensions.ColorResource(this AndroidX.Compose.Runtime.IComposer! composer, int id) -> long
static AndroidX.Compose.ComposeExtensions.ColorScheme(this AndroidX.Compose.Runtime.IComposer! composer) -> AndroidX.Compose.Material3.ColorScheme!
+static AndroidX.Compose.ComposeExtensions.CurrentWindowAdaptiveInfo(this AndroidX.Compose.Runtime.IComposer! composer, bool supportLargeAndXLargeWidth = false) -> AndroidX.Compose.Material3.Adaptive.WindowAdaptiveInfo!
static AndroidX.Compose.ComposeExtensions.DerivedStateOf(System.Func! calculation) -> AndroidX.Compose.DerivedState!
static AndroidX.Compose.ComposeExtensions.DerivedStateOf(this AndroidX.Compose.Runtime.IComposer! composer, System.Func! calculation) -> AndroidX.Compose.DerivedState!
static AndroidX.Compose.ComposeExtensions.DimensionResource(this AndroidX.Compose.Runtime.IComposer! composer, int id) -> AndroidX.Compose.Dp