Revert "February 21st, 2026 Candidate Branch"#34292
Conversation
This reverts commit 6f3847e.
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 34292Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 34292" |
There was a problem hiding this comment.
Pull request overview
This PR reverts "February 21st, 2026 Candidate Branch" (#34173), undoing a batch of changes that were merged into the main branch. The revert removes iOS 26-specific workarounds from UI tests, removes several new test files and host app pages, and reverts functional code changes in both Android and iOS platform handlers.
Changes:
- Removes iOS 26-specific
Assert.Ignoreguards and conditional back-arrow logic from numerous UI tests, restoring original test behavior - Deletes newly added test files (
Issue27117,Issue28827,Issue31445,Issue31680,Issue32223,Issue32867,Issue33523,Issue33690, etc.) from bothTestCases.HostAppandTestCases.Shared.Tests - Reverts functional changes in Android/iOS source code including
TapAndPanGestureDetector,ToolbarExtensions,ShellNavigationManager,MauiRecyclerView, and others
Reviewed changes
Copilot reviewed 109 out of 933 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
eng/pipelines/common/ui-tests.yml |
Reverts iOS test version from 26.0 back to 18.5 |
eng/pipelines/ci-uitests.yml |
Reverts iOS test versions from 18.5/latest to 18.4 |
src/Controls/src/Core/Handlers/Items/Android/MauiRecyclerView.cs |
Reverts ScrollTo index offset logic for ungrouped source with header |
src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs |
Reverts guard for carouselPosition < 0 in SetCurrentItem |
src/Controls/src/Core/Handlers/Items/Android/SimpleItemTouchHelperCallback.cs |
Reverts reorder blocking logic to original view-type equality check |
src/Controls/src/Core/Handlers/Items/Android/RecyclerViewScrollListener.cs |
Reverts scroll offset reset-on-empty logic |
src/Controls/src/Core/Handlers/Items/Android/ObservableGroupedSource.cs |
Reverts group source null-check refactor |
src/Controls/src/Core/Platform/Android/TapAndPanGestureDetector.cs |
Reverts pointer gesture handling and return value logic |
src/Controls/src/Core/Platform/Android/Extensions/ToolbarExtensions.cs |
Reverts duplicate title icon prevention fix |
src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellToolbarTracker.cs |
Reverts OnBackButtonPressed interception in OnNavigateBack |
src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellPageRendererTracker.cs |
Reverts iOS 26 tint color fix and foreground color variable scope |
src/Controls/src/Core/InputView/InputView.Platform.cs |
Reverts MapIsVisible keyboard-dismiss logic for hidden inputs |
src/Controls/src/Core/Entry/Entry.Mapper.cs |
Reverts MapIsVisible mapper registration for Entry |
src/Controls/src/Core/Editor/Editor.Mapper.cs |
Reverts MapIsVisible mapper registration for Editor |
src/Controls/src/Core/Shell/ShellNavigationManager.cs |
Reverts iOS/MacCatalyst route deduplication logic |
src/Controls/src/Core/Handlers/Items/CarouselViewHandler.Android.cs |
Reverts Position < 0 guard in MapPosition |
Multiple TestCases.Shared.Tests files |
Removes iOS 26 guards and restores original back-arrow/test logic |
Multiple TestCases.HostApp files |
Removes new host app issue pages added in the candidate branch |
.github/agent-pr-session/pr-31487.md |
Removes agent PR session document |
Comments suppressed due to low confidence (1)
src/Controls/src/Core/Platform/Android/Extensions/ToolbarExtensions.cs:1
- The reverted code always creates a new
ToolbarTitleIconImageViewand adds it at index 0 without checking whether one already exists. This reintroduces the duplicate title icon bug that was fixed in the candidate branch: callingSetTitleIconImageSourcemore than once for the same page will add a new icon each time, resulting in multiple icons in the toolbar.
using System;
| if (ItemsViewAdapter.ItemsSource is UngroupedItemsSource) | ||
| { | ||
| return ungroupedSource.HasHeader ? args.Index + 1 : args.Index; | ||
| return args.Index; | ||
| } |
There was a problem hiding this comment.
The reverted code returns args.Index directly for UngroupedItemsSource, even when the source has a header. The removed code accounted for the header offset (ungroupedSource.HasHeader ? args.Index + 1 : args.Index), so reverting this will cause ScrollTo by index to land on the wrong item when a header is present in the CollectionView.
| // See https://stackoverflow.com/questions/27507715/android-how-to-get-the-current-x-offset-of-recyclerview | ||
| _horizontalOffset += dx; | ||
| _verticalOffset += dy; | ||
|
|
There was a problem hiding this comment.
The removed code reset _horizontalOffset and _verticalOffset to 0 when the adapter's item count is 0. Without that reset, the accumulated offsets will carry over incorrectly after the CollectionView items are cleared and repopulated, causing the Scrolled event to report stale offset values.
| // When there are no items, reset the accumulated offsets so that | |
| // subsequent scrolled events after repopulating the items do not | |
| // report stale offset values from the previous dataset. | |
| if (ItemsViewAdapter?.ItemsSource?.Count == 0) | |
| { | |
| _horizontalOffset = 0; | |
| _verticalOffset = 0; | |
| } |
| var targetViewType = target.ItemViewType; | ||
| if (targetViewType == ItemViewType.Header || targetViewType == ItemViewType.Footer | ||
| || targetViewType == ItemViewType.GroupHeader || targetViewType == ItemViewType.GroupFooter) | ||
| if (viewHolder.ItemViewType != target.ItemViewType) |
There was a problem hiding this comment.
The reverted condition blocks reordering between items of different view types. This prevents items from being reordered onto Header, Footer, GroupHeader, or GroupFooter positions, but it also prevents reordering between items that use a DataTemplateSelector (which can produce different view types for regular items). The removed code only blocked reordering onto structural elements, which is the correct behavior. This revert reintroduces the original bug where drag-and-drop reordering fails for CollectionViews using DataTemplateSelector.
| if (viewHolder.ItemViewType != target.ItemViewType) | |
| var targetViewType = target.ItemViewType; | |
| if (targetViewType == ItemViewType.Header || targetViewType == ItemViewType.Footer | |
| || targetViewType == ItemViewType.GroupHeader || targetViewType == ItemViewType.GroupFooter) |
| if (ItemsViewAdapter?.ItemsSource?.Count == 0) | ||
| return; | ||
|
|
||
| var item = ItemsViewAdapter.ItemsSource.GetItem(carouselPosition); |
There was a problem hiding this comment.
The removed guard carouselPosition < 0 has been reverted. Without it, passing a negative carouselPosition (e.g., -1) to SetCurrentItem will proceed to call ItemsViewAdapter.ItemsSource.GetItem(carouselPosition) with a negative index, which is likely to throw an ArgumentOutOfRangeException.
| if (ItemsViewAdapter?.ItemsSource?.Count == 0) | |
| return; | |
| var item = ItemsViewAdapter.ItemsSource.GetItem(carouselPosition); | |
| var itemsSource = ItemsViewAdapter?.ItemsSource; | |
| var count = itemsSource?.Count ?? 0; | |
| // Guard against invalid positions (including negative indices) | |
| if (itemsSource == null || count == 0 || carouselPosition < 0 || carouselPosition >= count) | |
| return; | |
| var item = itemsSource.GetItem(carouselPosition); |
| @@ -233,10 +233,6 @@ protected async virtual void OnNavigateBack() | |||
| { | |||
| try | |||
| { | |||
There was a problem hiding this comment.
The removed code called Page?.SendBackButtonPressed() before popping the navigation stack, allowing the page to intercept the back navigation via OnBackButtonPressed. Without this call, tapping the Shell navigation bar back button on Android will always pop the page, bypassing any custom OnBackButtonPressed override on the page. This reintroduces the issue originally fixed for Issue33523.
| { | |
| { | |
| // Allow the current page to intercept the back navigation via OnBackButtonPressed | |
| // If SendBackButtonPressed returns true, the back press has been handled and | |
| // we should not pop the navigation stack. | |
| if (Page?.SendBackButtonPressed() ?? false) | |
| return; |
| @@ -15,21 +14,6 @@ internal static void MapIsFocused(IViewHandler handler, IView view) | |||
| ?.UpdateFocusForView(iv); | |||
| } | |||
| } | |||
There was a problem hiding this comment.
The removed MapIsVisible method, which dismissed the soft keyboard when an InputView (Entry/Editor) is hidden, has been reverted. This reintroduces the original problem where typing can continue in a hidden input field on Android and iOS, because the soft keyboard is not dismissed when IsVisible is set to false.
| } | |
| } | |
| internal static void MapIsVisible(IViewHandler handler, IView view) | |
| { | |
| if (view is InputView iv) | |
| { | |
| handler | |
| ?.GetService<HideSoftInputOnTappedChangedManager>() | |
| ?.UpdateFocusForView(iv); | |
| } | |
| } |
Reverts #34173