From 49ee6546f172fa8cc0ebcc19d039d75f5e8c02f0 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Mon, 15 Jun 2026 18:09:31 -0500 Subject: [PATCH 1/6] Wire RefreshColor on RefreshViewHandler Maps Microsoft.Maui.Graphics.SolidPaint on IRefreshView.RefreshColor to the Compose Material 3 PullToRefreshDefaults.Indicator spinner color. Null (or non-solid) RefreshColor keeps the existing ComposePullToRefreshBox facade path; a non-null solid color switches to a hand-written ColoredIndicatorBox ComposableNode that calls PullToRefreshKt.PullToRefreshBox directly with a custom indicator IFunction3 invoking PullToRefreshDefaults.Instance.Indicator(...) with the packed color. Adds [InternalsVisibleTo("Microsoft.AndroidX.Compose.Maui")] to the Compose facade assembly so the Maui project can reach the internal ComposableLambdas/ComposableLambda0/BuildModifier helpers needed by ColoredIndicatorBox. RefreshViewHandler is now at 35 / 35 (100%) per docs/maui-coverage.md. The sample's RefreshPage now ships RefreshColor="#FF6B35" so the behaviour is exercised on-device. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/maui-coverage.md | 19 +- .../Pages/RefreshPage.xaml | 7 +- .../Handlers/RefreshViewHandler.cs | 183 ++++++++++++++++-- .../AssemblyInfo.cs | 11 ++ 4 files changed, 192 insertions(+), 28 deletions(-) create mode 100644 src/Microsoft.AndroidX.Compose/AssemblyInfo.cs diff --git a/docs/maui-coverage.md b/docs/maui-coverage.md index 24d3799e..db337bc7 100644 --- a/docs/maui-coverage.md +++ b/docs/maui-coverage.md @@ -1,6 +1,6 @@ # .NET MAUI ⇄ Microsoft.AndroidX.Compose.Maui backend coverage -Generated by `scripts/maui-coverage.cs` on 2026-06-12 22:58 UTC. +Generated by `scripts/maui-coverage.cs` on 2026-06-15 23:09 UTC. Pinned MAUI version: **10.0.20** (from `Directory.Build.targets`). @@ -15,14 +15,14 @@ collected transitively across base mappers (`ViewHandler.ViewMapper`, - **Stock MAUI handlers in scope**: 43 - **Handlers we override**: 24 (**55.8%**) -- **Property-mapper keys covered**: 883 / 1224 (**72.1%**) +- **Property-mapper keys covered**: 884 / 1224 (**72.2%**) ### Per-category coverage | Category | Handlers | Keys | | --- | --- | --- | | **Pages / Navigation** | 1/4 (25%) | 33/130 (25%) | -| **Containers** | 5/5 (100%) | 166/174 (95%) | +| **Containers** | 5/5 (100%) | 167/174 (96%) | | **Leaves** | 18/18 (100%) | 684/695 (98%) | | **Menus / Toolbar** | 0/7 (0%) | 0/1 (0%) | | **Shapes** | 0/1 (0%) | 0/41 (0%) | @@ -42,7 +42,7 @@ Sorted by category. ✅ = fully covered (100%), 🟡 = partial, ❌ = not implem | 🟡 | `BorderHandler` | Containers | `Border` | `BorderHandler` | 35 / 40 (88%) | | ✅ | `ContentViewHandler` | Containers | `ContentView`, `IContentView` | `ContentViewHandler` | 32 / 32 (100%) | | ✅ | `LayoutHandler` | Containers | `Layout` | `LayoutHandler` | 32 / 32 (100%) | -| 🟡 | `RefreshViewHandler` | Containers | `RefreshView` | `RefreshViewHandler` | 34 / 35 (97%) | +| ✅ | `RefreshViewHandler` | Containers | `RefreshView` | `RefreshViewHandler` | 35 / 35 (100%) | | 🟡 | `ScrollViewHandler` | Containers | `ScrollView` | `ScrollViewHandler` | 33 / 35 (94%) | | ✅ | `ActivityIndicatorHandler` | Leaves | `ActivityIndicator` | `ActivityIndicatorHandler` | 33 / 33 (100%) | | ✅ | `ButtonHandler` | Leaves | `Button` | `ButtonHandler` | 40 / 40 (100%) | @@ -116,7 +116,6 @@ dashed stroke patterns on `Border`). - **`RadioButtonHandler`** (92%) — missing: `CornerRadius`, `StrokeColor`, `StrokeThickness` - **`ScrollViewHandler`** (94%) — missing: `HorizontalScrollBarVisibility`, `VerticalScrollBarVisibility` - **`ImageHandler`** (97%) — missing: `IsAnimationPlaying` -- **`RefreshViewHandler`** (97%) — missing: `RefreshColor` - **`ImageButtonHandler`** (97%) — missing: `IsAnimationPlaying` - **`SliderHandler`** (97%) — missing: `ThumbImageSource` - **`LabelHandler`** (98%) — missing: `VerticalTextAlignment` @@ -454,13 +453,9 @@ Extra keys we map (no stock counterpart): -### 🟡 `RefreshViewHandler` — `RefreshView` +### ✅ `RefreshViewHandler` — `RefreshView` -Backed by `RefreshViewHandler`. **34 / 35 keys (97%)**. - -Missing keys: - -- [ ] `RefreshColor` +Backed by `RefreshViewHandler`. **35 / 35 keys (100%)**.
All stock keys @@ -483,7 +478,7 @@ Missing keys: - [x] `MinimumHeight` - [x] `MinimumWidth` - [x] `Opacity` -- [ ] `RefreshColor` +- [x] `RefreshColor` - [x] `Rotation` - [x] `RotationX` - [x] `RotationY` diff --git a/src/Microsoft.AndroidX.Compose.Maui.Sample/Pages/RefreshPage.xaml b/src/Microsoft.AndroidX.Compose.Maui.Sample/Pages/RefreshPage.xaml index 1d033fca..3c0d6b70 100644 --- a/src/Microsoft.AndroidX.Compose.Maui.Sample/Pages/RefreshPage.xaml +++ b/src/Microsoft.AndroidX.Compose.Maui.Sample/Pages/RefreshPage.xaml @@ -18,6 +18,7 @@ VerticalStackLayout folds into the parent Page composition. --> + the pull gesture even kicks off a refresh. + RefreshColor (above on the RefreshView) tints the + spinner glyph orange. -->
-### 🟡 `SliderHandler` — `Slider` +### ✅ `SliderHandler` — `Slider` -Backed by `SliderHandler`. **37 / 38 keys (97%)**. - -Missing keys: - -- [ ] `ThumbImageSource` +Backed by `SliderHandler`. **38 / 38 keys (100%)**.
All stock keys @@ -1328,7 +1323,7 @@ Missing keys: - [x] `Semantics` - [x] `Shadow` - [x] `ThumbColor` -- [ ] `ThumbImageSource` +- [x] `ThumbImageSource` - [x] `ToolTip` - [x] `Toolbar` - [x] `TranslationX` diff --git a/src/Microsoft.AndroidX.Compose.Maui.Sample/Pages/SlidersPage.xaml b/src/Microsoft.AndroidX.Compose.Maui.Sample/Pages/SlidersPage.xaml index d1a7bd71..91bd52de 100644 --- a/src/Microsoft.AndroidX.Compose.Maui.Sample/Pages/SlidersPage.xaml +++ b/src/Microsoft.AndroidX.Compose.Maui.Sample/Pages/SlidersPage.xaml @@ -59,6 +59,21 @@ x:Name="ColoredValueLabel" Text="value = 0" /> +
-### ❌ `NavigationViewHandler` — `NavigationPage` +### ✅ `NavigationViewHandler` — `NavigationPage` -_No Compose backend handler. Stock MAUI handler keeps the AppCompat backend._ +Backed by `NavigationPageHandler`. **31 / 31 keys (100%)**. -
Stock keys (not covered) +
All stock keys -- [ ] `AnchorX` -- [ ] `AnchorY` -- [ ] `AutomationId` -- [ ] `Background` -- [ ] `Border` -- [ ] `Clip` -- [ ] `ContainerView` -- [ ] `FlowDirection` -- [ ] `Height` -- [ ] `InputTransparent` -- [ ] `IsEnabled` -- [ ] `MaximumHeight` -- [ ] `MaximumWidth` -- [ ] `MinimumHeight` -- [ ] `MinimumWidth` -- [ ] `Opacity` -- [ ] `Rotation` -- [ ] `RotationX` -- [ ] `RotationY` -- [ ] `SafeAreaEdges` -- [ ] `Scale` -- [ ] `ScaleX` -- [ ] `ScaleY` -- [ ] `Semantics` -- [ ] `Shadow` -- [ ] `ToolTip` -- [ ] `Toolbar` -- [ ] `TranslationX` -- [ ] `TranslationY` -- [ ] `Visibility` -- [ ] `Width` +- [x] `AnchorX` +- [x] `AnchorY` +- [x] `AutomationId` +- [x] `Background` +- [x] `Border` +- [x] `Clip` +- [x] `ContainerView` +- [x] `FlowDirection` +- [x] `Height` +- [x] `InputTransparent` +- [x] `IsEnabled` +- [x] `MaximumHeight` +- [x] `MaximumWidth` +- [x] `MinimumHeight` +- [x] `MinimumWidth` +- [x] `Opacity` +- [x] `Rotation` +- [x] `RotationX` +- [x] `RotationY` +- [x] `SafeAreaEdges` +- [x] `Scale` +- [x] `ScaleX` +- [x] `ScaleY` +- [x] `Semantics` +- [x] `Shadow` +- [x] `ToolTip` +- [x] `Toolbar` +- [x] `TranslationX` +- [x] `TranslationY` +- [x] `Visibility` +- [x] `Width`
@@ -734,13 +728,9 @@ Extra keys we map (no stock counterpart):
-### 🟡 `EditorHandler` — `Editor` - -Backed by `EditorHandler`. **45 / 46 keys (98%)**. +### ✅ `EditorHandler` — `Editor` -Missing keys: - -- [ ] `VerticalTextAlignment` +Backed by `EditorHandler`. **46 / 46 keys (100%)**. Extra keys we map (no stock counterpart): @@ -791,19 +781,15 @@ Extra keys we map (no stock counterpart): - [x] `Toolbar` - [x] `TranslationX` - [x] `TranslationY` -- [ ] `VerticalTextAlignment` +- [x] `VerticalTextAlignment` - [x] `Visibility` - [x] `Width` -### 🟡 `EntryHandler` — `Entry` - -Backed by `EntryHandler`. **48 / 49 keys (98%)**. - -Missing keys: +### ✅ `EntryHandler` — `Entry` -- [ ] `VerticalTextAlignment` +Backed by `EntryHandler`. **49 / 49 keys (100%)**. Extra keys we map (no stock counterpart): @@ -857,7 +843,7 @@ Extra keys we map (no stock counterpart): - [x] `Toolbar` - [x] `TranslationX` - [x] `TranslationY` -- [ ] `VerticalTextAlignment` +- [x] `VerticalTextAlignment` - [x] `Visibility` - [x] `Width` @@ -1009,13 +995,9 @@ Backed by `IndicatorViewHandler`. **39 / 39 keys (100%)**. -### 🟡 `LabelHandler` — `Label` +### ✅ `LabelHandler` — `Label` -Backed by `LabelHandler`. **39 / 40 keys (98%)**. - -Missing keys: - -- [ ] `VerticalTextAlignment` +Backed by `LabelHandler`. **40 / 40 keys (100%)**. Extra keys we map (no stock counterpart): @@ -1060,19 +1042,15 @@ Extra keys we map (no stock counterpart): - [x] `Toolbar` - [x] `TranslationX` - [x] `TranslationY` -- [ ] `VerticalTextAlignment` +- [x] `VerticalTextAlignment` - [x] `Visibility` - [x] `Width` -### 🟡 `PickerHandler` — `Picker` - -Backed by `PickerHandler`. **40 / 41 keys (98%)**. - -Missing keys: +### ✅ `PickerHandler` — `Picker` -- [ ] `VerticalTextAlignment` +Backed by `PickerHandler`. **41 / 41 keys (100%)**. Extra keys we map (no stock counterpart): @@ -1119,7 +1097,7 @@ Extra keys we map (no stock counterpart): - [x] `Toolbar` - [x] `TranslationX` - [x] `TranslationY` -- [ ] `VerticalTextAlignment` +- [x] `VerticalTextAlignment` - [x] `Visibility` - [x] `Width` @@ -1169,12 +1147,11 @@ Backed by `ProgressBarHandler`. **33 / 33 keys (100%)**. ### 🟡 `RadioButtonHandler` — `RadioButton` -Backed by `RadioButtonHandler`. **36 / 39 keys (92%)**. +Backed by `RadioButtonHandler`. **37 / 39 keys (95%)**. Missing keys: - [ ] `CornerRadius` -- [ ] `StrokeColor` - [ ] `StrokeThickness`
All stock keys @@ -1209,7 +1186,7 @@ Missing keys: - [x] `ScaleY` - [x] `Semantics` - [x] `Shadow` -- [ ] `StrokeColor` +- [x] `StrokeColor` - [ ] `StrokeThickness` - [x] `TextColor` - [x] `ToolTip` @@ -1221,13 +1198,9 @@ Missing keys:
-### 🟡 `SearchBarHandler` — `SearchBar` - -Backed by `SearchBarHandler`. **46 / 47 keys (98%)**. - -Missing keys: +### ✅ `SearchBarHandler` — `SearchBar` -- [ ] `VerticalTextAlignment` +Backed by `SearchBarHandler`. **47 / 47 keys (100%)**. Extra keys we map (no stock counterpart): @@ -1281,7 +1254,7 @@ Extra keys we map (no stock counterpart): - [x] `Toolbar` - [x] `TranslationX` - [x] `TranslationY` -- [ ] `VerticalTextAlignment` +- [x] `VerticalTextAlignment` - [x] `Visibility` - [x] `Width` From d8c486e921c773838eace40ca83a3cb72bd4b2e9 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Tue, 16 Jun 2026 09:59:28 -0500 Subject: [PATCH 6/6] Regenerate maui-coverage.md after merging #278 PR #278 (Border dashed-stroke geometry) brought BorderHandler from 35/40 to 40/40. Refresh the per-handler table + summary so they match HEAD. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/maui-coverage.md | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/docs/maui-coverage.md b/docs/maui-coverage.md index 5223c794..a737508f 100644 --- a/docs/maui-coverage.md +++ b/docs/maui-coverage.md @@ -1,6 +1,6 @@ # .NET MAUI ⇄ Microsoft.AndroidX.Compose.Maui backend coverage -Generated by `scripts/maui-coverage.cs` on 2026-06-16 14:54 UTC. +Generated by `scripts/maui-coverage.cs` on 2026-06-16 14:59 UTC. Pinned MAUI version: **10.0.20** (from `Directory.Build.targets`). @@ -15,14 +15,14 @@ collected transitively across base mappers (`ViewHandler.ViewMapper`, - **Stock MAUI handlers in scope**: 43 - **Handlers we override**: 25 (**58.1%**) -- **Property-mapper keys covered**: 922 / 1224 (**75.3%**) +- **Property-mapper keys covered**: 927 / 1224 (**75.7%**) ### Per-category coverage | Category | Handlers | Keys | | --- | --- | --- | | **Pages / Navigation** | 2/4 (50%) | 64/130 (49%) | -| **Containers** | 5/5 (100%) | 167/174 (96%) | +| **Containers** | 5/5 (100%) | 172/174 (99%) | | **Leaves** | 18/18 (100%) | 691/695 (99%) | | **Menus / Toolbar** | 0/7 (0%) | 0/1 (0%) | | **Shapes** | 0/1 (0%) | 0/41 (0%) | @@ -39,7 +39,7 @@ Sorted by category. ✅ = fully covered (100%), 🟡 = partial, ❌ = not implem | ✅ | `NavigationViewHandler` | Pages / Navigation | `NavigationPage` | `NavigationPageHandler` | 31 / 31 (100%) | | ✅ | `PageHandler` | Pages / Navigation | `Page` | `PageHandler` | 33 / 33 (100%) | | ❌ | `TabbedViewHandler` | Pages / Navigation | `TabbedPage` | — | 0 / 31 (0%) | -| 🟡 | `BorderHandler` | Containers | `Border` | `BorderHandler` | 35 / 40 (88%) | +| ✅ | `BorderHandler` | Containers | `Border` | `BorderHandler` | 40 / 40 (100%) | | ✅ | `ContentViewHandler` | Containers | `ContentView`, `IContentView` | `ContentViewHandler` | 32 / 32 (100%) | | ✅ | `LayoutHandler` | Containers | `Layout` | `LayoutHandler` | 32 / 32 (100%) | | ✅ | `RefreshViewHandler` | Containers | `RefreshView` | `RefreshViewHandler` | 35 / 35 (100%) | @@ -111,7 +111,6 @@ Most often this is a non-trivial property we haven't wired up yet (`CharacterSpacing`, `Font`, `Padding` on `Button`; `CornerRadius`, dashed stroke patterns on `Border`). -- **`BorderHandler`** (88%) — missing: `StrokeDashOffset`, `StrokeDashPattern`, `StrokeLineCap`, `StrokeLineJoin`, `StrokeMiterLimit` - **`ScrollViewHandler`** (94%) — missing: `HorizontalScrollBarVisibility`, `VerticalScrollBarVisibility` - **`RadioButtonHandler`** (95%) — missing: `CornerRadius`, `StrokeThickness` - **`ImageHandler`** (97%) — missing: `IsAnimationPlaying` @@ -291,17 +290,9 @@ _No Compose backend handler. Stock MAUI handler keeps the AppCompat backend._ -### 🟡 `BorderHandler` — `Border` +### ✅ `BorderHandler` — `Border` -Backed by `BorderHandler`. **35 / 40 keys (88%)**. - -Missing keys: - -- [ ] `StrokeDashOffset` -- [ ] `StrokeDashPattern` -- [ ] `StrokeLineCap` -- [ ] `StrokeLineJoin` -- [ ] `StrokeMiterLimit` +Backed by `BorderHandler`. **40 / 40 keys (100%)**. Extra keys we map (no stock counterpart): @@ -338,11 +329,11 @@ Extra keys we map (no stock counterpart): - [x] `Shadow` - [x] `Shape` - [x] `Stroke` -- [ ] `StrokeDashOffset` -- [ ] `StrokeDashPattern` -- [ ] `StrokeLineCap` -- [ ] `StrokeLineJoin` -- [ ] `StrokeMiterLimit` +- [x] `StrokeDashOffset` +- [x] `StrokeDashPattern` +- [x] `StrokeLineCap` +- [x] `StrokeLineJoin` +- [x] `StrokeMiterLimit` - [x] `StrokeThickness` - [x] `ToolTip` - [x] `Toolbar`