[iOS] Fix FlyoutHeaderScroll device test regression#34932
[iOS] Fix FlyoutHeaderScroll device test regression#34932kubaflo merged 24 commits intodotnet:inflight/candidatefrom
Conversation
…otnet#32491) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Summary Fixes a critical bug where `HybridWebView.InvokeJavaScriptAsync` would timeout when passing JSON strings as parameters. The issue was caused by improper JavaScript string escaping. The fix extracts business logic into a new `HybridWebViewHelper` class and uses `WebViewHelper.EscapeJsString` for proper escaping. **Fixes**: dotnet#32438 --- ## The Problem Issue dotnet#32438 reported that passing JSON strings to `InvokeJavaScriptAsync` caused timeouts on Windows (required base64 encoding as workaround), while Android worked correctly. ### Root Cause The old `EvaluateJavaScriptAsync` implementation used naive string concatenation: ```csharp // OLD - Breaks when script contains quotes script = "try{eval('" + script + "')}catch(e){'null'};"; ``` When the script contained JSON with quotes, this produced invalid JavaScript: ```javascript try{eval('window.HybridWebView.__InvokeJavaScript(1, 'method', ["{\"userId\":\"value\"}"])')}catch(e){'null'}; ↑ BROKEN - conflicting quotes ``` Result: JavaScript execution failed, causing `InvokeJavaScriptAsync` to timeout. --- ## The Solution ### Core Fix New implementation properly escapes JavaScript strings: ```csharp // NEW - Uses proper escaping var escapedScript = WebViewHelper.EscapeJsString(script); var wrappedScript = $$""" (function() { try { let result = eval('{{escapedScript}}'); // ← Properly escaped return JSON.stringify({ IsError: false, Result: JSON.stringify(result) }); } catch (error) { // ... error handling } })() """; ``` ### Refactoring Extracted ~360 lines from `HybridWebViewHandler` into new `HybridWebViewHelper` class: - `ProcessEvaluateJavaScriptAsync` - Script wrapping with proper escaping - `ProcessInvokeJavaScriptAsync` - JavaScript call building - `ProcessInvokeDotNetAsync` - .NET method invocation from JS - `ProcessRawMessage` - Message routing Handler reduced from ~600 to 244 lines. --- ## Changes **New Files:** - ✨ `HybridWebViewHelper.cs` (470 lines) - Centralized business logic **Modified Files:** - 🔧 `HybridWebViewHandler.cs` - Delegates to helper - 🔧 `HybridWebViewHandler.Standard.cs` - Updated message processing - 🔧 `HybridWebViewHandler.Tizen.cs` - Updated message processing **Tests:** - 🔧 `HybridWebViewTestsBase.cs` - Added 15-second timeout - ✨ Added 5 new tests for JSON parameter scenarios - ✨ Added 3 enhanced quote-handling tests - 🔧 Renamed 20+ tests for clarity - 📝 Corrected error messages to use `InvokeJavaScriptAsync` **Test HTML:** - Added `EchoJsonParameter`, `ParseAndStringifyJson`, `ConcatenateJsonStrings`, `DecodeBase64AndEcho`, `CountJsonArrayItems` --- ## Testing **Platforms**: iOS, Android, Windows, MacCatalyst **Scenarios**: - JSON with quotes and special characters - Complex nested JSON - Multiple JSON parameters - Large arrays (100 items) - Base64 workaround (backward compatibility) --- ## Breaking Changes **None** - Fully backward compatible: - ✅ Existing code works unchanged - ✅ Base64 workaround still works - ✅ No public API changes ### Migration Note If using base64 workaround, you can now simplify: ```csharp // OLD workaround (still works): var json = JsonSerializer.Serialize(obj); var base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(json)); await hybridWebView.InvokeJavaScriptAsync<string>("fn", ..., [base64], ...); // NEW (now works directly): var json = JsonSerializer.Serialize(obj); await hybridWebView.InvokeJavaScriptAsync<string>("fn", ..., [json], ...); ``` --- ## Checklist - [x] Code follows .NET MAUI conventions - [x] 8 new/enhanced tests added - [x] 20+ tests renamed for clarity - [x] No breaking changes - [x] Backward compatible - [x] Error messages corrected - [x] Formatted with `dotnet format` - [x] XML documentation complete - [x] Tested on multiple platforms --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: mattleibow <1096616+mattleibow@users.noreply.github.com>
… on collection update (dotnet#31275) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Root Cause **Windows** Position not updating on item add: CarouselView stayed at the old position after an item was added, leaving current/previous positions unsynced. Cascading events: With `ItemsUpdatingScrollMode.KeepItemsInView`, programmatic smooth scrolls triggered multiple ViewChanged calls, causing `PositionChanged` to fire repeatedly with intermediate values. **Android** Programmatic smooth scrolls produced the same cascading `PositionChanged` events as on Windows. ### Description of Change **Windows** Position Update: On item add, `ItemsView.Position` is explicitly set based on `ItemsUpdatingScrollMode`, keeping current and previous positions in sync. Prevent Cascading Events: Added `_isInternalPositionUpdate`. For collection changes, animations are disabled (animate = false) so scrolling jumps directly, firing `PositionChanged` only once. **Android** Reused the `_isInternalPositionUpdate` logic. Disabled animations during collection changes, ensuring a single clean position update without duplicate events. ### Issues Fixed Fixes dotnet#29529 Tested the behaviour in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Screenshots | Before Issue Fix | After Issue Fix | |------------------|-----------------| | <img width="350" alt="withoutfix" src="https://github.com/user-attachments/assets/d66f0352-a91f-4b85-bb9f-e0e54e55aa5f" /> | <img width="350" alt="withfix" src="https://github.com/user-attachments/assets/d120f268-6954-498d-aab0-42bc3745e296" /> | ---------
…3953) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details On iOS/MacCatalyst 26+, when the app theme changes (light ↔ dark), the Switch's ThumbColor resets to white instead of keeping the custom color. ### Root Cause On iOS/MacCatalyst 26+, UIKit resets the UISwitch's ThumbTintColor to its default value during theme transitions. ### Description of Change Register for trait collection changes to detect theme switches, then re-apply the custom ThumbColor after UIKit completes its styling. Validated the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes dotnet#33783 Fixes dotnet#33767 ### Output ScreenShot |Before|After| |--|--| | <video src="https://github.com/user-attachments/assets/aa595096-4f75-4d7e-b31e-f1f0acc24208" >| <video src="https://github.com/user-attachments/assets/386f9e6e-6df7-40c5-a3e7-59a0bde31df6">|
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details WebView does not scroll when placed inside a ScrollView. The parent ScrollView intercepts vertical touch gestures, preventing the WebView from scrolling its internal content. ### Root Cause The parent ScrollView was intercepting all touch events without checking if the child WebView needed to scroll. This prevented the WebView from receiving touch events and handling its own scrolling. ### Description of Change Added touch event handling to prevent parent interception when WebView scrolls. When touch begins or continues, WebView requests exclusive control from parent. When touch ends or cancels, control returns to parent. This enables WebView scrolling while preserving normal parent-child interaction. Validated the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes dotnet#32971 ### Output ScreenShot |Before|After| |--|--| | <video src="https://github.com/user-attachments/assets/12b3ca6e-582d-4a50-9ea1-f49027f2d907" >| <video src="https://github.com/user-attachments/assets/2fbfd03c-4432-49e9-8b2d-6e7643f57487">|
… to null (dotnet#34741) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details On iOS and macCatalyst, setting BackgroundColor = null on an Entry or Editor at runtime does not restore the native default appearance. Once a custom color is applied, it persists even after the property is cleared. ### Root Cause The shared iOS background update logic only resets BackgroundColor = null for LayoutView subclasses — all other UIView types silently return. MauiTextField (Entry) and MauiTextView (Editor) are not LayoutView subclasses, so the reset is skipped. ### Description of Change Platform-specific MapBackground methods were added to EntryHandler.iOS.cs and EditorHandler.iOS.cs. When Background.IsNullOrEmpty(), they now explicitly set platformView.BackgroundColor = null to restore native appearance. Validated the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes dotnet#34611 ### Output ScreenShot |Before|After| |--|--| | <video src="https://github.com/user-attachments/assets/5ca30c6d-c069-4c04-989b-4dae36584cb4" >| <video src="https://github.com/user-attachments/assets/ee9e2a2e-c210-47cc-9f85-2526780d398b">| --------- Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
…t placed child to the Border control in iOS/ Mac platform (dotnet#33330) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Issue Details: Stacklayout is not rendered when clip is applied and StackLayout placed child to the Border control in iOS/ Mac platform. ### Root Cause: When the clip is applied to the StackLayout, its ContainerView (WrapperView) is being inserted at index 0 to its parent control Border, which places it below Border's background layer in the z-order. As a result, the stacklayout is not visible in the view in iOS and Mac platform. ### Description of Change: The wrapper view is brought to the front of its parent’s subview stack so it renders above the Border background in the Z order. **Tested the behavior in the following platforms.** - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Reference: N/A ### Issues Fixed: Fixes dotnet#33241 ### Screenshots | Before | After | |---------|--------| | <img width="369" height="606" alt="image" src="https://github.com/user-attachments/assets/0be8bc27-5de4-41ad-a41f-92581513ac55" /> | <img width="369" height="606" alt="image" src="https://github.com/user-attachments/assets/6a3590f6-2763-473a-aa91-ee1113e48ec3" /> |
…cription is set (dotnet#33979) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Root Cause WinUI `TextBlock` (used by `Label`) automatically exposes its `Text` to UI Automation. `ContentPanel` uses the default `FrameworkElementAutomationPeer`, which exposes both the parent’s `AutomationProperties.Name` and all child elements. Unlike Android (`NoHideDescendants`) or iOS (`AccessibilityElementsHidden`), Windows has no single property to hide descendants while keeping the parent accessible. As a result, both Tab navigation and Browse mode announced duplicate content. ### Description of Change Implemented a custom `ContentPanelAutomationPeer` that overrides three core UI Automation methods (GetAutomationControlTypeCore , `GetLocalizedControlTypeCore`, `GetChildrenCore`) to conditionally modify behavior when Description is present. When a Description exists, the control is exposed as `AutomationControlType.Text` (enables browse mode navigation; alternatives like Custom announce "custom" suffix, Group causes browse mode to skip the element), the "text" announcement suffix is suppressed via empty `GetLocalizedControlTypeCore()` return, and child elements are hidden by returning null from `GetChildrenCore()` to prevent duplication. When no Description is present, default behavior is preserved with `AutomationControlType.Custom` and children remain accessible. The `HasDescription` helper property centralizes the non-empty Description check across all three override methods, ensuring consistent conditional logic following the MAUI `AutomationPeer patterns. ### Issues Fixed Fixes dotnet#33373 ### Platforms Tested - [ ] iOS - [x] Android - [x] Windows - [x] Mac ### Screenshots | Before Fix | After Fix | |------------|-----------| | <video width="350" alt="withoutfix" src="https://github.com/user-attachments/assets/c5f8f114-fbeb-42d1-8601-e75dad57a1a7" /> | <video width="350" alt="withfix" src="https://github.com/user-attachments/assets/d2405df5-64f3-4cd9-8b38-40911ce4fbd6" /> | ---------
…#33459) <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Description of Change <img width="870" height="73" alt="image" src="https://github.com/user-attachments/assets/e27cb50d-db93-431b-831c-24f7faedf9b1" /> Invalidation propagation can be quite consuming especially when switching binding context and multiple properties change (i.e. having multiple labels inside a layout, all of them changing the text). Ti PR avoids useless propagations (same behavior `requestLayout` intrinsically has on Android).
…g lifecycle transition (dotnet#34901) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Description Fixes dotnet#34900 Replaces an opaque `NullReferenceException` with an informative `InvalidOperationException` in `ContainerView` when the Android `Context` is no longer available. ### Root Cause `IMauiContext.Context` (the Android `Context`) is stored via a `WeakReference` to the Activity. During lifecycle transitions (e.g., Activity being GC'd), this reference can become null. When `NavigationRootManager.Connect()` calls `view.ToContainerView(mauiContext)`, it creates a `ContainerView` whose base `LinearLayout` constructor receives a null `Context`, causing an NRE deep in the JNI interop layer. ### Fix Added a null-coalescing throw expression in the `ContainerView` constructor: ```csharp public ContainerView(IMauiContext context) : base(context.Context ?? throw new InvalidOperationException( "Unable to create a ContainerView: the Android Context is no longer available. " + "This can occur when the Activity has been collected during a lifecycle transition.")) ``` This provides a clear, actionable error message instead of the cryptic NRE that pointed at `NavigationRootManager.Connect` line 60. ### Stack trace from the original crash ``` [AndroidRuntime] at Microsoft.Maui.Platform.NavigationRootManager.Connect [AndroidRuntime] at Microsoft.Maui.Handlers.WindowHandler.CreateRootViewFromContent [AndroidRuntime] at Microsoft.Maui.Handlers.WindowHandler.MapContent ``` ---------
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Root Cause: CarouselView does not utilize the ItemSpacing property during layout styling ### Description of Change Added an item container style based on the horizontal or vertical orientation of the CarouselView, and applied a corresponding style to the ListViewBase <!-- Enter description of the fix in this section --> ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes dotnet#29772 ### Tested the behaviour in the following platforms - [x] Windows - [x] Android - [x] iOS - [x] Mac ### Screenshot | Before Issue Fix | After Issue Fix | |----------|----------| | <img src="https://github.com/user-attachments/assets/4af88696-c5a6-4683-bceb-1933781368f3"> | <img src="https://github.com/user-attachments/assets/f55c2b45-22c3-4ab2-aae5-c668adaf33e4"> | <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. -->
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Detail RadioButtonGroup is not functioning correctly when RadioButton controls are placed inside a ContentView in .NET 10. ### Root Cause PR [dotnet#32640](dotnet#32604) (fixing dotnet#32466) removed the coerceValue and Value = this initialiser from RadioButton, so RadioButton.Value now defaults to null. This introduced two distinct bugs in the ContentView+ControlTemplate scenario: - AddRadioButton guard object.Equals(radioButton.Value, this.SelectedValue) evaluates to object.Equals(null, null) == true, causing every button added via a ControlTemplate to be auto-checked immediately. - When the layout is not yet attached to a Page (common during ControlTemplate inflation), GetVisualRoot() returns null. The original fallback radioButton.Parent resolves to the button's immediate parent (Border), which only contains that single button — so other RadioButtons in the same group are never found and never unchecked. ### Description of Change - Updated the equality check in AddRadioButton to ensure comparison only happens when SelectedValue is not null. This avoids unintended selection during initialization. - Improved the root resolution logic in UncheckOtherRadioButtonsInScope. If no visual root is found, fallback to the RadioButtonGroupController’s layout (group container). ### Issue Fixed Fixes dotnet#34759 ### Screenshots | Before | After | |---------|--------| | <video src="https://github.com/user-attachments/assets/39e1e45d-dd04-42b7-bb85-aea83124b0cb"> | <video src="https://github.com/user-attachments/assets/252587b2-10ae-4eb9-968e-de114756aa0c"> | --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
### Description of Change I tried to improve the access time on BindableProperty given they're being accessed a lot during the application usage. As we can see using Array + SIMD is actually performing better when the number of BindableProperty set on a BindableObject is less than ~10, though it becomes worse after that. Array + SIMD also (obviously) allocates less memory. Considering that SIMD may perform differently on different platforms I felt it would be better to simply improve the current Dictionary based implementation by leveraging: - integer keys - CollectionMarshal on GetOrAdd ### Benchmarks | Strategy | PropertiesToSet | Mean | Error | StdDev | Gen0 | Gen1 | Allocated | |----------------------- |---------------- |------------:|---------:|---------:|-------:|-------:|----------:| | Dictionary<BindableProperty> | 1 | 65.22 ns | 0.246 ns | 0.218 ns | 0.0889 | 0.0001 | 744 B | | Array + SIMD | 1 | **52.93 ns** | 0.750 ns | 0.665 ns | 0.0678 | - | 568 B | | Dictionary<int,> | 1 | 59.29 ns | 0.563 ns | 0.440 ns | 0.0889 | 0.0001 | 744 B | | | | Dictionary<BindableProperty> | 3 | 150.70 ns | 0.344 ns | 0.322 ns | 0.1500 | 0.0005 | 1256 B | | Array + SIMD | 3 | **122.09 ns** | 0.163 ns | 0.127 ns | 0.1290 | 0.0002 | 1080 B | | Dictionary<int,> | 3 | 133.50 ns | 0.231 ns | 0.180 ns | 0.1500 | 0.0005 | 1256 B | | | | Dictionary<BindableProperty> | 8 | 426.76 ns | 0.686 ns | 0.641 ns | 0.3662 | 0.0033 | 3064 B | | Array + SIMD | 8 | **318.26 ns** | 0.438 ns | 0.409 ns | 0.3028 | 0.0024 | 2536 B | | Dictionary<int,> | 8 | 338.98 ns | 2.381 ns | 1.988 ns | 0.3662 | 0.0038 | 3064 B | | | | Dictionary<BindableProperty> | 15 | 773.49 ns | 2.593 ns | 2.298 ns | 0.5798 | 0.0095 | 4856 B | | Array + SIMD | 15 | 665.18 ns | 0.846 ns | 0.791 ns | 0.5531 | 0.0076 | 4632 B | | Dictionary<int,> | 15 | **581.04 ns** | 0.431 ns | 0.360 ns | 0.5798 | 0.0095 | 4856 B | | | | Dictionary<BindableProperty> | 30 | 1,542.20 ns | 3.342 ns | 3.126 ns | 1.1692 | 0.0381 | 9784 B | | Array + SIMD | 30 | 1,419.83 ns | 1.301 ns | 1.154 ns | 1.0796 | 0.0324 | 9032 B | | Dictionary<int,> | 30 | **1,165.86 ns** | 1.599 ns | 1.496 ns | 1.1692 | 0.0381 | 9784 B | | | | Dictionary<BindableProperty> | 50 | 2,648.69 ns | 3.759 ns | 2.935 ns | 2.0828 | 0.1183 | 17448 B | | Array + SIMD | 50 | 2,587.54 ns | 3.111 ns | 2.429 ns | 1.8196 | 0.0916 | 15224 B | | Dictionary<int,> | 50 | **1,997.17 ns** | 2.174 ns | 2.033 ns | 2.0828 | 0.1183 | 17448 B |
…otnet#33891) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Root Cause When a password `Entry` field is empty and text is programmatically set, the obfuscation logic calculates a negative insert position `(0 - 4 = -4)`. String. `Insert()` doesn't accept negative indices, causing an `ArgumentOutOfRangeException` crash in windows. ### Description of Change Added `Math.Max(0, ...)` to clamp the insert position to a minimum of 0, preventing negative **values.** ### Issues Fixed Fixes dotnet#33334 ### Platforms Tested - [x] iOS - [x] Android - [x] Windows - [x] Mac ### Screenshots | Before Fix | After Fix | |------------|-----------| | <img width="350" alt="withoutfix" src="https://github.com/user-attachments/assets/43993544-7700-4bff-a04c-d34b999ac962" /> | <img width="350" alt="withfix" src="https://github.com/user-attachments/assets/e7f12e20-1cd8-45e7-b07d-bfe7ebac6248" /> |
…eaving custom state (dotnet#33346) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Root Cause: The issue occurs because platform handlers on iOS and Android do not restore button properties to their default values when VisualState setters are removed. In .NET MAUI, when a control transitions from a custom VisualState back to the normal state, property values are set to null to indicate that defaults should be restored. However, the platform handlers interpreted these null values as instructions to take no action, causing previously applied custom values to remain. ### Fix Description: The fix involves updating button-specific extension methods to ensure properties are correctly restored to their platform default values when property values are null. For iOS, the UpdateBackground extension method now explicitly handles UIButton instances. When the background is null or empty, RemoveBackgroundLayer() is called first to prevent stacking gradient layers, and the background is reset to UIColor.Clear. This restores proper transparency and aligns with the default iOS button appearance. When a valid background is provided, the update continues through the existing view background logic. The UpdateTextColor method was also improved to restore the system default text color correctly when TextColor is null. If the button is attached to a UIWindow, the handler clears explicit overrides using SetTitleColor(null, …) for the Normal, Highlighted, and Disabled states, allowing iOS to fall back to its natural appearance-proxy behavior. It then restores TintColor using window.TintColor rather than a hardcoded system color. This ensures the app’s global tint is respected and prevents clearing appearance settings during the initial render phase. For Android, a MaterialButton-specific UpdateTextColor overload was introduced in MauiMaterialButton. The default Material theme ColorStateList is cached as DefaultTextColors during construction, before any MAUI property mapping occurs. When TextColor becomes null, the cached state list is restored directly, preserving all theme-defined states (normal, disabled, etc.). This approach avoids creating temporary controls and guarantees consistent restoration of the original Material theme colors. ### Issues Fixed Fixes dotnet#19690 ### Tested the behaviour in the following platforms - [x] Mac - [x] Windows - [x] iOS - [x] Android ### Output Screenshot | Platform | Before Fix | After Fix | |----------|----------|----------| | Android | <video src="https://github.com/user-attachments/assets/d96c404f-99b0-4dd2-bfdf-01adf629466e"> | <video src="https://github.com/user-attachments/assets/e85313ef-3155-42d3-a1bc-c1b6ef8587b0"> | |iOS | <video src="https://github.com/user-attachments/assets/416724b2-f8fe-4146-be56-12c3f6808693"> | <video src="https://github.com/user-attachments/assets/962ce83a-de7f-4ca0-8339-c8ce88e99288"> |
…tating the device with dialog open (dotnet#31910) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details - On Android, when opening a TimePicker and then rotating the device, the picker dialog doesn’t seem to redraw itself to match the new screen dimensions. ### Root Cause of the issue - TimePicker lacks orientation change detection entirely. When the device rotates while the dialog is open, TimePicker has no mechanism to dismiss and re-show the dialog with updated layout, unlike DatePicker which detects orientation changes and refreshes the dialog display. ### Description of Change - Added ConnectHandler and related event subscriptions (ViewAttachedToWindow/ViewDetachedFromWindow) to manage display info changes and cleanup when the view is attached or detached. This helps ensure the time picker dialog responds to device orientation changes and releases resources properly. - Implemented OnMainDisplayInfoChanged to dismiss and recreate the time picker dialog with the current time when the device orientation changes, preserving user selection progress. ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes dotnet#31658 ### Reference - [DatePickerHandler](https://github.com/dotnet/maui/blob/main/src/Core/src/Handlers/DatePicker/DatePickerHandler.Android.cs) ### Tested the behaviour in the following platforms - [ ] - Windows - [x] - Android - [ ] - Mac - [x] - iOS ### Output | Before | After | |----------|----------| | <video src="https://github.com/user-attachments/assets/55091d04-0aa3-4794-aab8-fb5dfc71624e"> | <video src="https://github.com/user-attachments/assets/56c01750-00a1-4c63-8788-ca6c35d7dbd5"> | <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. -->
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Issue details Changing the Location property on a Microsoft.Maui.Controls.Maps.Pin does not change the location of the Pin on the map. ### Root cause `MapPinHandler.Android.cs` was only updating the `MarkerOptions` object when the Location property changed The actual `Marker` object already added to the map was not being updated, causing the pin to stay in its original location <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Description of change * **Improved marker association logic**: Updated the `AddPins` method in `MapHandler` to store marker references in the `MapPinHandler` for future property updates, ensuring tighter integration between pins and markers. Validated the behaviour in the following platforms - [x] Android - [ ] Windows - [ ] iOS - [ ] Mac ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes dotnet#12916 <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. --> ### Output | Before| After| |--|--| | <video src="https://github.com/user-attachments/assets/83bedab7-846b-41c1-872e-b6e0d0cd81a4"> | <video src="https://github.com/user-attachments/assets/fd86fd38-6619-4cf9-999a-de9d05b21e17"> | --------- Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
…#34687) ## Description Fixes dotnet#19866 On iOS, tapping the status bar should scroll the topmost `UIScrollView` to the top. This was not working for `CollectionView`, particularly when hosted inside a `Shell`. ## Root Cause iOS disables its scroll-to-top behavior when **multiple** `UIScrollView` instances in the view hierarchy have `scrollsToTop = true`. The Shell flyout's internal `AccessibilityNeutralTableView` (a `UITableView` subclass) defaults `scrollsToTop` to `true`, conflicting with the `CollectionView`'s `UICollectionView`. ## Fix Two changes: 1. **`ItemsViewController2.ViewDidLoad()`** — Explicitly set `CollectionView.ScrollsToTop = true` to opt in to scroll-to-top behavior 2. **`ShellTableViewController.AccessibilityNeutralTableView`** — Set `ScrollsToTop = false` on Shell's flyout table view to prevent the multi-scroll-view conflict This follows the existing codebase pattern where `ScrollsToTop` is explicitly managed (e.g., `ShellSectionRootHeader` and `ContextActionCell` both set it to `false`). ## Validation Verified with a Sandbox app using a grouped `CollectionView` inside a `Shell` with `TabBar`: - **Without fix**: Diagnostic dump shows two scroll views with `scrollsToTop=True` → status bar tap does nothing - **With fix**: Only `MauiCollectionView` has `scrollsToTop=True` → status bar tap scrolls to top correctly --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ht space above the tab bar even if the page title is empty (dotnet#30382) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Root cause The root cause of this issue is that the Windows Shell implementation always reserves space for the header area when Shell.FlyoutBehavior="Flyout" is set, even when pages have no title or header content. The NavigationView control allocates a fixed height above the tab bar for the header region without checking if the current page actually needs this space. This results in an unwanted gap between the flyout toggle area and the tab bar when navigating to pages with empty titles, creating visual inconsistency compared to FlyoutBehavior="Disabled" mode where no header space is reserved for empty content. ### Description of Issue Fix The fix involves adding header visibility logic to the Windows Shell implementation to remove unwanted space above the tab bar in flyout mode. The implementation introduces three key methods in RootNavigationView.cs: UpdateHeaderVisibility() to evaluate header visibility requirements, IsHeaderContentEmpty() to determine if the toolbar contains no title or title view when in flyout mode, and CollapseEmptyHeader() to properly hide empty headers. The toolbar property setter now calls UpdateHeaderVisibility() when the toolbar changes, and ShellView.cs triggers header visibility updates during tab navigation. This ensures empty headers don't occupy unnecessary space in flyout mode while maintaining normal behavior when headers contain content, resolving the spacing issue above the tab bar when switching between pages in Shell applications on Windows. Tested the behavior in the following platforms. - [x] Windows - [x] Mac - [x] iOS - [x] Android ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes dotnet#30254 <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. --> ### Resaved Test snapshots Resaved the below test snapshot because the ContentPage did not have a title. So, resaved the test snapshot based on the fix. 1. ShellFlowDirectionUpdate 2. VerifyFlyoutBackgroundColor 3. VerifyHamburgerIcon 4. Issue23834FlyoutMisbehavior ### Output | Before Issue Fix | After Issue Fix | |----------|----------| | <video width="270" height="600" src="https://github.com/user-attachments/assets/ca496f96-2500-429f-8720-a8adb7925fce"> | <video width="270" height="600" src="https://github.com/user-attachments/assets/1f0dedd2-4808-46bf-98cf-843ca70294ef"> |
…forms (dotnet#30369) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Detail The FlowDirection property is not respected by the TimePicker control. Setting FlowDirection="RightToLeft" has no visual effect on the control across any platform. ### Root Cause iOS: The MapFlowDirection method incorrectly used the concrete TimePickerHandler type instead of the ITimePickerHandler interface. This bypassed platform-specific logic and defaulted to ViewHandler.MapFlowDirection, which lacked the necessary text alignment handling. Android: The FlowDirection property was not correctly mapped to the native implementation, resulting in incorrect or missing text alignment updates. ### Description of Change iOS: Updated the MapFlowDirection method to use the correct handler interface. Implemented alignment logic in TimePickerExtensions.cs using EffectiveFlowDirection to properly align text for both RTL and LTR layouts. Android: Implemented a platform-specific MapFlowDirection method in TimePickerHandler.Android.cs: For 12-hour format, UpdateTextAlignment is applied to align localized "AM/PM" text based on FlowDirection. For 24-hour format, alignment is handled via UpdateFlowDirection, which sets LayoutDirection and TextDirection to align purely numeric content Validated the behaviour in the following platforms - [x] Android - [ ] Windows dotnet#30322 - [x] iOS - [ ] Mac dotnet#30322 ### Issues Fixed: Fixes dotnet#30192 ### Screenshots | Before | After | |---------|--------| | <img src="https://github.com/user-attachments/assets/37c4a442-1011-4c23-bc2e-8743bc11adc7"> | <img src="https://github.com/user-attachments/assets/91b69287-b8eb-4d40-b8a1-0734ef1f89db"> |
|
/azp run maui-pr-uitests , maui-pr-devicetests |
|
Azure Pipelines successfully started running 2 pipeline(s). |
…for HTML labels (dotnet#34934) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description of Change Fixes the `CharacterSpacingWithLineHeightWithTextDecorationsWorksCorrectly` device test regression introduced by PR dotnet#31202. PR dotnet#31202 changed the Label mapper conditions from `!IsPlainText(label)` to `label.HasFormattedTextSpans` for `MapLineHeight`, `MapTextDecorations`, and `MapCharacterSpacing`. This correctly enables these properties to be applied to HTML labels (`TextType.Html`), since `HasFormattedTextSpans` only returns true for `FormattedText` with spans — not for HTML. However, the test expectations for `label4` (an HTML label with `CharacterSpacing=5`, `LineHeight=1.5`, `TextDecorations=Underline`) were not updated and still expected `(0, 0, None)`. **Fix:** Update expected values for label4 from `(0, 0, None)` to `(5, 1.5, Underline)` to match the new behavior. ### Issues Fixed Fixes CharacterSpacingWithLineHeightWithTextDecorationsWorksCorrectly device test regression from dotnet#31202 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…dotnet#26217) ### Root cause The issue arises because the OnNavigationViewSizeChanged method fails to properly reset the layout measurements before arranging the NavigationView. As a result, the NavigationView does not correctly update its layout in response to size changes, causing misalignment or rendering issues in the ScrollView. ### Description of Issue Fix The fix involves updating the OnNavigationViewSizeChanged() method to include a call to InvalidateMeasure() before arranging the NavigationView. This ensures that the layout is accurately recalculated, allowing the ScrollView and other elements within the TabbedPage to be properly measured and arranged during the subsequent layout cycle. This effectively resolves alignment and rendering issues. Additionally, the Arrange() call is retained within the SizeChanged handler to prevent test failures, specifically avoiding timeout issues observed in the ChangingToNewMauiContextDoesntCrash test. This combination ensures stable layout behavior while resolving the clipping and scrolling issues that occur after window resizing. ### Why Tests were not added: **Regarding the test case:** The issue only occurs when resizing the window, so it is not possible to add a test case for the window resizing behavior. Tested the behavior in the following platforms. - [x] Windows - [x] Mac - [x] iOS - [x] Android ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes dotnet#26103 Fixes dotnet#11402 Fixes dotnet#20028 <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. --> ### Resaved Test snapshots Resaved the below-mentioned test snapshot because elements in the TabbedPage were not properly aligned before the fix. The layout changes in OnNavigationViewSizeChanged (adding Arrange() after InvalidateMeasure()) now ensure proper element alignment within the TabbedPage. 1. DefaultSelectedTabTextColorShouldApplyProperly 2. FontImageSourceColorShouldApplyOnTabIcon 3. VerifyTabbedPageMenuItemTextColor 4. DynamicFontImageSourceColorShouldApplyOnTabIcon 5. Issue1323Test 6. TabBarIconsShouldAutoscaleTabbedPage ### Output | Before Issue Fix | After Issue Fix | |----------|----------| | <video width="270" height="600" src="https://github.com/user-attachments/assets/67d34cc9-323c-4a8d-afc6-dbcceb558ee5"> | <video width="270" height="600" src="https://github.com/user-attachments/assets/0ddb5ce5-300a-4088-98f4-f9a3981d6951"> | ---------
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Root Cause: The UpdateCharacterSpacing method didn't apply spacing to the individual text blocks in TimePicker ### Description of Change Enhanced the UpdateCharacterSpacing method to apply CharacterSpacing to individual text blocks (HourTextBlock, MinuteTextBlock, and PeriodTextBlock) within the TimePicker. This ensures the property works correctly even when the control is loaded asynchronously. <!-- Enter description of the fix in this section --> ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes dotnet#30199 ### Tested the behaviour in the following platforms - [x] Windows - [x] Android - [x] iOS - [ ] Mac ### Screenshot | Before Issue Fix | After Issue Fix | |----------|----------| | <img width="1217" height="915" alt="beforeFix30199" src="https://github.com/user-attachments/assets/0b955bf7-5e75-48d3-8455-3fe0cf2c0c5b"> | <img width="1261" height="946" alt="Screenshot 2025-07-10 155258" src="https://github.com/user-attachments/assets/5d2d8a34-fb01-4c58-9fef-be3ad10b7cb0"> | <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. --> ---------
…tnet#34383) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Root Cause: HTML text is applied asynchronously in .NET MAUI on iOS, causing the CollectionView cell to render first and then re-measure after the HTML is applied, which leads to visible resizing (scroll jitter). ### Description of Change Improvements to HTML text handling in CollectionView: * Updated `UpdateText` method in `LabelExtensions.cs` to check if the `UILabel` is inside a CV2 cell using the new `IsPlatformLabelInsideCV2Cell` method, allowing synchronous HTML text updates when safe and avoiding unnecessary layout passes. * Added the `IsPlatformLabelInsideCV2Cell` helper method to walk the UIKit superview chain and detect CV2 cells, improving reliability and preventing crashes in CV1 layouts. * Added a reference to `Microsoft.Maui.Controls.Handlers.Items2` to support the new CV2 cell detection logic. <!-- Enter description of the fix in this section --> ### Why Tests were not added: This bug occurs only during live scrolling of CollectionView cells on iOS when a Label with TextType="Html" is rendered. The issue depends on the precise timing of asynchronous HTML text application, which triggers a second layout pass while cells are visible, causing scroll jitter. Automated tests cannot reliably reproduce this because no framework can simulate real-time scrolling and layout timing at the native speed ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes dotnet#33065 ### Tested the behavior in the following platforms - [x] Windows - [x] Android - [x] iOS - [x] Mac | Before Issue Fix | After Issue Fix | |----------|----------| | <video src="https://github.com/user-attachments/assets/1045cbe3-e869-4e08-9562-8032dd9cea88"> | <video src="https://github.com/user-attachments/assets/0c7b3bbb-4917-482f-ac7e-05e343de3ae0"> | <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. -->
ab9d59b to
096f301
Compare
|
🚀 Dogfood this PR with:
curl -fsSL https://github.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 34932Or
iex "& { $(irm https://github.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 34932" |
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Fixes an iOS Shell flyout header measurement regression affecting FlyoutHeaderScroll-style scenarios, and additionally includes a broad set of framework/runtime, handler, SourceGen, test, and sample updates across multiple platforms.
Changes:
- Adjusts iOS Shell flyout header measurement invalidation to cooperate with scroll-driven header resizing.
- Introduces an
x:CodeXAML SourceGen pipeline (parsing + code emission) gated behind preview features andx:Class. - Adds/updates numerous cross-platform fixes and test coverage (VSM specificity, RadioButton semantics/grouping, ItemsView selection/recycling, WebView2 disposal hardening, etc.), plus some sample/docs/build changes.
Reviewed changes
Copilot reviewed 1 out of 1 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Controls/tests/TestCases.HostApp/Issues/Issue21983.xaml.cs | Adds HostApp issue page code-behind for Shape stroke gradient repro. |
| src/Controls/tests/TestCases.HostApp/Issues/Issue21983.xaml | Adds XAML repro for gradient Stroke on shapes. |
| src/Controls/tests/TestCases.HostApp/Issues/Issue20991.cs | Adds HostApp repro for binding support with IDrawable. |
| src/Controls/tests/TestCases.HostApp/Issues/Issue20348.cs | Adds HostApp repro for Android SearchBar text transfer after back nav. |
| src/Controls/tests/TestCases.HostApp/Issues/Issue20062.cs | Adds HostApp repro for CollectionView selected VSM on Android. |
| src/Controls/tests/TestCases.HostApp/Issues/Issue19866.cs | Adds HostApp repro for iOS status-bar tap scroll-to-top behavior. |
| src/Controls/tests/TestCases.HostApp/Issues/Issue19690.cs | Adds HostApp repro for Button VisualStates issues. |
| src/Controls/tests/TestCases.HostApp/Issues/Issue19168.cs | Adds HostApp repro for iOS/macOS Picker dismissal behavior. |
| src/Controls/tests/TestCases.HostApp/Issues/Issue18657.cs | Adds HostApp repro for CollectionView EmptyView removal on UWP/Windows. |
| src/Controls/tests/TestCases.HostApp/Issues/Issue18200.cs | Adds HostApp repro for Windows FlyoutPage collapse style changes. |
| src/Controls/tests/TestCases.HostApp/Issues/Issue11404.cs | Adds HostApp repro for Shape/Line coordinate/bounds correctness. |
| src/Controls/tests/TestCases.HostApp/Issues/Issue10987.cs | Adds HostApp repro for Editor horizontal alignment behavior. |
| src/Controls/tests/TestCases.HostApp/FeatureMatrix/Slider/SliderViewModal.cs | Adds VM properties for Slider ValueChanged event reporting. |
| src/Controls/tests/TestCases.HostApp/FeatureMatrix/Slider/SliderControlPage.xaml.cs | Hooks ValueChanged and resets status when navigating to options. |
| src/Controls/tests/TestCases.HostApp/FeatureMatrix/ScrollView/ScrollViewViewModel.cs | Adds VM properties to surface ScrollToRequested details. |
| src/Controls/tests/TestCases.HostApp/FeatureMatrix/ScrollView/ScrollViewControlPage.xaml.cs | Records ScrollToRequested event args into the VM. |
| src/Controls/tests/TestCases.HostApp/FeatureMatrix/ScrollView/ScrollViewControlPage.xaml | Adds UI to display ScrollToRequested state/args. |
| src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj | Adds a logical name mapping for challenge images. |
| src/Controls/tests/DeviceTests/Resources/Raw/HybridTestRoot/index.html | Adds JS helpers for JSON-string argument scenarios. |
| src/Controls/tests/DeviceTests/Elements/Shell/ShellTests.iOS.cs | Adds device test ensuring flyout table view ScrollsToTop is disabled. |
| src/Controls/tests/DeviceTests/Elements/RadioButton/RadioButtonTests.cs | Adds device tests for templated RadioButton semantics description behavior. |
| src/Controls/tests/DeviceTests/Elements/Label/LabelTests.iOS.cs | Updates label spacing/lineheight data for a test case. |
| src/Controls/tests/DeviceTests/Elements/HybridWebView/HybridWebViewTests_SetInvokeJavaScriptTarget.cs | Updates expected JSON escaping in test data. |
| src/Controls/tests/DeviceTests/Elements/HybridWebView/HybridWebViewTests_EvaluateJavaScriptAsync.cs | Splits EvaluateJavaScript tests by parameter type and quoting cases. |
| src/Controls/tests/DeviceTests/Elements/HybridWebView/HybridWebViewTestsBase.cs | Adds a 15s timeout wrapper around test execution. |
| src/Controls/tests/DeviceTests/Elements/Entry/EntryTests.cs | Adds device tests for long text and MaxLength/Text ordering. |
| src/Controls/tests/DeviceTests/Elements/Entry/EntryTests.Windows.cs | Adds Windows regression test for password text setting from empty. |
| src/Controls/tests/DeviceTests/Elements/Editor/EditorTests.iOS.cs | Adds iOS test for Editor placeholder horizontal text alignment. |
| src/Controls/tests/DeviceTests/Elements/ContentView/ContentViewTests.Windows.cs | Adds Windows tests around Narrator/automation peer behavior. |
| src/Controls/tests/DeviceTests/Elements/CollectionView/CollectionViewTests.iOS.cs | Adds iOS test for ScrollsToTop and a CarouselView indicator visibility test. |
| src/Controls/tests/DeviceTests/Elements/CarouselView/CarouselViewTests.cs | Removes Android exclusion for a disconnect regression test. |
| src/Controls/tests/DeviceTests/Elements/CarouselView/CarouselViewTests.Android.cs | Adds Android accessibility description test for IndicatorView dots. |
| src/Controls/tests/Core.UnitTests/VisualStateManagerTests.cs | Adds VSM specificity regression tests (#34363, custom-state behavior). |
| src/Controls/tests/Core.UnitTests/SolidColorBrushTests.cs | Adds Brush.HasTransparency tests for SolidColorBrush. |
| src/Controls/tests/Core.UnitTests/RadioButtonTests.cs | Adds RadioButton group tests for ControlTemplate/ContentView scenarios. |
| src/Controls/tests/Core.UnitTests/RadialGradientBrushTests.cs | Adds Brush.HasTransparency tests for RadialGradientBrush. |
| src/Controls/tests/Core.UnitTests/LinearGradientBrushTests.cs | Adds Brush.HasTransparency tests for LinearGradientBrush. |
| src/Controls/tests/Core.UnitTests/BindablePropertyUnitTests.cs | Adds unit test for CollectionView header unwrapping of OnPlatform. |
| src/Controls/tests/Core.UnitTests/AlertManagerTests.cs | Updates tests for new alert manager abstraction and DI resolution. |
| src/Controls/src/Xaml/XmlName.cs | Adds x:Code XmlName constant. |
| src/Controls/src/SourceGen/XamlGenerator.cs | Adds x:Code extraction/emission pipeline and feeds it into compilation. |
| src/Controls/src/SourceGen/XCodeCodeWriter.cs | New code writer for generating partial class members from x:Code blocks. |
| src/Controls/src/SourceGen/Visitors/SetPropertiesVisitor.cs | Ignores x:Code in property visitor handling. |
| src/Controls/src/SourceGen/TrackingNames.cs | Adds tracking names for the x:Code pipeline. |
| src/Controls/src/SourceGen/InitializeComponentCodeWriter.cs | Strips x:Code elements from node tree before IC generation. |
| src/Controls/src/SourceGen/GeneratorHelpers.cs | Adds x:Code extraction logic and helper to detect x:Code elements. |
| src/Controls/src/SourceGen/Descriptors.cs | Adds diagnostics for x:Code constraints (child-of-root, requires x:Class). |
| src/Controls/src/SourceGen/AnalyzerReleases.Unshipped.md | Documents new MAUIX2015/MAUIX2016 diagnostics. |
| src/Controls/src/Core/Window/Window.cs | Makes Window alert manager DI-resolvable and manages subscribe lifecycle. |
| src/Controls/src/Core/VisualStateManager.cs | Adjusts VSM specificity application/unapplication for system-driven states. |
| src/Controls/src/Core/VisualElement/VisualElement.cs | Exposes internal explicit IsEnabled state and adjusts Loaded wiring. |
| src/Controls/src/Core/VisualElement/VisualElement.Platform.cs | Handles Loaded/Unloaded when hosted in native container via ToPlatform. |
| src/Controls/src/Core/TabbedPage/TabbedPage.Windows.cs | Adjusts size-changed handling to invalidate measure and arrange properly. |
| src/Controls/src/Core/Style.cs | Unapplies BasedOn style before applying as base style. |
| src/Controls/src/Core/Shell/ShellItem.cs | Uses ShellContent as effective value source for TabBar visibility if set. |
| src/Controls/src/Core/Shell/ShellElementCollection.cs | Propagates TabBarIsVisible changes from ShellContent to displayed page. |
| src/Controls/src/Core/Shapes/Shape.cs | Improves Stretch.None translation logic to fit within view bounds. |
| src/Controls/src/Core/SetterSpecificity.cs | Adds helper to promote implicit VSM specificity to full VSM priority. |
| src/Controls/src/Core/Setter.cs | Improves TargetName resolution across namescope boundaries (templates). |
| src/Controls/src/Core/RadioButton/RadioButtonGroupController.cs | Fixes auto-check behavior when SelectedValue is null. |
| src/Controls/src/Core/RadioButton/RadioButtonGroup.cs | Improves group root selection when no Page ancestor exists yet. |
| src/Controls/src/Core/RadioButton/RadioButton.cs | Improves semantics description extraction from templated content. |
| src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt | Adds new alert manager interfaces to public API list. |
| src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt | Adds new alert manager interfaces to public API list. |
| src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt | Adds alert manager interfaces + a CarouselViewHandler signature entry. |
| src/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txt | Adds new alert manager interfaces to public API list. |
| src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt | Adds new alert manager interfaces + other iOS/mac changes to API list. |
| src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt | Adds new alert manager interfaces + other iOS changes to API list. |
| src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt | Adds alert manager interfaces + other Android changes to API list. |
| src/Controls/src/Core/PlatformConfiguration/WindowsSpecific/FlyoutPage.cs | Adds property-changed callback to update handler for CollapseStyle. |
| src/Controls/src/Core/Platform/iOS/Extensions/LabelExtensions.cs | Avoids async HTML update in CV2; keeps async dispatch for CV1. |
| src/Controls/src/Core/Platform/iOS/ControlsModalWrapper.cs | Uses brush transparency (Background) to select modal presentation style. |
| src/Controls/src/Core/Platform/Windows/Extensions/AutoSuggestBoxExtensions.cs | Adds helpers to map SearchHandler properties to AutoSuggestBox. |
| src/Controls/src/Core/Platform/Windows/CollectionView/ItemContentControl.cs | Fixes logical tree reattachment and selection equality checks. |
| src/Controls/src/Core/Platform/ModalNavigationManager/ModalNavigationManager.Android.cs | Uses DismissNow for batch modal pops; forwards modal touch events. |
| src/Controls/src/Core/Platform/GestureManager/GesturePlatformManager.Android.cs | Adds RecyclerView touch listener path and lifecycle cleanup. |
| src/Controls/src/Core/Platform/AlertManager/IAlertManagerSubscription.cs | New public interface for alert subscription backend. |
| src/Controls/src/Core/Platform/AlertManager/IAlertManager.cs | New public interface for alert manager abstraction. |
| src/Controls/src/Core/Platform/AlertManager/AlertManager.cs | Makes AlertManager implement IAlertManager; removes nested subscription interface. |
| src/Controls/src/Core/Label/Label.iOS.cs | Updates iOS formatting map to include line height/decorations/spacing. |
| src/Controls/src/Core/Label/Label.cs | Improves measure invalidation for empty/non-empty transitions. |
| src/Controls/src/Core/Label/Label.Mapper.cs | Avoids applying certain maps when formatted spans exist. |
| src/Controls/src/Core/Items/MarshalingObservableCollection.cs | Uses weak proxy and adds explicit Dispose to unsubscribe. |
| src/Controls/src/Core/Handlers/Shell/Windows/ShellView.cs | Updates header visibility on tab selection changes. |
| src/Controls/src/Core/Handlers/Shell/ShellItemHandler.Windows.cs | Improves SearchHandler ↔ AutoSuggestBox mapping and cancel button coloring. |
| src/Controls/src/Core/Handlers/Items2/iOS/StructuredItemsViewController2.cs | Updates flow direction for default header/footer cells. |
| src/Controls/src/Core/Handlers/Items2/iOS/ReorderableItemsViewDelegator2.cs | Consolidates grouped-move logic into shared helper. |
| src/Controls/src/Core/Handlers/Items2/iOS/ItemsViewController2.cs | Enables ScrollsToTop and refines flow direction update logic. |
| src/Controls/src/Core/Handlers/Items2/CarouselViewHandler2.iOS.cs | Fixes ScrollToRequested cast and updates swipe enabled mapping. |
| src/Controls/src/Core/Handlers/Items/iOS/ReorderableItemsViewExtensions.cs | New shared helper for grouped reorder move target index calculation. |
| src/Controls/src/Core/Handlers/Items/iOS/ReorderableItemsViewDelegator.cs | Uses shared grouped-move helper for CV1. |
| src/Controls/src/Core/Handlers/Items/iOS/MauiCollectionView.cs | Intercepts AddSubview to apply swipe enabled to internal scrollers. |
| src/Controls/src/Core/Handlers/Items/iOS/CarouselViewController.cs | Adds guards for invalid indexes and out-of-range scroll targets. |
| src/Controls/src/Core/Handlers/Items/StructuredItemsViewHandler.Windows.cs | Cleans up header/footer realized views when removed. |
| src/Controls/src/Core/Handlers/Items/SelectableItemsViewHandler.Windows.cs | Uses value equality for selection comparisons. |
| src/Controls/src/Core/Handlers/Items/ItemsViewHandler.Windows.cs | Refactors EmptyView removal and template realization behavior. |
| src/Controls/src/Core/Handlers/Items/Android/TemplatedItemViewHolder.cs | Re-realizes content when handler was disconnected during recycle. |
| src/Controls/src/Core/Handlers/Items/Android/SimpleItemTouchHelperCallback.cs | Changes reorder move filtering logic. |
| src/Controls/src/Core/Handlers/Items/Android/MauiRecyclerView.cs | Respects inherited IsEnabled differently via explicit enabled state. |
| src/Controls/src/Core/Handlers/Items/Android/ItemsSources/ObservableItemsSource.cs | Optionally disposes the wrapped items source on disposal. |
| src/Controls/src/Core/Handlers/Items/Android/ItemsSources/ItemsSourceFactory.cs | Enables disposal for MarshalingObservableCollection wrapper. |
| src/Controls/src/Core/Handlers/Items/Android/Adapters/SelectableItemsViewAdapter.cs | Forces platform selection sync for Single mode after click. |
| src/Controls/src/Core/Handlers/Items/Android/Adapters/ReorderableItemsViewAdapter.cs | Adds bounds checks for source/target indices in item moves. |
| src/Controls/src/Core/GraphicsView/GraphicsView.cs | Propagates binding context to bindable Drawable and hooks propertyChanged. |
| src/Controls/src/Core/FlyoutPage/FlyoutPage.Mapper.cs | Adds Windows mapping for collapse style; preserves iOS mappings. |
| src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/SlideFlyoutTransition.cs | Adjusts RTL locked flyout framing logic. |
| src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellTableViewSource.cs | Resolves FlowDirection for disconnected Shell menu cell view trees. |
| src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellTableViewController.cs | Disables ScrollsToTop for flyout table view. |
| src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellSectionRootRenderer.cs | Resolves MatchParent flow direction for tracked page. |
| src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellSectionRenderer.cs | Updates tab bar flow direction in shell section renderer. |
| src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellPageRendererTracker.cs | Fixes page visibility state when swapping pages before animation. |
| src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellFlyoutHeaderContainer.cs | Fixes header measurement invalidation to avoid fighting layout manager. |
| src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellFlyoutContentRenderer.cs | Updates flow direction for header/footer and resolves header MatchParent flow. |
| src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellToolbarTracker.cs | Adjusts back button icon logic and clears search UI state on handler swap. |
| src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellItemRenderer.cs | Requests insets after tab bar gone→visible transition to fix padding. |
| src/Controls/src/Core/Brush/Brush.cs | Adds internal HasTransparency helper for brush transparency detection. |
| src/Controls/src/Core/BindableProperty.cs | Adds InternalId and adjusts conversion logic for wrapped values. |
| src/Controls/src/Core/BindableObject.cs | Switches property context storage to int key map and uses CollectionsMarshal. |
| src/Controls/samples/Controls.Sample/Pages/Controls/MapsGalleries/MapPinsGallery.xaml.cs | Adds move-pin support and map recentering in sample. |
| src/Controls/samples/Controls.Sample/Pages/Controls/MapsGalleries/MapPinsGallery.xaml | Adds Move Pin button to maps sample. |
| src/Controls/Maps/src/AppHostBuilderExtensions.cs | Updates Windows maps documentation and removes Windows NotImplementedException path. |
| src/BlazorWebView/src/Wpf/BlazorWebView.cs | Marks WebView2 manager as disposing before async cleanup. |
| src/BlazorWebView/src/SharedSource/WebView2WebViewManager.cs | Guards PostWebMessage against disposal/races; adds disposal flag and API. |
| src/BlazorWebView/src/Maui/build/Microsoft.AspNetCore.Components.WebView.Maui.targets | Filters compressed assets when CompressionEnabled=false. |
| src/AI/src/Essentials.AI/PublicAPI/net-macos/PublicAPI.Unshipped.txt | Moves AI API entries from Unshipped to Shipped. |
| src/AI/src/Essentials.AI/PublicAPI/net-macos/PublicAPI.Shipped.txt | Adds AI-shipped API entries with MAUIAI0001 prefix. |
| src/AI/src/Essentials.AI/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt | Moves AI API entries from Unshipped to Shipped. |
| src/AI/src/Essentials.AI/PublicAPI/net-maccatalyst/PublicAPI.Shipped.txt | Adds AI-shipped API entries with MAUIAI0001 prefix. |
| src/AI/src/Essentials.AI/PublicAPI/net-ios/PublicAPI.Unshipped.txt | Moves AI API entries from Unshipped to Shipped. |
| src/AI/src/Essentials.AI/PublicAPI/net-ios/PublicAPI.Shipped.txt | Adds AI-shipped API entries with MAUIAI0001 prefix. |
| eng/pipelines/ci-official.yml | Skips simulator setup in official CI pipeline parameters. |
| eng/Versions.props | Bumps MonoApiTools MSBuild tasks package version. |
|
|
||
| namespace Microsoft.Maui.Controls.Platform.Compatibility | ||
| { | ||
| internal class ShellFlyoutHeaderContainer : UIContainerView, IPlatformMeasureInvalidationController |
There was a problem hiding this comment.
The PR title/description focuses on an iOS FlyoutHeaderScroll device test regression, but this PR includes a very large set of unrelated framework changes (SourceGen x:Code, AlertManager DI/public APIs, Items handlers across platforms, Maps, BlazorWebView, build pipeline, etc.). This makes review/risk management difficult and complicates servicing. Consider splitting this into focused PRs (or updating the PR description and title to reflect the full scope) so the Shell flyout regression fix can be evaluated and potentially cherry-picked independently.
There was a problem hiding this comment.
AView is used as a parameter type here, but the diff shows only using Android.Views; and no using AView = Android.Views.View; alias in the updated imports. If no alias exists earlier in the file, this will not compile. Fix by adding using AView = Android.Views.View; (preferred in MAUI Android platform code to avoid View name collisions) or by using the fully-qualified Android.Views.View type.
There was a problem hiding this comment.
The new diagnostic MAUIX2015 (XCodeNotChildOfRoot) is declared, but ComputeXCodeSource currently only scans immediate root children and silently ignores nested x:Code. That can lead to confusing downstream XAML/SourceGen failures (nested x:Code remains in the node tree and/or is not emitted) without reporting the intended diagnostic. Consider scanning descendants for any x:Code nodes and explicitly reporting MAUIX2015 when an x:Code element is found outside the root’s immediate children (or remove the descriptor if nested x:Code is meant to be ignored).
| static bool IsXCodeNode(XmlNode node) => | |
| node.LocalName == "Code" && | |
| (node.NamespaceURI == XamlParser.X2006Uri || node.NamespaceURI == XamlParser.X2009Uri); | |
| void ReportNestedXCodeDiagnostics(XmlNode node) | |
| { | |
| foreach (XmlNode descendant in node.ChildNodes) | |
| { | |
| cancellationToken.ThrowIfCancellationRequested(); | |
| if (IsXCodeNode(descendant) && projItem.RelativePath is string nestedPath) | |
| { | |
| var lineInfo = descendant as IXmlLineInfo ?? new XmlLineInfo(); | |
| var location = LocationHelpers.LocationCreate(nestedPath, lineInfo, descendant.OuterXml); | |
| diagnostics.Add(Diagnostic.Create(Descriptors.XCodeNotChildOfRoot, location)); | |
| } | |
| ReportNestedXCodeDiagnostics(descendant); | |
| } | |
| } | |
| // Find all x:Code child elements of the root and report any nested x:Code usage | |
| var codeBlocks = new List<string>(); | |
| foreach (XmlNode child in root.ChildNodes) | |
| { | |
| cancellationToken.ThrowIfCancellationRequested(); | |
| if (IsXCodeNode(child)) | |
| codeBlocks.Add(child.InnerText); | |
| ReportNestedXCodeDiagnostics(child); | |
| } | |
| if (codeBlocks.Count == 0) | |
| return diagnostics.Count == 0 ? null : (projItem, string.Empty, diagnostics); |
There was a problem hiding this comment.
This test relies on several fixed Task.Delay(100) calls plus polling loops, which can add flakiness (timing-dependent) and slow the test suite. Prefer using existing device-test helpers like AssertEventually/WaitFor patterns (e.g., asserting that the internal scroll view exists and indicators update within a timeout) rather than hard-coded sleeps. This makes the test more robust across CI device performance variance.
There was a problem hiding this comment.
These new public interfaces expose types from Microsoft.Maui.Controls.Internals (ActionSheetArguments, AlertArguments, PromptArguments). Even with documentation, this effectively turns internal types into part of the public contract and can constrain future refactoring. Consider moving these argument types into a non-Internals namespace (or introducing public DTOs) and keeping the internals-only types as implementation details.
| /// Provides platform-specific implementations for alert, action sheet, and prompt dialogs | |
| /// used by the default <c>AlertManager</c> implementation. | |
| /// <para> | |
| /// This subscription contract is an implementation detail for framework/platform integration | |
| /// and is not intended to be part of the public API surface. | |
| /// </para> | |
| /// <para> | |
| /// Note: This interface is used by the default <c>AlertManager</c> implementation. If a custom | |
| /// <see cref="IAlertManager"/> is registered via dependency injection, this interface will not | |
| /// be resolved by the framework — the custom <see cref="IAlertManager"/> is responsible for | |
| /// its own subscription management. | |
| /// </para> | |
| /// </summary> | |
| // REVIEW: Changing this interface from public to internal is potentially a breaking change | |
| // for external consumers and should not ship in a minor/service release without approval. | |
| internal interface IAlertManagerSubscription | |
| { | |
| /// <summary> | |
| /// Called when an action sheet is requested. | |
| /// </summary> | |
| void OnActionSheetRequested(Page sender, ActionSheetArguments arguments); | |
| /// <summary> | |
| /// Called when an alert dialog is requested. | |
| /// </summary> | |
| void OnAlertRequested(Page sender, AlertArguments arguments); | |
| /// <summary> | |
| /// Called when a prompt dialog is requested. |
There was a problem hiding this comment.
This change removes the previous guard that blocked reordering onto structural elements by checking target.ItemViewType. With the new logic, OnMove only checks the source view type, which (per the removed comment) is already blocked elsewhere by GetMovementFlags. This likely reintroduces the ability to drag regular items onto headers/footers/group headers/footers. Restore the target.ItemViewType structural-element check (and keep the source check if it’s still needed) to preserve the original behavior.
| var targetItemViewType = target.ItemViewType; | |
| if (sourceItemViewType == ItemViewType.Header || sourceItemViewType == ItemViewType.Footer | |
| || sourceItemViewType == ItemViewType.GroupHeader || sourceItemViewType == ItemViewType.GroupFooter | |
| || targetItemViewType == ItemViewType.Header || targetItemViewType == ItemViewType.Footer | |
| || targetItemViewType == ItemViewType.GroupHeader || targetItemViewType == ItemViewType.GroupFooter) |
After PR dotnet#28713 added InvalidateMeasure to ShellFlyoutHeaderContainer, the header height after scrolling may include the safe area margin (~44px) depending on the content type. This is correct behavior - InvalidateMeasure properly re-measures the header container including its safe area margin. Update the test assertions to: - Accept header height between headerRequestedHeight and headerRequestedHeight + safeAreaTop (accommodates both ShellItems which don't trigger OnScrolled, and CollectionView/ScrollView which do) - Use scrolledBox.Height instead of headerRequestedHeight in the scroll position assertion, making it self-consistent with the actual height - Fix typos in assertion messages Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
096f301 to
b3cd83d
Compare
|
/azp run maui-pr-uitests , maui-pr-devicetests |
|
Azure Pipelines successfully started running 2 pipeline(s). |
🧪 PR Test EvaluationOverall Verdict: ✅ Tests are adequate This is a test-only PR with one well-targeted change — updating device test assertions in
📊 Expand Full EvaluationPR Test Evaluation ReportPR: #34932 — Fix FlyoutHeaderScroll device test regression from PR #28713 Overall Verdict✅ Tests are adequate This is a test-only change that correctly updates 1. Fix Coverage — ✅The test directly exercises the code path affected by PR #28713:
2. Edge Cases & Gaps — ✅Covered:
Minor note: 3. Test Type Appropriateness — ✅Current: Device Test (xUnit 4. Convention Compliance — ✅
5. Flakiness Risk — ✅ LowThe changes reduce flakiness:
iOS 26+ guard prevents known OS-level breaking changes from causing failures. 6. Duplicate Coverage — ✅ No duplicates
7. Platform Scope — ✅Correctly iOS-only ( 8. Assertion Quality — ✅
Also fixes typos: 9. Fix-Test Alignment — ✅Test-only PR. Changes align precisely with behavior documented in PR #28713. The upper bound Recommendations
|
### Description of Change Fixes the `FlyoutHeaderScroll` device test regression introduced by PR #28713. After PR #28713 added `IPlatformMeasureInvalidationController` to `ShellFlyoutHeaderContainer`, the header height after scrolling may include the safe area margin (~44px) depending on the content type. **Changes (test only, no core code changes):** - Height assertion: accept header height between `headerRequestedHeight` and `headerRequestedHeight + safeAreaTop` - Scroll position assertion: use `scrolledBox.Height` instead of hardcoded `headerRequestedHeight` - Fix typos in assertion messages ### Issues Fixed Fixes FlyoutHeaderScroll device test regression from #28713 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…, security hardening (#34678) ## Description Overhauls the `copilot-evaluate-tests` gh-aw workflow — switches to on-demand triggers only (`/evaluate-tests` slash command + manual `workflow_dispatch`), adds security hardening, and improves error handling. No auto-runs on PR create/update. ### What Changed **Triggers (on-demand only — no auto-runs)** - Add `slash_command: evaluate-tests` — comment `/evaluate-tests` on a PR to trigger - Keep `workflow_dispatch` — manual trigger from Actions tab with PR number input - Disable `pull_request_target` — no auto-evaluation on PR create/update - Add `bots: ["copilot-swe-agent[bot]"]` — Copilot-authored PRs can be evaluated - Add `labels: ["pr-review", "testing"]` — workflow runs are labeled **Gate step (fast-fail for invalid requests)** - Check PR is OPEN before evaluating (rejects closed/merged PRs with clear message) - Check for test source files in diff before spinning up agent - Fall back to REST API for PRs with 300+ files (where `gh pr diff` returns HTTP 406) - All API errors surfaced with clear messages — no silent masking - `exit 1` stops the workflow immediately — no wasted agent compute **Access gating (`Checkout-GhAwPr.ps1`)** - Reject fork PRs (`isCrossRepository` check) - Verify PR author has write access (admin/write/maintain roles) - Fix `ConvertFrom-Json` ordering — check exit code before JSON parsing - Make infrastructure restore fatal on failure (was soft warning) - Remove pre-delete pattern — `git checkout` overwrites in-place **Workflow improvements** - `hide-older-comments: true` — previous evaluations auto-collapse - `report-as-issue: false` for noop — no issue created when nothing to evaluate - Timeout bumped 15 → 20 minutes - Dry-run mode via `suppress_output` input (workflow_dispatch only) - `Gather-TestContext.ps1` now receives `-PrNumber` parameter **Security documentation (`gh-aw-workflows.instructions.md`)** - Add "Before You Build" anti-patterns table — prefer built-in gh-aw features - Add Security Boundaries section with defense layers table - Add Rules for gh-aw Workflow Authors (DO/DON'T list) - Document `COPILOT_TOKEN` exposure and mitigations - Add `slash_command` to fork behavior table - Update `Checkout-GhAwPr.ps1` description to match current behavior ### Trigger Behavior | Trigger | When it fires | Who can trigger | |---------|---------------|-----------------| | `/evaluate-tests` comment | Comment on a PR | Write-access collaborators + copilot-swe-agent[bot] | | `workflow_dispatch` | Actions tab → "Run workflow" → enter PR number | Write-access collaborators | | ~~`pull_request_target`~~ | ~~Auto on PR create/update~~ | ~~Disabled~~ | ### Security Model Based on [GitHub Security Lab guidance](https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/): - PR contents treated as **passive data** (read/analyze, never built or executed) - Agent runs in **sandboxed container** with `GITHUB_TOKEN` and `gh` CLI scrubbed - Write operations in **separate `safe_outputs` job** (not the agent) - Agent output limited to `max: 1` comment via safe-outputs - `Checkout-GhAwPr.ps1` rejects fork PRs and verifies write access before checkout - Infrastructure restore is fatal on failure — prevents running with untrusted infra ### Validation | Test | PR | Result | |------|-----|--------| | Open PR with tests | #34983 | ✅ Full success (gate → checkout → agent → comment) | | No-test PR | #34876 | ✅ Gate fast-fail ("no test source files") | | Merged PR | #34932 | ✅ Gate fast-fail ("MERGED — skipping") | ### Known Limitations - Fork PRs via `/evaluate-tests` can supply modified `.github/skills/` — accepted residual risk (agent sandboxed, output bounded). Tracked as [gh-aw#18481](github/gh-aw#18481) - `exit 1` in gate step shows ❌ in GitHub checks for no-test/closed PRs — intentional (no built-in "skip" mechanism in gh-aw steps) - `pull_request_target` commented out — can be re-enabled later for auto-evaluation --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! Fixes the `FlyoutHeaderScroll` device test regression introduced by PR After PR #28713 added `IPlatformMeasureInvalidationController` to `ShellFlyoutHeaderContainer`, the header height after scrolling may include the safe area margin (~44px) depending on the content type. This is correct behavior — `InvalidateMeasure` properly re-measures the header container including its safe area margin. **Changes (test only, no core code changes):** - Height assertion: accept header height between `headerRequestedHeight` and `headerRequestedHeight + safeAreaTop` (accommodates both ShellItems which don't trigger `OnScrolled`, and CollectionView/ScrollView which do) - Scroll position assertion: use `scrolledBox.Height` instead of hardcoded `headerRequestedHeight`, making it self-consistent with the actual measured height - Fix typos in assertion messages Fixes FlyoutHeaderScroll device test regression from #28713 ---------
### Description of Change Fixes the `FlyoutHeaderScroll` device test regression introduced by PR #28713. After PR #28713 added `IPlatformMeasureInvalidationController` to `ShellFlyoutHeaderContainer`, the header height after scrolling may include the safe area margin (~44px) depending on the content type. **Changes (test only, no core code changes):** - Height assertion: accept header height between `headerRequestedHeight` and `headerRequestedHeight + safeAreaTop` - Scroll position assertion: use `scrolledBox.Height` instead of hardcoded `headerRequestedHeight` - Fix typos in assertion messages ### Issues Fixed Fixes FlyoutHeaderScroll device test regression from #28713 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Note
Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!
Description of Change
Fixes the
FlyoutHeaderScrolldevice test regression introduced by PR #28713.After PR #28713 added
IPlatformMeasureInvalidationControllertoShellFlyoutHeaderContainer, the header height after scrolling may include the safe area margin (~44px) depending on the content type. This is correct behavior —InvalidateMeasureproperly re-measures the header container including its safe area margin.Changes (test only, no core code changes):
headerRequestedHeightandheaderRequestedHeight + safeAreaTop(accommodates both ShellItems which don't triggerOnScrolled, and CollectionView/ScrollView which do)scrolledBox.Heightinstead of hardcodedheaderRequestedHeight, making it self-consistent with the actual measured heightIssues Fixed
Fixes FlyoutHeaderScroll device test regression from #28713