Fix SwipeView Threshold changes width and offset of the side menu (when visible)#34923
Fix SwipeView Threshold changes width and offset of the side menu (when visible)#34923KarthikRajaKalaimani wants to merge 9 commits intodotnet:mainfrom
Conversation
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 34923Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 34923" |
|
Hey there @@KarthikRajaKalaimani! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
|
/azp run maui-pr-uitests , maui-pr-devicetests |
|
Azure Pipelines successfully started running 2 pipeline(s). |
There was a problem hiding this comment.
Pull request overview
This PR fixes incorrect use of SwipeView.Threshold in the iOS and Android platform implementations so that Threshold affects only the trigger distance for opening, not the rendered swipe menu width or the final open offset.
Changes:
- iOS/Android: stop using
Thresholdto size swipe items and to determine the open snap distance; compute open distance from actual menu size and treatThresholdas a cap for the trigger distance. - iOS/Android: rename internal “threshold” helper to reflect “open distance” semantics and update call sites.
- Add a new UI test page + Appium test for Issue 6016 to validate menu width is unaffected by
Thresholdand that Execute mode still triggers.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Core/src/Platform/iOS/SwipeViewExtensions.cs | Removes Threshold from swipe-item sizing calculations on iOS. |
| src/Core/src/Platform/iOS/MauiSwipeView.cs | Uses menu open distance for snapping; uses Threshold only for trigger distance on iOS. |
| src/Core/src/Platform/Android/MauiSwipeView.cs | Mirrors iOS behavior changes on Android; removes old reveal-threshold helper and stops sizing by Threshold. |
| src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue6016.cs | Adds Appium UI coverage for the regression (menu width/offset + Execute mode). |
| src/Controls/tests/TestCases.HostApp/Issues/Issue6016.cs | Adds HostApp reproduction page used by the new UI test. |
addressed AI summary concerns |
|
/azp run maui-pr-uitests , maui-pr-devicetests |
|
Azure Pipelines successfully started running 2 pipeline(s). |
|
/azp run maui-pr-uitests , maui-pr-devicetests |
|
Azure Pipelines successfully started running 2 pipeline(s). |
kubaflo
left a comment
There was a problem hiding this comment.
Looks like some tests are failing - could you please verify?
|
Azure Pipelines successfully started running 1 pipeline(s). |
…ability (#35133) <!-- 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! > **Depends on #35136** (pipeline category detection — should merge first) ## What this does Two things: ### 1. UI test category detection in PR review During the PR review workflow, Step 0.5 detects which UI test categories the PR impacts and writes the result to the AI summary comment. This gives reviewers visibility into which UI tests are relevant. **Detection** reuses the 3-tier script from #35136 (test attributes → source paths → AI reasoning). **AI summary** shows a new 🧪 UI Tests section with detected categories before the gate section. ### 2. Gate reliability fixes Multiple fixes to make the gate (`verify-tests-fail.ps1`) more deterministic: | Fix | Problem it solves | |-----|-------------------| | **Absolute path resolution** | Gate scripts not found on Linux CI agents (`Resolve-Path`, `GetFullPath`) | | **File existence check** | Instant cryptic failure when verify script is missing — now logs clear error | | **3x retry on ENV ERROR** | Emulator timeouts, ADB failures, app crashes — transient issues that pass on retry | | **Strip bad report blocks** | Old verify script produces `Passed: False` with empty counts — stripped instead of shown | | **Gate log in fallback** | When report is missing, shows last 20 lines of gate output instead of just `❌ FAILED / Platform: IOS` | ## Files | File | Changes | |------|---------| | `.github/scripts/Review-PR.ps1` | Step 0.5 category detection + all 5 gate fixes | | `.github/scripts/post-ai-summary-comment.ps1` | Add `uitests` phase to render detected categories | | `.github/pr-review/pr-preflight.md` | Step 7: AI identifies impacted UI test categories | ## Validation — PR reviewer builds (Apr 26) 10 builds against real PRs — all succeeded ✅. Category detection shown in AI summary comment. | PR | Categories Detected | Build | AI Summary | |----|-------------------|-------|------------| | #35037 (WebView theme) | `ViewBaseTests,WebView` | [13940071](https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=13940071) | [comment](#35037 (comment)) | | #35031 (Shell memory leak) | `Shell` | [13940072](https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=13940072) | [comment](#35031 (comment)) | | #35020 (XAML Hot Reload) | _(none — XAML only)_ | [13940073](https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=13940073) | ✅ Shows "No UI test categories" | | #35008 (Shell SearchHandler) | `Shell` | [13940074](https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=13940074) | ✅ | | #34997 (RadioButton gradient) | `RadioButton,ViewBaseTests` | [13940075](https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=13940075) | ✅ | | #34980 (DatePicker rotation) | `ViewBaseTests` | [13940076](https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=13940076) | ✅ | | #34974 (Picker CharacterSpacing) | `ViewBaseTests` | [13940077](https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=13940077) | ✅ | | #34923 (SwipeView threshold) | `SwipeView,ViewBaseTests` | [13940078](https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=13940078) | ✅ | | #34907 (CollectionView ScrollTo) | `CollectionView` | [13940079](https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=13940079) | ✅ | | #34845 (RefreshView binding) | `RefreshView,ViewBaseTests` | [13940080](https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=13940080) | ✅ | --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 7 findings
See inline comments for details.
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 3 findings
See inline comments for details.
kubaflo
left a comment
There was a problem hiding this comment.
Some swipe view tests are failing - could you please verify?
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 7 findings
See inline comments for details.
🤖 AI Summary
📊 Review Session —
|
| Test | Without Fix (expect FAIL) | With Fix (expect PASS) |
|---|---|---|
🖥️ Issue6016 Issue6016 |
✅ FAIL — 562s | ✅ PASS — 518s |
🔴 Without fix — 🖥️ Issue6016: FAIL ✅ · 562s
Determining projects to restore...
All projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0-android36.0/Microsoft.Maui.dll
Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-android36.0/Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Foldable.dll
Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-android36.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Xaml.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Maps.dll
Controls.TestCases.HostApp -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Controls.TestCases.HostApp.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.dll
Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Maps.dll
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Xaml.dll
Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Maps.dll
Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.AspNetCore.Components.WebView.Maui.dll
Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Foldable.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:07:00.22
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
Determining projects to restore...
All projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
Controls.CustomAttributes -> /home/vsts/work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
UITest.Core -> /home/vsts/work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.dll
VisualTestUtils -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.dll
VisualTestUtils.MagickNet -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils.MagickNet/Debug/netstandard2.0/VisualTestUtils.MagickNet.dll
UITest.Appium -> /home/vsts/work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.dll
UITest.NUnit -> /home/vsts/work/1/s/artifacts/bin/UITest.NUnit/Debug/net10.0/UITest.NUnit.dll
UITest.Analyzers -> /home/vsts/work/1/s/artifacts/bin/UITest.Analyzers/Debug/netstandard2.0/UITest.Analyzers.dll
Controls.TestCases.Android.Tests -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
Test run for /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
/home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.11] Discovering: Controls.TestCases.Android.Tests
[xUnit.net 00:00:00.31] Discovered: Controls.TestCases.Android.Tests
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
NUnit3TestExecutor discovered 3 of 3 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 05/07/2026 22:19:28 FixtureSetup for Issue6016(Android)
>>>>> 05/07/2026 22:19:30 SwipeViewThresholdShouldNotChangeMenuWidth Start
>>>>> 05/07/2026 22:19:35 SwipeViewThresholdShouldNotChangeMenuWidth Stop
>>>>> 05/07/2026 22:19:35 Log types: logcat, bugreport, server
Failed LeftItems [5 s]
Error Message:
SwipeView menu width should not change with Threshold. Default=263.0px, Threshold=200 → 478.0px
Assert.That(thresholdMenuWidth, Is.EqualTo(defaultMenuWidth).Within(5))
Expected: 263.0f +/- 5
But was: 478.0f
Off by: -215.0d
Stack Trace:
at Microsoft.Maui.TestCases.Tests.Issues.Issue6016.SwipeViewThresholdShouldNotChangeMenuWidth(String defaultContentId, String thresholdContentId, String defaultSwipeViewId, String thresholdSwipeViewId, Boolean swipeRight) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue6016.cs:line 77
1) at Microsoft.Maui.TestCases.Tests.Issues.Issue6016.SwipeViewThresholdShouldNotChangeMenuWidth(String defaultContentId, String thresholdContentId, String defaultSwipeViewId, String thresholdSwipeViewId, Boolean swipeRight) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue6016.cs:line 77
>>>>> 05/07/2026 22:19:36 SwipeViewThresholdShouldNotChangeMenuWidth Start
>>>>> 05/07/2026 22:19:39 SwipeViewThresholdShouldNotChangeMenuWidth Stop
>>>>> 05/07/2026 22:19:39 Log types: logcat, bugreport, server
Failed RightItems [3 s]
Error Message:
SwipeView menu width should not change with Threshold. Default=263.0px, Threshold=200 → 314.0px
Assert.That(thresholdMenuWidth, Is.EqualTo(defaultMenuWidth).Within(5))
Expected: 263.0f +/- 5
But was: 314.0f
Off by: -51.0d
Stack Trace:
at Microsoft.Maui.TestCases.Tests.Issues.Issue6016.SwipeViewThresholdShouldNotChangeMenuWidth(String defaultContentId, String thresholdContentId, String defaultSwipeViewId, String thresholdSwipeViewId, Boolean swipeRight) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue6016.cs:line 77
at InvokeStub_Issue6016.SwipeViewThresholdShouldNotChangeMenuWidth(Object, Span`1)
1) at Microsoft.Maui.TestCases.Tests.Issues.Issue6016.SwipeViewThresholdShouldNotChangeMenuWidth(String defaultContentId, String thresholdContentId, String defaultSwipeViewId, String thresholdSwipeViewId, Boolean swipeRight) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue6016.cs:line 77
at InvokeStub_Issue6016.SwipeViewThresholdShouldNotChangeMenuWidth(Object, Span`1)
>>>>> 05/07/2026 22:19:39 SwipeViewExecuteModeTriggers Start
>>>>> 05/07/2026 22:19:41 SwipeViewExecuteModeTriggers Stop
Passed SwipeViewExecuteModeTriggers [1 s]
NUnit Adapter 4.5.0.0: Test execution complete
Test Run Failed.
Total tests: 3
Passed: 1
Failed: 2
Total time: 26.1893 Seconds
🟢 With fix — 🖥️ Issue6016: PASS ✅ · 518s
Determining projects to restore...
All projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0-android36.0/Microsoft.Maui.dll
Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-android36.0/Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Xaml.dll
Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-android36.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Maps.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Foldable.dll
Controls.TestCases.HostApp -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Controls.TestCases.HostApp.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.dll
Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Maps.dll
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Xaml.dll
Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.AspNetCore.Components.WebView.Maui.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Foldable.dll
Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Maps.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:06:41.75
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
Determining projects to restore...
All projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Controls.CustomAttributes -> /home/vsts/work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.14042758
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
UITest.Core -> /home/vsts/work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.dll
UITest.NUnit -> /home/vsts/work/1/s/artifacts/bin/UITest.NUnit/Debug/net10.0/UITest.NUnit.dll
UITest.Appium -> /home/vsts/work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.dll
VisualTestUtils -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.dll
VisualTestUtils.MagickNet -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils.MagickNet/Debug/netstandard2.0/VisualTestUtils.MagickNet.dll
UITest.Analyzers -> /home/vsts/work/1/s/artifacts/bin/UITest.Analyzers/Debug/netstandard2.0/UITest.Analyzers.dll
Controls.TestCases.Android.Tests -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
Test run for /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
/home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.11] Discovering: Controls.TestCases.Android.Tests
[xUnit.net 00:00:00.32] Discovered: Controls.TestCases.Android.Tests
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
NUnit3TestExecutor discovered 3 of 3 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 05/07/2026 22:28:09 FixtureSetup for Issue6016(Android)
>>>>> 05/07/2026 22:28:11 SwipeViewThresholdShouldNotChangeMenuWidth Start
>>>>> 05/07/2026 22:28:15 SwipeViewThresholdShouldNotChangeMenuWidth Stop
Passed LeftItems [3 s]
>>>>> 05/07/2026 22:28:15 SwipeViewThresholdShouldNotChangeMenuWidth Start
>>>>> 05/07/2026 22:28:18 SwipeViewThresholdShouldNotChangeMenuWidth Stop
Passed RightItems [3 s]
>>>>> 05/07/2026 22:28:18 SwipeViewExecuteModeTriggers Start
>>>>> 05/07/2026 22:28:20 SwipeViewExecuteModeTriggers Stop
Passed SwipeViewExecuteModeTriggers [1 s]
NUnit Adapter 4.5.0.0: Test execution complete
Test Run Successful.
Total tests: 3
Passed: 3
Total time: 22.1514 Seconds
📁 Fix files reverted (3 files)
src/Core/src/Platform/Android/MauiSwipeView.cssrc/Core/src/Platform/iOS/MauiSwipeView.cssrc/Core/src/Platform/iOS/SwipeViewExtensions.cs
🧪 UI Tests — Category Detection
Detected UI test categories: SwipeView,ViewBaseTests
🧪 UI Test Execution Results
❌ FAILED — 1 passed, 1 failed, 0 skipped (platform: android)
| Category | Result | Duration | Notes |
|---|---|---|---|
SwipeView |
❌ FAILED | 2064.8s | exit code 1 |
ViewBaseTests |
✅ PASSED | 1001.6s |
Failures here are informational only — they do not block the gate or affect try-fix candidate scoring.
🔍 Regression Cross-Reference
🔍 Regression Cross-Reference
🟢 No regression risks detected. No labeled bug-fix PRs in the last 6 months touched the modified files.
🔍 Pre-Flight — Context & Validation
Issue: #6016 - SwipeView Threshold changes width and offset of the side menu (when visible)
PR: #34923 - Fix SwipeView Threshold changes width and offset of the side menu (when visible)
Platforms Affected: Android, iOS (MacCatalyst inherits via .ios.cs)
Files Changed: 3 implementation (src/Core/src/Platform/Android/MauiSwipeView.cs, src/Core/src/Platform/iOS/MauiSwipeView.cs, src/Core/src/Platform/iOS/SwipeViewExtensions.cs), 2 test (Issue6016.cs HostApp + Shared.Tests), plus 12 snapshot baselines updated.
Key Findings
SwipeView.Thresholdis documented as the minimum drag distance needed to snap-open the menu, but the platform code conflated it with two unrelated quantities: (a) the swipe-item display width (GetSwipeItemSize), and (b) the snap-open distance (GetSwipeThreshold(ISwipeItems)).- The PR removes both misuses. Item size now uses
WidthRequestorSwipeViewExtensions.SwipeItemWidth(default 100). Snap distance is computed purely from the menu width. The user-setThresholdis now used only as a cap on the trigger threshold:triggerThreshold = Element.Threshold > 0 ? Math.Min(Threshold, openDistance) : 0.6 * openDistance. - Renames are part of the change: field
_swipeThreshold→_swipeOpenDistance; helperGetSwipeThreshold()/GetSwipeThreshold(ISwipeItems)→GetSwipeOpenDistance(...). Android also drops the now-unusedGetRevealModeSwipeThreshold(). - 12 PNG snapshot baselines were regenerated because both Android and iOS-26 visual diffs now show the corrected (non-bloated) menu width.
- Tests added for two parameterized cases (LeftItems / RightItems) plus an Execute-mode regression guard. Test is gated
#if TEST_FAILS_ON_WINDOWSbecause SwipeItem AutomationId isn't propagated on Windows. - Inline reviewer (Copilot) feedback on the PR raised two concerns: (1)
WaitForXPositionsilently returns the last X on timeout — the test could pass with both menu widths == 0; consider failing on timeout. (2) The field name_swipeThresholdwas misleading after semantics changed (already addressed by the rename in this PR; the inline comment was authored on an older revision). - Gate result: ✅ PASSED (test fails on baseline, passes with fix).
Code Review Summary
Verdict: NEEDS_CHANGES (low-severity)
Confidence: medium
Errors: 0 | Warnings: 2 | Suggestions: 3
Key code review findings:
⚠️ src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue6016.cs:33—WaitForXPositionswallows timeout: it returns the last observed X without asserting the predicate ever became true, so a swipe that fails to register can still producedefaultMenuWidth == thresholdMenuWidth == 0, and the equality assertion will spuriously pass. Recommend asserting predicate satisfaction (or returning a(bool satisfied, float x)tuple) before computing widths.⚠️ src/Core/src/Platform/Android/MauiSwipeView.cs:993-998andsrc/Core/src/Platform/iOS/MauiSwipeView.cs:765-772— duplicated trigger-threshold logic across Android and iOS. The blockif (Element != null && Element.Threshold > 0) triggerThreshold = Math.Min(Threshold, openDistance) else 0.6 * openDistanceappears 2× on Android (ProcessTouchUp+RaiseSwipeEnded) and 1× on iOS. Consider extractingGetTriggerThreshold()to keep the two platforms in sync.- 💡
Element != null && Element.Threshold > 0— on AndroidElementis repeatedly null-checked elsewhere; consider caching or using local var to avoid double-deref between branches. - 💡 The local
triggerThresholdclamps toMath.Min(Threshold, openDistance). IfThresholdis set very low (e.g., 5dp), the menu still snaps to full open distance, but the user-perceived "trigger" is reasonable. Consider also enforcing a minimum ofMinimumOpenSwipeThresholdPercentage * openDistanceon iOS to keep the existing 15% floor. - 💡
Math.Abs(_swipeOpenDistance) > double.Epsilon— the cache check is unchanged, but reads slightly oddly when the value is conceptually a distance (always ≥ 0). Could simplify to_swipeOpenDistance > 0.
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #34923 | Remove Threshold from item-size + snap-distance; use Threshold as a min(Threshold, openDistance) cap on trigger; rename field/methods | ✅ PASSED (Gate) | 3 src + 2 test + 12 snapshots | Original PR |
🔧 Fix — Analysis & Comparison
Try-Fix Summary (4 candidates)
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | try-fix-1 (claude-opus-4.6) | Split into GetSwipeThreshold() (trigger) + GetSwipeOpenDistance() (snap distance); reuse old method name with new semantics |
⏳ Not validated; logically equivalent to PR | 3 src + tests + 12 snapshots | Symbol-name churn for no behaviour change |
| 2 | try-fix-2 (claude-sonnet-4.6) | PR fix + extract GetTriggerThreshold() helper to dedupe Android/iOS trigger logic |
⏳ Not validated; pure refactor on top of PR | PR's files + ~10 lines | Nice cleanup; better as follow-up PR |
| 3 | try-fix-3 (gpt-5.3-codex) | PR fix + cache _triggerThreshold for hot-path optimization |
⏳ Not validated; introduces stale-cache risk for bound Threshold |
PR's files + ~24 lines | Likely regression on bound Threshold mutations |
| 4 | try-fix-4 (gemini-3-pro-preview) | Minimal: only delete the 2 misuses; do not add Math.Min(Threshold, openDistance) cap; no renames |
❌ Loses Threshold-as-trigger-cap feature; users wanting "less sensitive" swipe regress | smaller delta in src + tests + 12 snapshots | Drops a useful behaviour PR adds |
| PR | PR #34923 | Remove Threshold from item-size + snap-distance; cap trigger via Math.Min(Threshold, openDistance) else 60%; rename field/methods |
✅ PASSED (Gate) | 3 src + 2 test + 12 snapshots | Original PR — gate-verified |
Cross-Pollination
| Model | Round | New Ideas? | Details |
|---|---|---|---|
| claude-opus-4.6 | 2 | NO NEW IDEAS | The PR's approach already covers the substantive fix; remaining variations are stylistic. |
| claude-sonnet-4.6 | 2 | NO NEW IDEAS | Refactor proposal (try-fix-2) stands as-is. |
| gpt-5.3-codex | 2 | NO NEW IDEAS | Caching idea (try-fix-3) carries regression risk; declines further variants. |
| gemini-3-pro-preview | 2 | NO NEW IDEAS | Conservative variant (try-fix-4) drops a feature; declines further variants. |
Exhausted: Yes
Selected Fix: PR #34923 + reviewer test-quality fix (pr-plus-reviewer) — the PR is gate-verified
and is the only candidate explicitly tested. The expert reviewer surfaced one real test-quality
bug (silent timeout in WaitForXPosition) which pr-plus-reviewer addresses without altering any
production code.
Environment note
Try-fix candidates were generated and analyzed but not built/run because the agent's environment
(Linux without an Android emulator) cannot execute BuildAndRunHostApp.ps1 for Android UI tests.
The PR's gate result (✅ test fails on baseline, passes with fix) is the only empirical signal
available; per the prompt rules, candidates without passing test results MUST rank below the PR.
📋 Report — Final Recommendation
Final Recommendation — PR #34923
| Phase | Status |
|---|---|
| Gate | ✅ PASSED — tests fail on baseline, pass with fix |
| Pre-Flight | ✅ Complete |
| Code Review | ✅ Complete (NEEDS_CHANGES, low-severity — 2 warnings, 3 suggestions) |
| Try-Fix ×4 | ✅ Complete (4 candidates analysed) |
| Report | ✅ Complete |
Comparative analysis
| Candidate | Gate-tested | Behavioural delta vs PR | Risk | Rank |
|---|---|---|---|---|
| pr | ✅ | (baseline) | Low | 2 |
| pr-plus-reviewer | ✅ (PR's gate; sandbox patch is test-only) | identical production code; tighter test helper | Lowest — strictly safer test | 1 (winner) |
| try-fix-1 | ⏳ | Symbol-name churn only | Low (likely equivalent) | 3 |
| try-fix-2 | ⏳ | Refactor: helper extraction | Low (pure refactor) | 4 |
| try-fix-3 | ⏳ | Adds cached _triggerThreshold |
Medium — stale cache for bound Threshold |
5 |
| try-fix-4 | ⏳ | Drops PR's Math.Min(Threshold, openDistance) cap |
Medium — regresses the trigger-cap feature commenters asked for | 6 |
Why pr-plus-reviewer wins
- Gate-verified production code. It uses 100% of the PR's source-code changes, which are the
only changes that have empirically passed the gate. - Closes a real false-pass hole in the new test. Copilot's inline review correctly flagged that
WaitForXPositionreturns the last observed X on timeout, so a swipe that fails to register can
make the equality assertion pass with both sides equal to 0. The sandbox patch makes the helper
Assert.Failon timeout — strictly safer. - Strictly better than
pr— every test that passes underpralso passes under
pr-plus-reviewer, butpr-plus-reviewerwould additionally catch a class of silent UI-test
regressions. There is no scenario wherepr-plus-revieweris worse thanpr. - The other reviewer suggestions (extract
GetTriggerThresholdhelper, add iOS 15% floor, prettier
cache check) are deferred to follow-up — they are nice-to-have cleanup, not bug fixes.
Why all try-fix-* rank lower
Per the prompt's hard rule: “Candidates that failed regression tests MUST be ranked lower than
candidates that passed them.” The four try-fix candidates were not built or executed in this
environment (no Android emulator available). Treating "not validated" as "not passed", they all rank
strictly below pr and pr-plus-reviewer. Among themselves:
- try-fix-1 (rename split) — pure naming churn. No upside.
- try-fix-2 (helper extraction) — non-functional cleanup; better as a follow-up PR so the bug-fix
PR stays small and easy to revert if needed. - try-fix-3 (cache trigger threshold) — has a plausible regression path (bound
Thresholdwon't
invalidate the cache). Net negative. - try-fix-4 (minimal/conservative) — drops the new
Math.Min(Threshold, openDistance)cap,
which is a desirable secondary behaviour the PR introduces (issue commenters asked for less
sensitive swipes). Net negative.
Recommendation to the PR author
✅ Merge-ready with one suggested follow-up:
- Apply the
WaitForXPositiontimeout-fail-fast fix (Copilot inline finding on
Issue6016.cs:33). This is a 10-line change to the test helper. It strictly improves the test's
ability to catch silent failures and does not affect production code. See
expert-pr-eval/content.mdfor the exact patch.
Optional follow-ups (separate PR):
- Extract
GetTriggerThreshold()helper in bothMauiSwipeView.csfiles to dedupe the trigger
formula across AndroidProcessTouchUp+RaiseSwipeEndedand iOSProcessTouchUp. - Consider whether iOS should clamp the trigger to
Math.Max(Threshold, 0.15 * openDistance)to
preserve the existingMinimumOpenSwipeThresholdPercentagefloor when users set a very small
Threshold.
Caveats / honest disclosure
- The agent ran on a Linux runner without Android emulator infrastructure, so try-fix candidates
could not be built or test-executed locally. Their analyses are static and based on careful code
reading; they are not empirically validated. The PR's gate result is the only empirical signal. - Snapshot baselines (12 PNGs) regenerated by the PR author were not visually re-verified by this
agent.
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!
Issue Details:
SwipeView Threshold changes width and offset of the side menu (when visible) Opened.
Root Cause:
The SwipeView.Threshold property is designed for a single purpose: setting the minimum drag distance a user must swipe before the menu snaps open. It has nothing to do with how wide the menu
items should appear or where the content settles after the swipe. However, the platform code on both iOS and Android was incorrectly using this value in two unrelated calculations.
The first misuse was in GetSwipeItemSize(), where the code checked if Threshold > 0 and, if so, used the threshold value as the item's width. This meant that setting Threshold=200 would inflate
every swipe item to 200pt wide, far larger than the intended ~100pt. The second misuse was in GetSwipeThreshold(ISwipeItems), which had an early return that directly handed back the Threshold
value as the snap-open distance. So the content would snap to 200pt offset instead of snapping to the actual menu width. Together, these two bugs caused both the menu to look bloated and the
content displacement to differ depending on whether Threshold was set.
Description of Change:
The fix removes Threshold from both of those calculations entirely. Item sizing now uses only the item's configured WidthRequest or the default SwipeItemWidth, as it should. The snap distance is now computed as Math.Min(Threshold, menuWidth) — meaning if Threshold is set, it acts as a cap on how far the user needs to drag, but the content still snaps to the true menu width. If Threshold is not set, the default behaviour of 60% of menu width is preserved. This was applied consistently across iOS (MauiSwipeView.cs and SwipeViewExtensions.cs) and Android (MauiSwipeView.cs).
Tested the behavior in the following platforms:
Reference:
N/A
Issues Fixed:
Fixes #6016
Screenshots
Before_fix_6016.mov
After_fix_6016.mov