From 2cc5a7628a48e3d2c91ad543ca7fe80d2ce3899b Mon Sep 17 00:00:00 2001 From: Anandhan Rajagopal <97146406+anandhan-rajagopal@users.noreply.github.com> Date: Thu, 10 Apr 2025 00:53:13 +0530 Subject: [PATCH 01/34] fix for flaky tests (#28887) --- src/Controls/tests/TestCases.HostApp/Issues/Issue10222.cs | 4 +--- .../TestCases.Shared.Tests/Tests/DragAndDropUITests.cs | 6 ++++++ .../tests/TestCases.Shared.Tests/Tests/Issues/Issue10222.cs | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue10222.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue10222.cs index 1a8f2537acc4..70c66126c137 100644 --- a/src/Controls/tests/TestCases.HostApp/Issues/Issue10222.cs +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue10222.cs @@ -64,9 +64,7 @@ async void InitCV() cv.ScrollTo(items.Count - 1); - //give the cv time to scroll - var rand = new Random(); - await Task.Delay(rand.Next(10, 200)); + await Task.Delay(200); await Navigation.PopAsync(false); diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/DragAndDropUITests.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/DragAndDropUITests.cs index 10892df95305..52e0a552fa10 100644 --- a/src/Controls/tests/TestCases.Shared.Tests/Tests/DragAndDropUITests.cs +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/DragAndDropUITests.cs @@ -360,6 +360,12 @@ public void DropEventCoordinates() App.WaitForElement("Green"); App.DragAndDrop("Blue", "Green"); + // Wait for all UI elements to confirm drag and drop operation completion + App.WaitForElement("DropRelativeLayout"); + App.WaitForElement("DropRelativeScreen"); + App.WaitForElement("DropRelativeLabel"); + App.WaitForElement("DragStartRelativeScreen"); + var dropRelativeToLayout = GetCoordinatesFromLabel(App.FindElement("DropRelativeLayout").GetText()); var dropRelativeToScreen = GetCoordinatesFromLabel(App.FindElement("DropRelativeScreen").GetText()); var dropRelativeToLabel = GetCoordinatesFromLabel(App.FindElement("DropRelativeLabel").GetText()); diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue10222.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue10222.cs index 5d241620b172..34b94d7f2f14 100644 --- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue10222.cs +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue10222.cs @@ -18,8 +18,8 @@ public void Issue10222Test() { App.WaitForElement("goTo"); App.Tap("goTo"); - App.WaitForElement("items1"); - App.WaitForElement("goTo"); + App.WaitForElement("items1", timeout: TimeSpan.FromSeconds(1)); + App.WaitForElement("goTo", timeout: TimeSpan.FromSeconds(2)); } } #endif \ No newline at end of file From 43f90d0c48a5857a5e62985bedffc71a0120f5d9 Mon Sep 17 00:00:00 2001 From: Shane Neuville Date: Thu, 10 Apr 2025 08:56:06 -0500 Subject: [PATCH 02/34] Update Versions.props to 9.0.70 SR7 (#28900) --- eng/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index c5d41462f022..7680c27882a1 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -2,7 +2,7 @@ 9 0 - 60 + 70 9.0.100 ci.main From 037fd6c4718ca4728bc57654bcf5c1c25af29fba Mon Sep 17 00:00:00 2001 From: Shane Neuville Date: Thu, 10 Apr 2025 16:55:56 -0500 Subject: [PATCH 03/34] Update bug-report.yml with latest public releases (#28922) --- .github/ISSUE_TEMPLATE/bug-report.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 75922c1cb117..d3d8c3a585b9 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -42,7 +42,10 @@ body: label: Version with bug description: In what version do you see this issue? Run `dotnet workload list` to find your version. options: + - 10.0.0-preview.3 + - 10.0.0-preview.2 - 10.0.0-preview.1 + - 9.0.60 SR6 - 9.0.50 SR5 - 9.0.40 SR4 - 9.0.30 SR3 @@ -165,7 +168,10 @@ body: - 9.0.30 SR3 - 9.0.40 SR4 - 9.0.50 SR5 + - 9.0.60 SR6 - 10.0.0-preview.1 + - 10.0.0-preview.2 + - 10.0.0-preview.3 validations: required: true - type: dropdown From a8e1c3d051071602a243d5a38f105d9e21a7543f Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 11 Apr 2025 11:06:04 +0100 Subject: [PATCH 04/34] Update dependencies from https://github.com/dotnet/xharness build 20250407.3 (#28892) Microsoft.DotNet.XHarness.CLI , Microsoft.DotNet.XHarness.TestRunners.Common , Microsoft.DotNet.XHarness.TestRunners.Xunit From Version 9.0.0-prerelease.25203.2 -> To Version 9.0.0-prerelease.25207.3 Co-authored-by: dotnet-maestro[bot] --- .config/dotnet-tools.json | 2 +- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 8e53d6f23519..60580813dcc0 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -24,7 +24,7 @@ "rollForward": false }, "microsoft.dotnet.xharness.cli": { - "version": "9.0.0-prerelease.25203.2", + "version": "9.0.0-prerelease.25207.3", "commands": [ "xharness" ], diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 29f08eaf2094..d19a59bf2087 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,16 +1,16 @@ - + https://github.com/dotnet/xharness - 1088108e794db714c8a0a74d94da70199a7bc62c + aed708d126f0776c81966db1ca17278edbef8279 - + https://github.com/dotnet/xharness - 1088108e794db714c8a0a74d94da70199a7bc62c + aed708d126f0776c81966db1ca17278edbef8279 - + https://github.com/dotnet/xharness - 1088108e794db714c8a0a74d94da70199a7bc62c + aed708d126f0776c81966db1ca17278edbef8279 diff --git a/eng/Versions.props b/eng/Versions.props index 7680c27882a1..770868809206 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -125,9 +125,9 @@ <_HarfBuzzSharpVersion>8.3.0.1 <_SkiaSharpNativeAssetsVersion>0.0.0-commit.e57e2a11dac4ccc72bea52939dede49816842005.1728 7.0.120 - 9.0.0-prerelease.25203.2 - 9.0.0-prerelease.25203.2 - 9.0.0-prerelease.25203.2 + 9.0.0-prerelease.25207.3 + 9.0.0-prerelease.25207.3 + 9.0.0-prerelease.25207.3 0.9.2 2.0.0.4 1.3.0 From 358f7e73da32b1f06cf2855853f08ad19ca7acd1 Mon Sep 17 00:00:00 2001 From: Bhavanesh N Date: Fri, 11 Apr 2025 20:00:20 +0530 Subject: [PATCH 05/34] fix (#28919) --- .../TestCases.Shared.Tests/Tests/Issues/XFIssue/ShellInsets.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/ShellInsets.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/ShellInsets.cs index 6b73d8fed03c..46bc62808af5 100644 --- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/ShellInsets.cs +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/ShellInsets.cs @@ -129,6 +129,7 @@ public void PaddingWithoutSafeArea() Assert.That(zeroPadding, Is.EqualTo(1)); App.WaitForElement(ResetButton); App.Tap(ResetButton); + App.WaitForElement(PaddingEntry); App.EnterText(PaddingEntry, "100"); App.WaitForElement(PaddingTest); App.Tap(PaddingTest); From ff8cff2f824331ca9db7e2b07d5c3eadd56e3bcd Mon Sep 17 00:00:00 2001 From: Rui Marinho Date: Fri, 11 Apr 2025 15:38:25 +0100 Subject: [PATCH 06/34] [ai] Add release notes prompt (#28896) * [ai]Add release notes prompt * Improve prompt release notes * [ai] improve prompt * [ai] Try map commits to github users * Small update to get correct github user * [ai] Add list of common users * [ai] Remove extra vriable --- .github/prompts/contributors.json | 3926 +++++++++++++++++++++++ .github/prompts/release_notes.prompt.md | 419 +++ .vscode/mcp.json | 26 + maui.code-workspace | 10 + 4 files changed, 4381 insertions(+) create mode 100644 .github/prompts/contributors.json create mode 100644 .github/prompts/release_notes.prompt.md create mode 100644 .vscode/mcp.json create mode 100644 maui.code-workspace diff --git a/.github/prompts/contributors.json b/.github/prompts/contributors.json new file mode 100644 index 000000000000..39c75906ee2a --- /dev/null +++ b/.github/prompts/contributors.json @@ -0,0 +1,3926 @@ +[ + { + "login": "rmarinho", + "id": 1235097, + "type": "User", + "contributions": 2079 + }, + { + "login": "PureWeen", + "id": 5375137, + "type": "User", + "contributions": 1710 + }, + { + "login": "mattleibow", + "id": 1096616, + "type": "User", + "contributions": 1679 + }, + { + "login": "jsuarezruiz", + "id": 6755973, + "type": "User", + "contributions": 1035 + }, + { + "login": "hartez", + "id": 538025, + "type": "User", + "contributions": 958 + }, + { + "login": "dotnet-maestro[bot]", + "id": 42748379, + "type": "Bot", + "contributions": 895 + }, + { + "login": "StephaneDelcroix", + "id": 313003, + "type": "User", + "contributions": 856 + }, + { + "login": "Redth", + "id": 271950, + "type": "User", + "contributions": 781 + }, + { + "login": "github-actions[bot]", + "id": 41898282, + "type": "Bot", + "contributions": 443 + }, + { + "login": "jfversluis", + "id": 939291, + "type": "User", + "contributions": 430 + }, + { + "login": "samhouts", + "id": 7827070, + "type": "User", + "contributions": 415 + }, + { + "login": "jamesmontemagno", + "id": 1676321, + "type": "User", + "contributions": 370 + }, + { + "login": "dependabot[bot]", + "id": 49699333, + "type": "Bot", + "contributions": 337 + }, + { + "login": "jonathanpeppers", + "id": 840039, + "type": "User", + "contributions": 327 + }, + { + "login": "jonlipsky", + "id": 1466386, + "type": "User", + "contributions": 169 + }, + { + "login": "kingces95", + "id": 4120386, + "type": "User", + "contributions": 145 + }, + { + "login": "Eilon", + "id": 202643, + "type": "User", + "contributions": 134 + }, + { + "login": "kubaflo", + "id": 42434498, + "type": "User", + "contributions": 117 + }, + { + "name": "Pavel Yakovlev", + "email": "v-payako@microsoft.com", + "type": "Anonymous", + "contributions": 109 + }, + { + "login": "adrianknight89", + "id": 16855542, + "type": "User", + "contributions": 107 + }, + { + "login": "rookiejava", + "id": 1029134, + "type": "User", + "contributions": 105 + }, + { + "login": "pauldipietro", + "id": 1251024, + "type": "User", + "contributions": 94 + }, + { + "login": "rachelkang", + "id": 21988533, + "type": "User", + "contributions": 92 + }, + { + "login": "anandhan-rajagopal", + "id": 97146406, + "type": "User", + "contributions": 86 + }, + { + "login": "Clancey", + "id": 256046, + "type": "User", + "contributions": 79 + }, + { + "name": "Jason Smith", + "email": "jason.smith@xamarin.com", + "type": "Anonymous", + "contributions": 76 + }, + { + "login": "simonrozsival", + "id": 374616, + "type": "User", + "contributions": 69 + }, + { + "login": "Foda", + "id": 890772, + "type": "User", + "contributions": 66 + }, + { + "login": "pjcollins", + "id": 2000163, + "type": "User", + "contributions": 64 + }, + { + "login": "AndreiMisiukevich", + "id": 10124814, + "type": "User", + "contributions": 61 + }, + { + "login": "myroot", + "id": 1029155, + "type": "User", + "contributions": 60 + }, + { + "login": "tj-devel709", + "id": 50846373, + "type": "User", + "contributions": 60 + }, + { + "login": "MartyIX", + "id": 203266, + "type": "User", + "contributions": 57 + }, + { + "login": "davidortinau", + "id": 41873, + "type": "User", + "contributions": 55 + }, + { + "login": "mandel-macaque", + "id": 2190086, + "type": "User", + "contributions": 55 + }, + { + "login": "pictos", + "id": 20712372, + "type": "User", + "contributions": 51 + }, + { + "login": "drasticactions", + "id": 898335, + "type": "User", + "contributions": 47 + }, + { + "login": "dimonovdd", + "id": 59065470, + "type": "User", + "contributions": 47 + }, + { + "login": "eerhardt", + "id": 8291187, + "type": "User", + "contributions": 42 + }, + { + "login": "albyrock87", + "id": 1423005, + "type": "User", + "contributions": 40 + }, + { + "name": "Mike Corsaro", + "email": "mikecorsaro@microsoft.com", + "type": "Anonymous", + "contributions": 39 + }, + { + "login": "swharden", + "id": 4165489, + "type": "User", + "contributions": 37 + }, + { + "login": "MichaelNorman", + "id": 1462796, + "type": "User", + "contributions": 37 + }, + { + "login": "Tamilarasan-Paranthaman", + "id": 93904422, + "type": "User", + "contributions": 34 + }, + { + "login": "TanayParikh", + "id": 14852843, + "type": "User", + "contributions": 34 + }, + { + "login": "jknaudt21", + "id": 32918747, + "type": "User", + "contributions": 33 + }, + { + "login": "moljac", + "id": 1768576, + "type": "User", + "contributions": 33 + }, + { + "login": "jstedfast", + "id": 338984, + "type": "User", + "contributions": 32 + }, + { + "login": "andreinitescu", + "id": 743918, + "type": "User", + "contributions": 32 + }, + { + "name": "Schilli, Niklas", + "email": "schilli@ams-berlin.de", + "type": "Anonymous", + "contributions": 31 + }, + { + "login": "vividos", + "id": 429902, + "type": "User", + "contributions": 31 + }, + { + "login": "jimmgarrido", + "id": 4087358, + "type": "User", + "contributions": 29 + }, + { + "login": "sbanni", + "id": 1885888, + "type": "User", + "contributions": 28 + }, + { + "login": "shyunMin", + "id": 20968023, + "type": "User", + "contributions": 28 + }, + { + "login": "ravinderjangra", + "id": 9795917, + "type": "User", + "contributions": 28 + }, + { + "name": "Jason Smith", + "email": "jas@microsoft.com", + "type": "Anonymous", + "contributions": 27 + }, + { + "login": "antonfirsov", + "id": 6835152, + "type": "User", + "contributions": 27 + }, + { + "name": "Jonathan Dick", + "email": "jond@hey.com", + "type": "Anonymous", + "contributions": 25 + }, + { + "login": "kvpt", + "id": 1446221, + "type": "User", + "contributions": 25 + }, + { + "login": "mohachouch", + "id": 25939826, + "type": "User", + "contributions": 25 + }, + { + "login": "akihikodaki", + "id": 17036990, + "type": "User", + "contributions": 24 + }, + { + "login": "dustin-wojciechowski", + "id": 89540402, + "type": "User", + "contributions": 24 + }, + { + "login": "NirmalKumarYuvaraj", + "id": 97871636, + "type": "User", + "contributions": 22 + }, + { + "login": "JoonghyunCho", + "id": 14328614, + "type": "User", + "contributions": 22 + }, + { + "login": "jcmanke", + "id": 6132629, + "type": "User", + "contributions": 20 + }, + { + "login": "yurkinh", + "id": 17849938, + "type": "User", + "contributions": 20 + }, + { + "login": "bmacombe", + "id": 15127788, + "type": "User", + "contributions": 20 + }, + { + "login": "BradChase2011", + "id": 13279060, + "type": "User", + "contributions": 20 + }, + { + "login": "devanathan-vaithiyanathan", + "id": 114395405, + "type": "User", + "contributions": 19 + }, + { + "login": "HarishKumarSF4517", + "id": 171316288, + "type": "User", + "contributions": 19 + }, + { + "name": "Luke Westendorf", + "email": "lukewest@microsoft.com", + "type": "Anonymous", + "contributions": 18 + }, + { + "login": "Vignesh-SF3580", + "id": 102575140, + "type": "User", + "contributions": 18 + }, + { + "login": "BretJohnson", + "id": 245892, + "type": "User", + "contributions": 18 + }, + { + "login": "janusw", + "id": 484108, + "type": "User", + "contributions": 17 + }, + { + "login": "lutzroeder", + "id": 438516, + "type": "User", + "contributions": 17 + }, + { + "login": "spadapet", + "id": 2523431, + "type": "User", + "contributions": 17 + }, + { + "login": "newky2k", + "id": 6675766, + "type": "User", + "contributions": 16 + }, + { + "login": "melimion", + "id": 33512073, + "type": "User", + "contributions": 16 + }, + { + "login": "cshung", + "id": 3410332, + "type": "User", + "contributions": 15 + }, + { + "login": "sung-su", + "id": 10704816, + "type": "User", + "contributions": 15 + }, + { + "login": "javiercn", + "id": 6995051, + "type": "User", + "contributions": 14 + }, + { + "login": "MackinnonBuck", + "id": 10456961, + "type": "User", + "contributions": 14 + }, + { + "name": "Niklas Schilli", + "email": "schillinik@yahoo.de", + "type": "Anonymous", + "contributions": 14 + }, + { + "login": "dotMorten", + "id": 1378165, + "type": "User", + "contributions": 14 + }, + { + "login": "symbiogenesis", + "id": 1724472, + "type": "User", + "contributions": 13 + }, + { + "name": "GitHub Actions Autoformatter", + "email": "autoformat@example.com", + "type": "Anonymous", + "contributions": 13 + }, + { + "login": "jkurdek", + "id": 59935235, + "type": "User", + "contributions": 13 + }, + { + "login": "LogishaSelvarajSF4525", + "id": 171314950, + "type": "User", + "contributions": 13 + }, + { + "login": "MarkoBL", + "id": 273464, + "type": "User", + "contributions": 13 + }, + { + "login": "SuthiYuvaraj", + "id": 92777079, + "type": "User", + "contributions": 12 + }, + { + "login": "lytico", + "id": 1479980, + "type": "User", + "contributions": 12 + }, + { + "login": "emaf", + "id": 3286258, + "type": "User", + "contributions": 12 + }, + { + "login": "nivetha-nagalingam", + "id": 170066931, + "type": "User", + "contributions": 11 + }, + { + "login": "dellis1972", + "id": 810617, + "type": "User", + "contributions": 11 + }, + { + "login": "BagavathiPerumal", + "id": 93652794, + "type": "User", + "contributions": 11 + }, + { + "login": "VladislavAntonyuk", + "id": 33021114, + "type": "User", + "contributions": 10 + }, + { + "login": "ivanpovazan", + "id": 55002338, + "type": "User", + "contributions": 10 + }, + { + "login": "alanmcgovern", + "id": 264396, + "type": "User", + "contributions": 10 + }, + { + "login": "vpenades", + "id": 5433822, + "type": "User", + "contributions": 10 + }, + { + "login": "Depechie", + "id": 351693, + "type": "User", + "contributions": 10 + }, + { + "login": "csigs", + "id": 13859395, + "type": "User", + "contributions": 10 + }, + { + "name": "Damian Karzon", + "email": "dkarzon@skedulo.com", + "type": "Anonymous", + "contributions": 10 + }, + { + "login": "kzu", + "id": 169707, + "type": "User", + "contributions": 10 + }, + { + "login": "krdmllr", + "id": 11095003, + "type": "User", + "contributions": 10 + }, + { + "login": "SteveSandersonMS", + "id": 1101362, + "type": "User", + "contributions": 10 + }, + { + "login": "mikescandy", + "id": 2494505, + "type": "User", + "contributions": 9 + }, + { + "login": "alanag13", + "id": 5409649, + "type": "User", + "contributions": 9 + }, + { + "login": "Ahamed-Ali", + "id": 102580874, + "type": "User", + "contributions": 9 + }, + { + "login": "japarson", + "id": 59936622, + "type": "User", + "contributions": 9 + }, + { + "login": "activa", + "id": 650710, + "type": "User", + "contributions": 9 + }, + { + "login": "buyaa-n", + "id": 45579687, + "type": "User", + "contributions": 8 + }, + { + "login": "dalexsoto", + "id": 204671, + "type": "User", + "contributions": 8 + }, + { + "login": "ylatuya", + "id": 111134, + "type": "User", + "contributions": 8 + }, + { + "login": "NanthiniMahalingam", + "id": 105482474, + "type": "User", + "contributions": 8 + }, + { + "name": "Mrnikbobjeff", + "email": "schillinik@yahoo.de", + "type": "Anonymous", + "contributions": 8 + }, + { + "login": "mjbond-msft", + "id": 35508883, + "type": "User", + "contributions": 8 + }, + { + "login": "techduggu", + "id": 17450941, + "type": "User", + "contributions": 7 + }, + { + "login": "etvorun", + "id": 48451158, + "type": "User", + "contributions": 7 + }, + { + "login": "felipebaltazar", + "id": 19656249, + "type": "User", + "contributions": 7 + }, + { + "login": "henricm", + "id": 3715975, + "type": "User", + "contributions": 7 + }, + { + "login": "VitalyKnyazev", + "id": 12721191, + "type": "User", + "contributions": 7 + }, + { + "login": "almirvuk", + "id": 15986629, + "type": "User", + "contributions": 7 + }, + { + "login": "brunck", + "id": 4502210, + "type": "User", + "contributions": 7 + }, + { + "login": "conceptdev", + "id": 199373, + "type": "User", + "contributions": 7 + }, + { + "login": "yourina", + "id": 20967778, + "type": "User", + "contributions": 6 + }, + { + "login": "kicsiede", + "id": 4233752, + "type": "User", + "contributions": 6 + }, + { + "login": "dotnet-bot", + "id": 9011267, + "type": "User", + "contributions": 6 + }, + { + "login": "bentmar", + "id": 10244000, + "type": "User", + "contributions": 6 + }, + { + "login": "knocte", + "id": 331303, + "type": "User", + "contributions": 6 + }, + { + "login": "dansiegel", + "id": 3860573, + "type": "User", + "contributions": 6 + }, + { + "login": "ionixjunior", + "id": 519642, + "type": "User", + "contributions": 6 + }, + { + "login": "WayaFlyfeather", + "id": 3807144, + "type": "User", + "contributions": 6 + }, + { + "login": "GalaxiaGuy", + "id": 475450, + "type": "User", + "contributions": 6 + }, + { + "login": "sps014", + "id": 45932883, + "type": "User", + "contributions": 6 + }, + { + "login": "TimBarham", + "id": 9665847, + "type": "User", + "contributions": 6 + }, + { + "login": "Viridovics", + "id": 6348792, + "type": "User", + "contributions": 6 + }, + { + "login": "mkieres", + "id": 8372764, + "type": "User", + "contributions": 5 + }, + { + "login": "eltociear", + "id": 22633385, + "type": "User", + "contributions": 5 + }, + { + "login": "bill2004158", + "id": 211855, + "type": "User", + "contributions": 5 + }, + { + "login": "bruzkovsky", + "id": 10390959, + "type": "User", + "contributions": 5 + }, + { + "login": "molesmoke", + "id": 3227864, + "type": "User", + "contributions": 5 + }, + { + "login": "lindexi", + "id": 16054566, + "type": "User", + "contributions": 5 + }, + { + "login": "VSadov", + "id": 8218165, + "type": "User", + "contributions": 5 + }, + { + "login": "vs-mobiletools-engineering-service2", + "id": 67918504, + "type": "User", + "contributions": 5 + }, + { + "login": "peterfoot", + "id": 3985053, + "type": "User", + "contributions": 5 + }, + { + "login": "dhindrik", + "id": 6691971, + "type": "User", + "contributions": 5 + }, + { + "login": "TheCodeTraveler", + "id": 13558917, + "type": "User", + "contributions": 5 + }, + { + "login": "Dhivya-SF4094", + "id": 127717131, + "type": "User", + "contributions": 5 + }, + { + "login": "edsnider", + "id": 557602, + "type": "User", + "contributions": 5 + }, + { + "login": "f1nzer", + "id": 1970236, + "type": "User", + "contributions": 5 + }, + { + "login": "MSLukeWest", + "id": 42553283, + "type": "User", + "contributions": 5 + }, + { + "login": "mgoertz-msft", + "id": 14282894, + "type": "User", + "contributions": 5 + }, + { + "login": "mrlacey", + "id": 189547, + "type": "User", + "contributions": 5 + }, + { + "name": "Matthew Richardson", + "email": "matthew@velocitysystems.co.nz", + "type": "Anonymous", + "contributions": 5 + }, + { + "login": "mhutch", + "id": 183285, + "type": "User", + "contributions": 5 + }, + { + "login": "NafeelaNazhir", + "id": 171174978, + "type": "User", + "contributions": 5 + }, + { + "login": "bhavanesh2001", + "id": 184209926, + "type": "User", + "contributions": 4 + }, + { + "login": "slang25", + "id": 1341446, + "type": "User", + "contributions": 4 + }, + { + "login": "Cheesebaron", + "id": 249719, + "type": "User", + "contributions": 4 + }, + { + "login": "WonyoungChoi", + "id": 1029205, + "type": "User", + "contributions": 4 + }, + { + "login": "KSemenenko", + "id": 4385716, + "type": "User", + "contributions": 4 + }, + { + "login": "memu8", + "id": 66331238, + "type": "User", + "contributions": 4 + }, + { + "login": "prakashKannanSf3972", + "id": 127308739, + "type": "User", + "contributions": 4 + }, + { + "login": "vishnumenon2684", + "id": 95695113, + "type": "User", + "contributions": 4 + }, + { + "login": "jonpryor", + "id": 155958, + "type": "User", + "contributions": 4 + }, + { + "login": "IlGalvo", + "id": 17992288, + "type": "User", + "contributions": 4 + }, + { + "login": "CliffAgius", + "id": 5613809, + "type": "User", + "contributions": 4 + }, + { + "login": "mfkl", + "id": 3928834, + "type": "User", + "contributions": 4 + }, + { + "login": "vhugogarcia", + "id": 1047398, + "type": "User", + "contributions": 4 + }, + { + "login": "bares43", + "id": 956930, + "type": "User", + "contributions": 4 + }, + { + "login": "flish", + "id": 3818800, + "type": "User", + "contributions": 4 + }, + { + "login": "BrayanKhosravian", + "id": 35541212, + "type": "User", + "contributions": 4 + }, + { + "login": "daltzctr", + "id": 105223895, + "type": "User", + "contributions": 4 + }, + { + "login": "ederbond", + "id": 12549812, + "type": "User", + "contributions": 4 + }, + { + "login": "adamped", + "id": 13672662, + "type": "User", + "contributions": 4 + }, + { + "login": "filipnavara", + "id": 1764393, + "type": "User", + "contributions": 4 + }, + { + "login": "praeclarum", + "id": 323548, + "type": "User", + "contributions": 4 + }, + { + "login": "J-Swift", + "id": 734158, + "type": "User", + "contributions": 4 + }, + { + "login": "jvansickle", + "id": 7631608, + "type": "User", + "contributions": 4 + }, + { + "login": "MartinZikmund", + "id": 1075116, + "type": "User", + "contributions": 4 + }, + { + "login": "BioTurboNick", + "id": 1438610, + "type": "User", + "contributions": 4 + }, + { + "login": "legistek", + "id": 13384523, + "type": "User", + "contributions": 4 + }, + { + "login": "pranavkm", + "id": 174281, + "type": "User", + "contributions": 4 + }, + { + "login": "rolfbjarne", + "id": 249268, + "type": "User", + "contributions": 4 + }, + { + "login": "scastria", + "id": 4534494, + "type": "User", + "contributions": 4 + }, + { + "name": "Paul DiPietro", + "email": "paul.dipietro@microsoft.com", + "type": "Anonymous", + "contributions": 3 + }, + { + "login": "rogihee", + "id": 4984486, + "type": "User", + "contributions": 3 + }, + { + "login": "stmoor", + "id": 77985069, + "type": "User", + "contributions": 3 + }, + { + "login": "sthewissen", + "id": 2419439, + "type": "User", + "contributions": 3 + }, + { + "login": "SubhikshaSf4851", + "id": 184361895, + "type": "User", + "contributions": 3 + }, + { + "login": "TamilarasanSF4853", + "id": 184361845, + "type": "User", + "contributions": 3 + }, + { + "login": "YZahringer", + "id": 4254116, + "type": "User", + "contributions": 3 + }, + { + "login": "Youssef1313", + "id": 31348972, + "type": "User", + "contributions": 3 + }, + { + "login": "jzeferino", + "id": 10722952, + "type": "User", + "contributions": 3 + }, + { + "login": "puppetSpace", + "id": 14003064, + "type": "User", + "contributions": 3 + }, + { + "login": "solomonfried", + "id": 36649129, + "type": "User", + "contributions": 3 + }, + { + "login": "tessarolli", + "id": 11618432, + "type": "User", + "contributions": 3 + }, + { + "login": "magoolation", + "id": 626364, + "type": "User", + "contributions": 3 + }, + { + "login": "beeradmoore", + "id": 904737, + "type": "User", + "contributions": 3 + }, + { + "login": "jgold6", + "id": 4606509, + "type": "User", + "contributions": 3 + }, + { + "login": "akoeplinger", + "id": 1376924, + "type": "User", + "contributions": 3 + }, + { + "login": "patridge", + "id": 713665, + "type": "User", + "contributions": 3 + }, + { + "login": "aaronfranke", + "id": 1646875, + "type": "User", + "contributions": 3 + }, + { + "login": "artemious7", + "id": 16724889, + "type": "User", + "contributions": 3 + }, + { + "login": "artemvalieiev", + "id": 3391032, + "type": "User", + "contributions": 3 + }, + { + "login": "Axemasta", + "id": 33064621, + "type": "User", + "contributions": 3 + }, + { + "login": "BjornVanslembrouck", + "id": 44607491, + "type": "User", + "contributions": 3 + }, + { + "login": "daniel-luberda", + "id": 13569983, + "type": "User", + "contributions": 3 + }, + { + "login": "DianaSoltani", + "id": 31975705, + "type": "User", + "contributions": 3 + }, + { + "login": "ooikengsiang", + "id": 19687809, + "type": "User", + "contributions": 3 + }, + { + "login": "mikeparker104", + "id": 12763221, + "type": "User", + "contributions": 3 + }, + { + "login": "MichaelRumpler", + "id": 8309363, + "type": "User", + "contributions": 3 + }, + { + "login": "mkhamoyan", + "id": 96171496, + "type": "User", + "contributions": 3 + }, + { + "login": "Lehonti", + "id": 17771375, + "type": "User", + "contributions": 3 + }, + { + "login": "jeffhandley", + "id": 1031940, + "type": "User", + "contributions": 3 + }, + { + "login": "SotoiGhost", + "id": 5924210, + "type": "User", + "contributions": 3 + }, + { + "login": "GiampaoloGabba", + "id": 8319337, + "type": "User", + "contributions": 3 + }, + { + "login": "felipemomm", + "id": 6777353, + "type": "User", + "contributions": 3 + }, + { + "login": "espenrl", + "id": 4621581, + "type": "User", + "contributions": 3 + }, + { + "login": "jpobst", + "id": 179295, + "type": "User", + "contributions": 2 + }, + { + "login": "RodgerLeblanc", + "id": 6235690, + "type": "User", + "contributions": 2 + }, + { + "login": "SpiegelSoft", + "id": 557824, + "type": "User", + "contributions": 2 + }, + { + "login": "rick-palmsens", + "id": 57390463, + "type": "User", + "contributions": 2 + }, + { + "login": "nogginbox", + "id": 729381, + "type": "User", + "contributions": 2 + }, + { + "login": "JTOne123", + "id": 3457140, + "type": "User", + "contributions": 2 + }, + { + "login": "PaulAndersonS", + "id": 42271912, + "type": "User", + "contributions": 2 + }, + { + "login": "ntherning", + "id": 135765, + "type": "User", + "contributions": 2 + }, + { + "login": "pingzing", + "id": 5133649, + "type": "User", + "contributions": 2 + }, + { + "login": "manutdkid77", + "id": 14297705, + "type": "User", + "contributions": 2 + }, + { + "login": "nwestfall", + "id": 4753021, + "type": "User", + "contributions": 2 + }, + { + "login": "Moha69100", + "id": 6330427, + "type": "User", + "contributions": 2 + }, + { + "login": "mjmostachetti", + "id": 6486831, + "type": "User", + "contributions": 2 + }, + { + "login": "migueldeicaza", + "id": 36863, + "type": "User", + "contributions": 2 + }, + { + "login": "mauroa", + "id": 2921919, + "type": "User", + "contributions": 2 + }, + { + "login": "mattjohnsonpint", + "id": 1396388, + "type": "User", + "contributions": 2 + }, + { + "login": "martincostello", + "id": 1439341, + "type": "User", + "contributions": 2 + }, + { + "login": "marcmognol", + "id": 8171300, + "type": "User", + "contributions": 2 + }, + { + "login": "domagojmedo", + "id": 12157224, + "type": "User", + "contributions": 2 + }, + { + "login": "DavidRoqueni", + "id": 45717673, + "type": "User", + "contributions": 2 + }, + { + "login": "Dresel", + "id": 1769090, + "type": "User", + "contributions": 2 + }, + { + "login": "Adam--", + "id": 2179171, + "type": "User", + "contributions": 2 + }, + { + "login": "workgroupengineering", + "id": 12531229, + "type": "User", + "contributions": 2 + }, + { + "login": "ruby-verma", + "id": 20953456, + "type": "User", + "contributions": 2 + }, + { + "login": "praveenkumarkarunanithi", + "id": 100338903, + "type": "User", + "contributions": 2 + }, + { + "login": "neolithos", + "id": 9724420, + "type": "User", + "contributions": 2 + }, + { + "login": "maonaoda", + "id": 32831595, + "type": "User", + "contributions": 2 + }, + { + "login": "flyofsky", + "id": 16184582, + "type": "User", + "contributions": 2 + }, + { + "login": "dotnet-policy-service[bot]", + "id": 123482357, + "type": "Bot", + "contributions": 2 + }, + { + "name": "dend", + "email": "dend@outlook.com", + "type": "Anonymous", + "contributions": 2 + }, + { + "login": "campersau", + "id": 4009570, + "type": "User", + "contributions": 2 + }, + { + "login": "WeihanLi", + "id": 7604648, + "type": "User", + "contributions": 2 + }, + { + "login": "vitek-karas", + "id": 10670590, + "type": "User", + "contributions": 2 + }, + { + "login": "surayya-MS", + "id": 114938397, + "type": "User", + "contributions": 2 + }, + { + "login": "stephen-hawley", + "id": 15199050, + "type": "User", + "contributions": 2 + }, + { + "login": "sanyandreichuk", + "id": 8818052, + "type": "User", + "contributions": 2 + }, + { + "login": "Rustamxon", + "id": 123984585, + "type": "User", + "contributions": 2 + }, + { + "login": "maxkoshevoi", + "id": 6609929, + "type": "User", + "contributions": 2 + }, + { + "login": "dmariogatto", + "id": 8588913, + "type": "User", + "contributions": 2 + }, + { + "login": "breenbob", + "id": 6000851, + "type": "User", + "contributions": 2 + }, + { + "login": "cadsit", + "id": 9328605, + "type": "User", + "contributions": 2 + }, + { + "login": "cschwarz", + "id": 717934, + "type": "User", + "contributions": 2 + }, + { + "login": "csteeg", + "id": 431177, + "type": "User", + "contributions": 2 + }, + { + "login": "chabiss", + "id": 14151258, + "type": "User", + "contributions": 2 + }, + { + "login": "bricelam", + "id": 1226749, + "type": "User", + "contributions": 2 + }, + { + "login": "Bobface", + "id": 10945014, + "type": "User", + "contributions": 2 + }, + { + "login": "BitooBit", + "id": 59031286, + "type": "User", + "contributions": 2 + }, + { + "login": "BurningLights", + "id": 14267553, + "type": "User", + "contributions": 2 + }, + { + "login": "mkArtakMSFT", + "id": 34246760, + "type": "User", + "contributions": 2 + }, + { + "login": "andres-fg", + "id": 16245738, + "type": "User", + "contributions": 2 + }, + { + "login": "SkyeHoefling", + "id": 17751436, + "type": "User", + "contributions": 2 + }, + { + "login": "AArnott", + "id": 3548, + "type": "User", + "contributions": 2 + }, + { + "login": "andreas-nesheim", + "id": 11583629, + "type": "User", + "contributions": 2 + }, + { + "login": "aheubusch", + "id": 11393955, + "type": "User", + "contributions": 2 + }, + { + "login": "appsourcers", + "id": 36886162, + "type": "User", + "contributions": 2 + }, + { + "login": "agaluzzi", + "id": 5098044, + "type": "User", + "contributions": 2 + }, + { + "login": "akamud", + "id": 954102, + "type": "User", + "contributions": 2 + }, + { + "login": "HavenDV", + "id": 3002068, + "type": "User", + "contributions": 2 + }, + { + "login": "KarthikRajaKalaimani", + "id": 92777139, + "type": "User", + "contributions": 2 + }, + { + "login": "jorisvergeer", + "id": 1906639, + "type": "User", + "contributions": 2 + }, + { + "login": "Suplanus", + "id": 2002916, + "type": "User", + "contributions": 2 + }, + { + "login": "lateralusX", + "id": 11529140, + "type": "User", + "contributions": 2 + }, + { + "login": "joelmartinez", + "id": 90380, + "type": "User", + "contributions": 2 + }, + { + "login": "jsmarcus", + "id": 1919776, + "type": "User", + "contributions": 2 + }, + { + "name": "Dave Humphreys", + "email": "dave@thing.com", + "type": "Anonymous", + "contributions": 2 + }, + { + "login": "dend", + "id": 1389609, + "type": "User", + "contributions": 2 + }, + { + "login": "breyed", + "id": 1299073, + "type": "User", + "contributions": 2 + }, + { + "login": "thudugala", + "id": 4112014, + "type": "User", + "contributions": 2 + }, + { + "login": "EmilAlipiev", + "id": 10422347, + "type": "User", + "contributions": 2 + }, + { + "name": "Israel Soto", + "email": "issoto@microsoft.com", + "type": "Anonymous", + "contributions": 2 + }, + { + "login": "terrajobst", + "id": 5169960, + "type": "User", + "contributions": 2 + }, + { + "login": "ethanis", + "id": 8703324, + "type": "User", + "contributions": 2 + }, + { + "login": "fredeil", + "id": 17533404, + "type": "User", + "contributions": 2 + }, + { + "login": "ghuntley", + "id": 127353, + "type": "User", + "contributions": 2 + }, + { + "name": "Stefan de Vogelaere", + "email": "stefan@cavebirdlabs.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Stefan Gerasch", + "email": "stefangerasch1991@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Stanislav", + "email": "stasbav@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Sreeraj P R", + "email": "sreerajpr.mec@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Soundman32", + "email": "neil.scales@outlook.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Soichi Ikebe", + "email": "souichi1997@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Softlion (Benjamin Mayrargue)", + "email": "benjamin@vapolia.fr", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Softlion (Benjamin Mayrargue)", + "email": "benjamin@mayrargue.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Smit Patel", + "email": "smitpatel@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Sivamuthu Kumar", + "email": "sivamuthukumar07@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Sivakumar", + "email": "sivakumarr@syncfusion.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Simon Cropp", + "email": "simon.cropp@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Shalini-Ashokan", + "email": "102292178+shalini-ashokan@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Sergio Escalada", + "email": "sescalada@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Sergej Derjabkin", + "email": "sergej@sendev.de", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Sebastian Rauer", + "email": "info@sebastianrauer.de", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Sean Killeen", + "email": "seankilleen@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Sean Davies", + "email": "spdavies2@live.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Sandro Cavazzoni", + "email": "sandro@ideaful.it", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Samir GC", + "email": "55045516+samirgcofficial@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Todd", + "email": "thenderson21@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "TingtingAn", + "email": "antingting2009@qq.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Timothé Larivière", + "email": "timothe.lariviere@outlook.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Tim Johnson", + "email": "t-johnson@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Tianqi Zhang", + "email": "tianqizhang@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Thomas Muller", + "email": "imuller@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Thomas Mijieux", + "email": "tmijieux@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Thetyne", + "email": "thetyne@live.fr", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Theodore Tsirpanis", + "email": "teo-tsirpanis@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Takym (たかやま)", + "email": "15681312+takym@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Takaaki Suzuki", + "email": "xin9le@live.jp", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Sławomir Kulików", + "email": "slawomir.kulikow@outlook.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Sławomir Kulików", + "email": "kulikow@logotec.pl", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Sören Nils Kuklau", + "email": "chucker@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Symbai", + "email": "14368203+symbai@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Sylvain Gravel", + "email": "lrp-sgravel@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "SyedAbdulAzeemSF4852", + "email": "syedabdulazeem.a@syncfusion.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Sven Boemer", + "email": "sbomer@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Surayya Huseyn Zada", + "email": "shuseynzada@microsoft.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Sunner", + "email": "sunnerlp@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "StevenGranados", + "email": "51818199+stevengranados@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Steve", + "email": "steverichey@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Stephen Halter", + "email": "halter73@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Sam", + "email": "28056243+faheys@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Peter Spada", + "email": "spadapet@outlook.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "PawKanarek", + "email": "paw.kanarek@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "PavloLukianets", + "email": "109070173+pavlolukianets@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Pavel Yakovlev (Akvelon)", + "email": "v-payako@microsoft.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Patrick Long", + "email": "pat@munkiisoft.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Patrick Hartman", + "email": "patrick@leglock.net", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Patrick Allwood", + "email": "patchandthat@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Parker Bibus", + "email": "pbibus@hotmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Parker Bibus", + "email": "parkerbibus@microsoft.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "P3PPP", + "email": "ticktackmob@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Oren Novotny", + "email": "oren@novotny.org", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Ooi Keng Siang", + "email": "ks@ooiks.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Omniq-APL-Rollving", + "email": "61408543+omniq-apl-rollving@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Oleksandr Dobrynin", + "email": "shuron1988@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Oleh Kaliuzhnyi", + "email": "oleg.kaliuzhny@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Oddbjørn Bakke", + "email": "oddbjorn.bakke@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Oberdan Bitencourt Ferreira", + "email": "oberdan.bitencourt@arctouch.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Noam Yogev", + "email": "noamyogev84@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Niklas Therning", + "email": "nitherni@microsoft.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Niklas Schilli", + "email": "niklasschilli@mailbox.org", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Niklas Schilli", + "email": "n.schilli@inno-focus.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Niels van der Knaap", + "email": "niels@nielsknaap.nl", + "type": "Anonymous", + "contributions": 1 + }, + { + "login": "CartBlanche", + "id": 271363, + "type": "User", + "contributions": 1 + }, + { + "name": "Salar K", + "email": "1272095+salarcode@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Safia Abdalla", + "email": "safia@safia.rocks", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Ryo Tsunoda", + "email": "try0.development@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Ryan Robidou", + "email": "robidou@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Ryan Davis", + "email": "ryandavis.au@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Ryan Buckley", + "email": "9486206+rabuckley@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Rui Marinho", + "email": "ruimarinho@msft-m3-pro.ihome", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Roy", + "email": "royvou@hotmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Ronny Gunawan", + "email": "3048897+ronnygunawan@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Ronan", + "email": "burkuscat@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Roger Hardiman", + "email": "rogerhardiman@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Rasto", + "email": "rasto@duracellko.net", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Rastislav Novotný", + "email": "rasto@duracellko.net", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Raka Rasell", + "email": "rrrraka@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Rafal", + "email": "rkdevel@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Precious Nyasulu", + "email": "preciousnyasulu441@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Praga Siva", + "email": "praga@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Poppyto", + "email": "poppyto@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Pieter Nijs", + "email": "pieternijs@live.be", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Pierre Henri", + "email": "pierrehenrikt@kleartouch.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Pierre Galaup", + "email": "pierregalaup@outlook.fr", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Philipp Sumi", + "email": "hardcodet@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Phil Henning", + "email": "phenning@microsoft.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "nextfool", + "email": "nextfool@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "nels83", + "email": "nels+git@pgroupe.net", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "nalka0", + "email": "30848600+nalka0@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "mos379", + "email": "45105519+mos379@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "mohsen bagheri", + "email": "85581484+mohsenbgi@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "michalpobuta", + "email": "52126292+michalpobuta@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "matt4pi", + "email": "matt@4pi.com.au", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "masonyc", + "email": "mason.yunchen@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "mallibone", + "email": "mallibone@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "maexsp", + "email": "maex.sp@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "luyajun0205", + "email": "v-yajlu@microsoft.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "lewcianci", + "email": "lewcianci@hotmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "kadiryazgan", + "email": "kadiryazgan@msn.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "juliuszint", + "email": "julius.zint@awin-software.de", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "jpiechowiak", + "email": "jerzy.piechowiak@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "jonlipsky", + "email": "jonlipsky@github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "john-larson", + "email": "21021544+john-larson@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "joepgrooten", + "email": "52749854+joepgrooten@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "jaytilly", + "email": "jt@jaybirdlabs.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "jacobmcgoogan", + "email": "jacob.mcgoogan@allscripts.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "inforithmics", + "email": "thomas.stocker@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "indydawgy", + "email": "tophe112@yahoo.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Xiangwei Cai", + "email": "v-caxian@microsoft.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "zhuXinghan", + "email": "1097278366@qq.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "z3ut", + "email": "z3ut@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "ytn3rd", + "email": "b.moore@4pilabs.com.au", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "yone64", + "email": "yone64@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "wplong11", + "email": "wplong11@naver.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "woutermeuwis", + "email": "wouter.meuwis@3factr.be", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "webwarrior-ws", + "email": "webwarrior-ws@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "weases", + "email": "richard.wiesinger@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "v-haroha", + "email": "51649153+v-haroha@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "tomeverin", + "email": "24466690+tomeverin@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "tj-devel709", + "email": "tj.devel709@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "thisisthekap", + "email": "christian.kapplmueller@tonestro.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "thisisthekap", + "email": "c.kapplmueller@me.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "spruceDevelopment", + "email": "33689503+sprucedevelopment@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "softlion", + "email": "benjamin@vapolia.fr", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "sheiksyedm", + "email": "sheiksyedm@syncfusion.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "sahi82", + "email": "sahi82@yahoo.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "rjantz3", + "email": "rjantz3@msn.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "qmark", + "email": "dimka.qmark@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "pit", + "email": "37137614+pitmobile@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "piotrkonowalski", + "email": "piotrkonowalski@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "pRopia", + "email": "pratik.ropia@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "nor0x", + "email": "nor0x@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Will Davies", + "email": "wdavies973@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "WdeBruin", + "email": "wouterdebruin88@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Vũ Đức Tuyến", + "email": "tuyen@naxam.net", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Víctor Martos", + "email": "vmareg@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Víctor Guzmán", + "email": "vgzman+github@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Vojtěch Mádr", + "email": "madrvojtech@outlook.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Vlada Shubina", + "email": "vshubina@microsoft.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Vinicius Jarina", + "email": "viniciusjarina@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Vincent Hoogendoorn", + "email": "vincenth.net@outlook.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Vincent Dondain", + "email": "vincentdondain@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Vincent Costel", + "email": "vincent.costel@apcurium.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Vijay Anand E G", + "email": "81947404+egvijayanand@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Tushar Koshti", + "email": "koshtitushar1994@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Trung Nguyen", + "email": "57174311+trungnt2910@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Trivalik", + "email": "3148279+trivalik@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Toni Petrina", + "email": "tonipetrina@hotmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Tomáš Ondřej", + "email": "45392392+tomond@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Tommi Gustafsson", + "email": "tommi.gustafsson@hyvanmielenpelit.fi", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Tomasz Ścisłowicz", + "email": "toomasz@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Tomasz Cielecki", + "email": "249719+cheesebaron@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Tom Meschter", + "email": "tom.meschter@valinor.org", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Tom Gilder", + "email": "tom@tom.me.uk", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "hydrogen-software-ff", + "email": "81678363+hydrogen-software-ff@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "humhei", + "email": "humhei@outlook.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "gleblebedev", + "email": "gleb@gleblebedev.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "genriquez", + "email": "genriquez@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "fengrui", + "email": "fengrui358@163.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "dottienet", + "email": "61212782+dottienet@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "dogukandemir", + "email": "dogukandemir@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "digitaldirk", + "email": "22691956+digitaldirk@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "dgeller-OUHSC", + "email": "dgeller@ouhsc.edu", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "dartasen", + "email": "10561268+dartasen@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "cliff v", + "email": "powerdude@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "ckrempp91", + "email": "chrisk@msidata.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "chenrensong", + "email": "chenrensong@outlook.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "cat0363", + "email": "125236133+cat0363@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "borrmann", + "email": "max.borrmann@gmx.net", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "atoghyani", + "email": "ariantoghyani@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "adammeaney", + "email": "meaneykid2@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "acuntex", + "email": "werner@welsch.cc", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Yusuke Yamada", + "email": "yamachu.dev@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Yunus Efendi", + "email": "19399214+yunusefendi52@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Yun Chen", + "email": "mason.yunchen@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Youssef Victor", + "email": "31348972+youssef1313@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Yaser Moradi", + "email": "ysmoradi@outlook.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "login": "LyalinDotCom", + "id": 2363526, + "type": "User", + "contributions": 1 + }, + { + "login": "ChasakisD", + "id": 23040695, + "type": "User", + "contributions": 1 + }, + { + "login": "humblehacker", + "id": 117582, + "type": "User", + "contributions": 1 + }, + { + "login": "EislerDavid", + "id": 48833197, + "type": "User", + "contributions": 1 + }, + { + "login": "davidbritch", + "id": 8092460, + "type": "User", + "contributions": 1 + }, + { + "name": "Dave Humphreys", + "email": "dave@none.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "login": "danielwilliamson", + "id": 6487407, + "type": "User", + "contributions": 1 + }, + { + "login": "danielmarbach", + "id": 174258, + "type": "User", + "contributions": 1 + }, + { + "login": "danielchalmers", + "id": 7112040, + "type": "User", + "contributions": 1 + }, + { + "login": "danmoseley", + "id": 6385855, + "type": "User", + "contributions": 1 + }, + { + "login": "DamianMehers", + "id": 1457446, + "type": "User", + "contributions": 1 + }, + { + "login": "dkarzon", + "id": 214449, + "type": "User", + "contributions": 1 + }, + { + "login": "Csaba8472", + "id": 483692, + "type": "User", + "contributions": 1 + }, + { + "login": "craigloewen-msft", + "id": 42221804, + "type": "User", + "contributions": 1 + }, + { + "login": "CleanCodeDeveloper", + "id": 16760760, + "type": "User", + "contributions": 1 + }, + { + "login": "csdinon", + "id": 24420845, + "type": "User", + "contributions": 1 + }, + { + "login": "Choza-rajan", + "id": 92723643, + "type": "User", + "contributions": 1 + }, + { + "login": "Chase-William", + "id": 46757278, + "type": "User", + "contributions": 1 + }, + { + "login": "ChaseMarsh", + "id": 19700403, + "type": "User", + "contributions": 1 + }, + { + "login": "charlesroddie", + "id": 19760720, + "type": "User", + "contributions": 1 + }, + { + "name": "Charles Petzold", + "email": "chape@microsoft.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "login": "kvochko", + "id": 2308830, + "type": "User", + "contributions": 1 + }, + { + "name": "Max Brister", + "email": "a+github@2bass.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "login": "Giviruk", + "id": 42971690, + "type": "User", + "contributions": 1 + }, + { + "login": "giuseppe-guerra", + "id": 11569903, + "type": "User", + "contributions": 1 + }, + { + "login": "Ghostbird", + "id": 1202149, + "type": "User", + "contributions": 1 + }, + { + "login": "tarasverq", + "id": 8226275, + "type": "User", + "contributions": 1 + }, + { + "login": "JoergMeier106", + "id": 22917826, + "type": "User", + "contributions": 1 + }, + { + "login": "gabor-nemeth", + "id": 37656640, + "type": "User", + "contributions": 1 + }, + { + "login": "FriedrichRehren", + "id": 22966022, + "type": "User", + "contributions": 1 + }, + { + "login": "fredyadriano90", + "id": 25233851, + "type": "User", + "contributions": 1 + }, + { + "login": "kiok85", + "id": 158862689, + "type": "User", + "contributions": 1 + }, + { + "login": "francedot", + "id": 11706033, + "type": "User", + "contributions": 1 + }, + { + "login": "fenxu", + "id": 12146082, + "type": "User", + "contributions": 1 + }, + { + "login": "IIFabixn", + "id": 92400234, + "type": "User", + "contributions": 1 + }, + { + "login": "EP01", + "id": 22454118, + "type": "User", + "contributions": 1 + }, + { + "login": "eth-ellis", + "id": 13865151, + "type": "User", + "contributions": 1 + }, + { + "login": "Eschryn", + "id": 8217655, + "type": "User", + "contributions": 1 + }, + { + "login": "modplug", + "id": 789588, + "type": "User", + "contributions": 1 + }, + { + "login": "jingliancui", + "id": 16309962, + "type": "User", + "contributions": 1 + }, + { + "login": "eliaspuurunen", + "id": 695294, + "type": "User", + "contributions": 1 + }, + { + "login": "Elashi", + "id": 12378171, + "type": "User", + "contributions": 1 + }, + { + "login": "wachs", + "id": 12235778, + "type": "User", + "contributions": 1 + }, + { + "name": "Edwin Wachs", + "email": "edwin.wachs@tecfinance.com.br", + "type": "Anonymous", + "contributions": 1 + }, + { + "login": "Eden-Mor", + "id": 20691183, + "type": "User", + "contributions": 1 + }, + { + "name": "Andrew Hoefling", + "email": "andrew@hoeflingsoftware.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "login": "awaescher", + "id": 3630638, + "type": "User", + "contributions": 1 + }, + { + "login": "AndersRasmussen", + "id": 213707, + "type": "User", + "contributions": 1 + }, + { + "login": "AmrAlSayed0", + "id": 2955032, + "type": "User", + "contributions": 1 + }, + { + "login": "AlleSchonWeg", + "id": 6727366, + "type": "User", + "contributions": 1 + }, + { + "login": "aritchie", + "id": 1431555, + "type": "User", + "contributions": 1 + }, + { + "login": "alfredmyers", + "id": 12210687, + "type": "User", + "contributions": 1 + }, + { + "login": "AxelUser", + "id": 7935489, + "type": "User", + "contributions": 1 + }, + { + "login": "cacti-acaprais", + "id": 43949501, + "type": "User", + "contributions": 1 + }, + { + "login": "NordAlex", + "id": 6042648, + "type": "User", + "contributions": 1 + }, + { + "login": "ahouben", + "id": 2446666, + "type": "User", + "contributions": 1 + }, + { + "name": "Alexander Hardwicke", + "email": "alex.hardwicke@outlook.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "login": "Pandalink", + "id": 18328783, + "type": "User", + "contributions": 1 + }, + { + "login": "adrianhall", + "id": 1489465, + "type": "User", + "contributions": 1 + }, + { + "login": "adamsitnik", + "id": 6011991, + "type": "User", + "contributions": 1 + }, + { + "login": "APoukar", + "id": 36044908, + "type": "User", + "contributions": 1 + }, + { + "name": "Adam Pedley", + "email": "adam.pedley@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "login": "adamivancza", + "id": 19835917, + "type": "User", + "contributions": 1 + }, + { + "login": "adambarath", + "id": 14049972, + "type": "User", + "contributions": 1 + }, + { + "login": "1iveowl", + "id": 12871120, + "type": "User", + "contributions": 1 + }, + { + "login": "1d0n7kn0w", + "id": 3910210, + "type": "User", + "contributions": 1 + }, + { + "login": "1c3f0x84", + "id": 35239416, + "type": "User", + "contributions": 1 + }, + { + "name": "Chad Kimes", + "email": "chad.kimes@iticentral.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "login": "kericbowman", + "id": 12725288, + "type": "User", + "contributions": 1 + }, + { + "login": "breezy64", + "id": 3731287, + "type": "User", + "contributions": 1 + }, + { + "login": "bkaankose", + "id": 12009960, + "type": "User", + "contributions": 1 + }, + { + "login": "Brucepimenta", + "id": 37835327, + "type": "User", + "contributions": 1 + }, + { + "login": "brainoffline", + "id": 1763877, + "type": "User", + "contributions": 1 + }, + { + "login": "bradencohen", + "id": 11482832, + "type": "User", + "contributions": 1 + }, + { + "login": "TrueGeek", + "id": 90821, + "type": "User", + "contributions": 1 + }, + { + "login": "bbenetskyy", + "id": 8330262, + "type": "User", + "contributions": 1 + }, + { + "name": "Bohdan Benetskyi", + "email": "bbenetskyi@pgs-soft.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "login": "bwoebi", + "id": 3154871, + "type": "User", + "contributions": 1 + }, + { + "login": "BinaryCraX", + "id": 5560801, + "type": "User", + "contributions": 1 + }, + { + "login": "billvenhaus", + "id": 6692379, + "type": "User", + "contributions": 1 + }, + { + "login": "BenBtg", + "id": 70525, + "type": "User", + "contributions": 1 + }, + { + "login": "baskren", + "id": 2528888, + "type": "User", + "contributions": 1 + }, + { + "login": "BarryNolte", + "id": 4474173, + "type": "User", + "contributions": 1 + }, + { + "login": "BaY1251", + "id": 48309205, + "type": "User", + "contributions": 1 + }, + { + "login": "axelgorris", + "id": 11756311, + "type": "User", + "contributions": 1 + }, + { + "login": "atsushieno", + "id": 53929, + "type": "User", + "contributions": 1 + }, + { + "login": "artemutin", + "id": 7271331, + "type": "User", + "contributions": 1 + }, + { + "login": "mellson", + "id": 167574, + "type": "User", + "contributions": 1 + }, + { + "login": "AndrewLang", + "id": 3375370, + "type": "User", + "contributions": 1 + }, + { + "login": "AndreKraemer", + "id": 312671, + "type": "User", + "contributions": 1 + }, + { + "name": "Mausam Shrestha", + "email": "46900712+mausam-shrestha@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Mauro Agnoletti", + "email": "mauro.agnoletti@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Mattias Sjögren", + "email": "github@msjogren.net", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Matthijs ter Woord", + "email": "matthijsterwoord@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Matthew Robbins", + "email": "matthew.ch.robbins@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Matt Ward", + "email": "ward.matt@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Matt Ward", + "email": "matt.ward@microsoft.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Matt Soucoup", + "email": "masoucou@microsoft.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Matt Regul", + "email": "mareg@microsoft.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Matt Mitchell", + "email": "mmitche@microsoft.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Matt Goldman", + "email": "matt.goldman@outlook.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Mathias Storm", + "email": "mathias@storm.lc", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Mateus Luiz Camilo", + "email": "37350787+mathewlc@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Martin Kuckert", + "email": "m.kuckert@salt-and-pepper.eu", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Martin", + "email": "modermatt@tuta.io", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Martijn van Dijk", + "email": "mhvdijk@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Mark", + "email": "mrcull@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "login": "Marioo1357", + "id": 45981364, + "type": "User", + "contributions": 1 + }, + { + "login": "MariovanZeist", + "id": 12493059, + "type": "User", + "contributions": 1 + }, + { + "login": "Marcus-L", + "id": 1369184, + "type": "User", + "contributions": 1 + }, + { + "login": "mgierlasinski", + "id": 19707868, + "type": "User", + "contributions": 1 + }, + { + "login": "john-hollander", + "id": 11653688, + "type": "User", + "contributions": 1 + }, + { + "name": "Nicolò Carandini", + "email": "ncarandini@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "NicolD", + "email": "nicolgit@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Nick Kovalsky", + "email": "taublast@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Nick Gamroth", + "email": "thebeekeeper@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Neville Nazerane", + "email": "31866047+neville-nazerane@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Muzib", + "email": "thisismuzib@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Mitchell Hwang", + "email": "16830051+mdh1418@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Mikhail", + "email": "om2804@mail.ru", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Mike Schwörer", + "email": "mailport@mikescher.de", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Mike Parker", + "email": "mjbparker@outlook.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Mike Parker", + "email": "mikeparker104", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Mike Norman", + "email": "mike.norman@xamarin.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Mike Irving", + "email": "79252299+mikeirvingweb@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Mihhail Maslakov", + "email": "mihhail.maslakov@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Michael Yanni", + "email": "miyanni@microsoft.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Michael S. Scherotter", + "email": "mischero@microsoft.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Michael Dwan", + "email": "m@dwan.io", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Michael Cummings (MSFT)", + "email": "mcumming@microsoft.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Michael Cao", + "email": "poppop208@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Michael", + "email": "michael@zpf.fr", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Mendy Berger", + "email": "12537668+mendyberger@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "MemeMan", + "email": "52583316+imememani@users.noreply.github.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "name": "Maximo Piva", + "email": "maximo.piva@gmail.com", + "type": "Anonymous", + "contributions": 1 + }, + { + "login": "johannesegger", + "id": 237707, + "type": "User", + "contributions": 1 + }, + { + "login": "johankson", + "id": 1113636, + "type": "User", + "contributions": 1 + }, + { + "login": "JogyBlack", + "id": 1275686, + "type": "User", + "contributions": 1 + }, + { + "name": "Joakim Carselind", + "email": "joakim.carselind@cub.se", + "type": "Anonymous", + "contributions": 1 + }, + { + "login": "jimbobbennett", + "id": 1710385, + "type": "User", + "contributions": 1 + }, + { + "login": "jrjrguo", + "id": 27794646, + "type": "User", + "contributions": 1 + }, + { + "login": "Powerhelmsman", + "id": 33136632, + "type": "User", + "contributions": 1 + }, + { + "login": "solvingj", + "id": 8557737, + "type": "User", + "contributions": 1 + }, + { + "login": "lirkki", + "id": 665778, + "type": "User", + "contributions": 1 + }, + { + "login": "JanKrivanek", + "id": 3809076, + "type": "User", + "contributions": 1 + }, + { + "login": "JimBobSquarePants", + "id": 385879, + "type": "User", + "contributions": 1 + }, + { + "login": "licon4812", + "id": 32421608, + "type": "User", + "contributions": 1 + }, + { + "login": "jadenrogers", + "id": 8000621, + "type": "User", + "contributions": 1 + }, + { + "login": "lamest", + "id": 7779341, + "type": "User", + "contributions": 1 + }, + { + "login": "RussKie", + "id": 4403806, + "type": "User", + "contributions": 1 + }, + { + "login": "ice-j", + "id": 3597015, + "type": "User", + "contributions": 1 + }, + { + "login": "ChummerUA", + "id": 12427312, + "type": "User", + "contributions": 1 + }, + { + "login": "hemantbeast", + "id": 10476066, + "type": "User", + "contributions": 1 + }, + { + "login": "Happypig375", + "id": 19922066, + "type": "User", + "contributions": 1 + }, + { + "login": "tracplus-hpaterson", + "id": 87885287, + "type": "User", + "contributions": 1 + }, + { + "login": "gatm50", + "id": 440179, + "type": "User", + "contributions": 1 + }, + { + "login": "GuidoNeele", + "id": 1301586, + "type": "User", + "contributions": 1 + }, + { + "login": "MarcelStommel", + "id": 45386201, + "type": "User", + "contributions": 1 + }, + { + "login": "FaithfulDev", + "id": 16925901, + "type": "User", + "contributions": 1 + }, + { + "login": "manishkungwani", + "id": 673367, + "type": "User", + "contributions": 1 + }, + { + "login": "mairaw", + "id": 12971179, + "type": "User", + "contributions": 1 + }, + { + "login": "MagicAndre1981", + "id": 8274816, + "type": "User", + "contributions": 1 + }, + { + "login": "guardrex", + "id": 1622880, + "type": "User", + "contributions": 1 + }, + { + "login": "lizharems", + "id": 103444841, + "type": "User", + "contributions": 1 + }, + { + "login": "leoMehlig", + "id": 9119485, + "type": "User", + "contributions": 1 + }, + { + "login": "rs-lkroneman", + "id": 66680815, + "type": "User", + "contributions": 1 + }, + { + "login": "lobrien", + "id": 181571, + "type": "User", + "contributions": 1 + }, + { + "login": "lewing", + "id": 24063, + "type": "User", + "contributions": 1 + }, + { + "login": "KyNam", + "id": 1797185, + "type": "User", + "contributions": 1 + }, + { + "login": "pineapple216", + "id": 7579094, + "type": "User", + "contributions": 1 + }, + { + "login": "koviant", + "id": 23036313, + "type": "User", + "contributions": 1 + }, + { + "login": "thekbb", + "id": 8903473, + "type": "User", + "contributions": 1 + }, + { + "login": "kentcb", + "id": 1901832, + "type": "User", + "contributions": 1 + }, + { + "login": "khuongntrd", + "id": 8498480, + "type": "User", + "contributions": 1 + }, + { + "login": "dahlbyk", + "id": 133987, + "type": "User", + "contributions": 1 + }, + { + "login": "Kahbazi", + "id": 19396090, + "type": "User", + "contributions": 1 + }, + { + "login": "garuma", + "id": 104105, + "type": "User", + "contributions": 1 + }, + { + "login": "tondat", + "id": 383380, + "type": "User", + "contributions": 1 + }, + { + "login": "JFMG", + "id": 100067782, + "type": "User", + "contributions": 1 + }, + { + "login": "Jon2G", + "id": 24820069, + "type": "User", + "contributions": 1 + } +] diff --git a/.github/prompts/release_notes.prompt.md b/.github/prompts/release_notes.prompt.md new file mode 100644 index 000000000000..4210177b4ed1 --- /dev/null +++ b/.github/prompts/release_notes.prompt.md @@ -0,0 +1,419 @@ +# .NET MAUI Release Notes Generator + +You are an Open Source release notes generator assistant responsible for classifying and generating comprehensive release notes between two commits from the repository the user specifies. + +## Understanding Categories + +You will classify all commits into exactly ONE of the following categories: + +1. **MAUI Product Fixes**: Bug fixes, improvements, and features related to the MAUI product itself +2. **Dependency Updates**: Updates to dependencies, packages, libraries, or SDKs +3. **Testing**: Test-related changes, test infrastructure, and test improvements +4. **Docs**: Documentation changes, samples, and tutorials +5. **Housekeeping**: Build system changes, CI pipeline, code cleanup, formatting, and any other changes + +Every commit must be classified into exactly one category. When uncertain about where to place a commit, follow the classification rules below or default to Housekeeping. + +## Process for Creating Release Notes + +When asked to create release notes for a particular branch, follow these steps: + +### 1. Finding the Commits to Compare + +* When user specifies two branches or commits, use these for comparison +* If only one branch/commit is provided, you'll need to determine the previous release point, ask the user to tell you what is the previous release branch you can try something like `git branch -a | grep -E "release/10.0.*preview"` +* If needed, ask the user for the comparison point or the previous branch + +### 2. Retrieving the Commit Log + +* Use `git log` or equivalent to get the commits between the two commits/branches and save it to a file like this exmaple `git log --pretty=format:"%h - %s - #%cd (%an - %ae)" --date=short release/10.0.1xx-preview2..release/10.0.1xx-preview3 > release_notes_commits.txt` +* Ensure you capture all commits within the specified range +* Pay attention to merge commits that might indicate important feature merges + +### 3. Find the correct Github username for each commit + +* For each commit on the list, look up the corresponding GitHub username from the actual GitHub PR, not just the commit author email +* Use the `get_pull_request` tool if available to fetch the actual PR information including the correct GitHub username that created the PR +* Use the [text](contributors.json) file to help map commit authors to GitHub usernames +* When encountering an email address in a commit author, check if it exists in the contributors.json file and use the corresponding GitHub login +* Verify all usernames are consistent with GitHub's format (e.g., @jsuarezruiz instead of @javiersuarezruiz) +* Some common username transformations to check for: + - Internal usernames may differ from GitHub usernames + - Email addresses should be converted to GitHub handles + - Employee IDs or numbers in usernames should be included if they are part of the GitHub username (e.g., @HarishKumarSF4517 not @harish.kumar) +* Keep the '@' prefix for all usernames to maintain consistency +* For "Anonymous" type contributors in [text](contributors.json), use their name as shown but try to find their corresponding GitHub username if possible +* For automated systems like dependabot or github-actions, use the standard bot usernames (@dependabot[bot], @github-actions[bot], etc.) + +### 4. Classifying the Commits + +To help when doing your category analizing use lower case of the commit messages +Apply these classification rules: + +* **MAUI Product Fixes**: + - Bug fixes with platform tags like [iOS], [Android], [Windows], [Mac], [MacCatalyst], [android], [x], [xaml], [core], [ios], [android], [windows], [mac], [maccatalyst] + - Feature additions or improvements to MAUI components + - Performance improvements + - API changes and enhancements + - New features or fixes related to Aspire + - Remove for fixing pending TODOs + - Trimmer and AOT related changes + +* **Testing**: + - Has tag [testing], [test], [uitests] or contains terms like "test", "add test", "UI test", "unit test", "UItests", "uitests", if any of these exists the commit is from Testing category + - Changes to test infrastructure, test frameworks, or CI test configurations + - Test coverage improvements + +* **Docs**: + - Has tag [docs] or contains terms like "documentation", "docs", "sample", "example" + - README updates, API documentation, code comments + - No other commits should belong here + +* **Dependency Updates**: + - Updates to package references, dependencies, or SDKs + - Commits from automation bots updating dependencies (e.g., @dotnet-maestro) + - Version bumps of external libraries + - Changes to NuGet packages + +* **Housekeeping**: + - CI pipeline changes, formatting fixes, repo maintenance + - Build system modifications, tooling updates + - Refactoring with no functional changes + - Any commit that doesn't clearly fit other categories + - Merging a branch to another branch + - Has tag [ci] + + +### 5. Organizing for the Response + +* Group commits by category as defined in section 1 +* Within each category, list in descending order by PR number (newest PRs first) +* For PR numbers: + - Ensure they are formatted as '#XXXXX' (e.g., #28804) + - When creating GitHub links, use full URLs: https://github.com/dotnet/maui/pull/XXXXX +* For contributor attribution: + - Use ONLY the GitHub username that appears in the PR, not the commit author + - Always prefix usernames with '@' (e.g., @kubaflo) + - Be especially careful with usernames that have employee IDs or numbers at the end + - For automated actions, use @github-actions or @dotnet-bot as appropriate +* Save the results to a markdown file like docs/release_notes_{releasename}.md + +### 6. Special Cases & Edge Cases + +* **Reverts**: Classify reverted commits to the same category as the original commit +* **Automated PRs**: Place automation-driven changes (like dependency updates) in appropriate categories like Dependency Updates +* **Cross-cutting changes**: When a commit spans multiple categories, prioritize based on the primary focus +* **Breaking changes**: Highlight any breaking changes prominently in the summary +* **New contributors**: Include a separate section acknowledging first-time contributors + +## Response Format + +Structure your release notes in the following categorized format, and save them to a file like docs/release_notes_{releasename}.md: + +```markdown +### MAUI Product Fixes +* [Commit title] by @[correct-github-username] in https://github.com/dotnet/maui/pull/[PR number] +* ... + +### Testing +* [Commit title] by @[correct-github-username] in https://github.com/dotnet/maui/pull/[PR number] +* ... + +### Dependency Updates +* [Commit title] by @[correct-github-username] in https://github.com/dotnet/maui/pull/[PR number] +* ... + +### Docs +* [Commit title] by @[correct-github-username] in https://github.com/dotnet/maui/pull/[PR number] +* ... + +### Housekeeping +* [Commit title] by @[correct-github-username] in https://github.com/dotnet/maui/pull/[PR number] +* ... + +## New Contributors +* @[correct-github-username] made their first contribution in https://github.com/dotnet/maui/pull/[PR number] +* ... + +**Full Changelog**: https://github.com/dotnet/maui/compare/[previous-branch]...[current-branch] +``` + +## Contributors list + +[text](contributors.json) + + +## Example + +Here's a shortened example of properly formatted release notes: + +## What's Changed + +* Internalize/remove MessagingCenter by @jfversluis in https://github.com/dotnet/maui/pull/27842 +* [release/10.0.1xx-preview2] Obsolete TableView by @github-actions in https://github.com/dotnet/maui/pull/28327 + +### MAUI Product Fixes +* Radio button's default template improvements by @kubaflo in https://github.com/dotnet/maui/pull/26719 +* [Windows] - Fixed Window Title Not Shown When Reverting from TitleBar to Default State by @prakashKannanSf3972 in https://github.com/dotnet/maui/pull/27148 +* [Windows] Fixed Margin Not Applied to Shell Flyout Template Items on First Display by @prakashKannanSf3972 in https://github.com/dotnet/maui/pull/27060 +* [iOS] Fix for Left SwipeView Items Conflict with Shell Menu Swipe Gesture by @Tamilarasan-Paranthaman in https://github.com/dotnet/maui/pull/26976 +* [iOS]Fix for Character Spacing Not Updating Correctly in Editor for Dynamically Added Text by @devanathan-vaithiyanathan in https://github.com/dotnet/maui/pull/25347 +* Make ImageSource more async-friendly by @symbiogenesis in https://github.com/dotnet/maui/pull/22098 +* [XC] don't call ProvideValue on compiled bindings by @StephaneDelcroix in https://github.com/dotnet/maui/pull/27509 +* [XC] trim x:Name values by @StephaneDelcroix in https://github.com/dotnet/maui/pull/27452 +* [Mac] TitleBar not always initally set by @tj-devel709 in https://github.com/dotnet/maui/pull/27487 +* [X] don't expand types to Extension for x:Static by @StephaneDelcroix in https://github.com/dotnet/maui/pull/17276 +* Fix Android TextView being truncated under some conditions by @albyrock87 in https://github.com/dotnet/maui/pull/27179 +* Improve debugger display XP by @pictos in https://github.com/dotnet/maui/pull/27489 +* [Windows]Fixed Shell Navigating event issue when switching tabs by @Vignesh-SF3580 in https://github.com/dotnet/maui/pull/27197 +* Revert "Implementation of Customizable Search Button Color for SearchBar Across Platforms (#26759)" by @jfversluis in https://github.com/dotnet/maui/pull/27568 +* [net10.0] Revert "Implementation of Customizable Search Button Color for SearchBar Across Platforms (#26759)" by @github-actions in https://github.com/dotnet/maui/pull/27578 +* Use TCS for BusySetSignalName tests by @PureWeen in https://github.com/dotnet/maui/pull/27583 +* [Windows] - Resolved FlyoutBehavior "Locked" State Reset Issue After Navigation by @prakashKannanSf3972 in https://github.com/dotnet/maui/pull/27379 +* Fixed the vertical orientation issue in the CarouselViewHandler2 on iOS by @Ahamed-Ali in https://github.com/dotnet/maui/pull/27273 +* [Android] Fixed the CarouselView Items overlap issue with PeekAreaInsets by @Ahamed-Ali in https://github.com/dotnet/maui/pull/27499 +* Fixed CollectionView's HeaderTemplate is not rendering in iOS and MacCatalyst platform. by @KarthikRajaKalaimani in https://github.com/dotnet/maui/pull/27466 +* Obsolete iOS Compatibility AccessibilityExtensions by @jfversluis in https://github.com/dotnet/maui/pull/27593 +* Make HybridWebView.InvokeJavaScriptAsync public by @jfversluis in https://github.com/dotnet/maui/pull/27594 +* Replace Android ToSpannableString overload by @jfversluis in https://github.com/dotnet/maui/pull/27597 +* [net10.0] Set `UseRidGraph=false` on Windows by @MartyIX in https://github.com/dotnet/maui/pull/27595 +* Reapply "Implementation of Customizable Search Button Color for Search Across Platforms (#26759)" by @jfversluis in https://github.com/dotnet/maui/pull/27586 +* [Android] Fix for Flyout closing when updating the FlyoutPage.Detail by @Tamilarasan-Paranthaman in https://github.com/dotnet/maui/pull/26425 +* Fix for [Windows]ToolbarItem visibility until Page Disappearing by @SuthiYuvaraj in https://github.com/dotnet/maui/pull/26915 +* [net10.0] Set `UseRidGraph=false` on Windows (2) by @MartyIX in https://github.com/dotnet/maui/pull/27634 +* Fix for MenuFlyoutItem stops working after navigating away from and back to page by @BagavathiPerumal in https://github.com/dotnet/maui/pull/25170 +* Fix Issue13551 to use WaitForElement by @PureWeen in https://github.com/dotnet/maui/pull/27644 +* [Android] Fix Flickering issue when calling Navigation.PopAsync by @devanathan-vaithiyanathan in https://github.com/dotnet/maui/pull/24887 +* Fix GC Race condition with tests by @PureWeen in https://github.com/dotnet/maui/pull/27652 +* Fix 19647 by @StephaneDelcroix in https://github.com/dotnet/maui/pull/20127 +* [net10.0] Make CV2 default for net10 by @rmarinho in https://github.com/dotnet/maui/pull/27567 +* Timeout Android emulator start by @PureWeen in https://github.com/dotnet/maui/pull/27657 +* [net10] Revert Windows RID graph changes by @jfversluis in https://github.com/dotnet/maui/pull/27671 +* BindableLayout should disconnect handlers by @albyrock87 in https://github.com/dotnet/maui/pull/27450 +* Improve shadow rendering on Android, fix shadow clipping on iOS by @albyrock87 in https://github.com/dotnet/maui/pull/26789 +* [X] deprecate fontImageExtension by @StephaneDelcroix in https://github.com/dotnet/maui/pull/23657 +* 26598 - Fix for Tabbar disappears when navigating back from page with hidden TabBar in iOS 18 by @SuthiYuvaraj in https://github.com/dotnet/maui/pull/27582 +* Avoid compiler error when using init properties with BindingSourceGenerator by @rabuckley in https://github.com/dotnet/maui/pull/27655 +* Make iOS WebView delegates virtual by @jfversluis in https://github.com/dotnet/maui/pull/27601 +* Improve TextToSpeech function by adding a speech rate parameter by @Zerod159 in https://github.com/dotnet/maui/pull/24798 +* Adds very basic CSS support for Border by @sthewissen in https://github.com/dotnet/maui/pull/27529 +* [iOS] Added PermissionStatus.Limited for Contacts by @kubaflo in https://github.com/dotnet/maui/pull/27694 +* Make some internal methods public by @jfversluis in https://github.com/dotnet/maui/pull/27598 +* Add support for iOS/Mac specific modals styled as popovers by @piersdeseilligny in https://github.com/dotnet/maui/pull/23984 +* Adds CSS support for shadows and a simpler way of defining shadows in XAML by @sthewissen in https://github.com/dotnet/maui/pull/27180 +* Fix the Collection view empty view not fill the vertical space by @Shalini-Ashokan in https://github.com/dotnet/maui/pull/27464 +* [Windows] Fix for SearchHandler.Focused and Unfocused event never fires by @BagavathiPerumal in https://github.com/dotnet/maui/pull/27577 +* [Android] Fix Cursor Not Closing in File Picker to Prevent Log Spam. by @bhavanesh2001 in https://github.com/dotnet/maui/pull/27718 +* [Android] Fixed the SoftInputMode issues with modal pages by @Ahamed-Ali in https://github.com/dotnet/maui/pull/27553 +* [iOS] Fix Gray Line Appears on the Right Side of GraphicsView with Decimal WidthRequest by @devanathan-vaithiyanathan in https://github.com/dotnet/maui/pull/26368 +* Page cannot scroll to the bottom while using RoundRectangle by @Dhivya-SF4094 in https://github.com/dotnet/maui/pull/27451 +* Support for Setting Switch Off State Color by @devanathan-vaithiyanathan in https://github.com/dotnet/maui/pull/25068 +* [iOS] Fix ShellContent Title Does Not Update at Runtime by @devanathan-vaithiyanathan in https://github.com/dotnet/maui/pull/26062 +* Fixed [iOS] Navigation breaks when modal pages use PageSheet by @NanthiniMahalingam in https://github.com/dotnet/maui/pull/27765 +* BarBackground with Brush in TabbedPage on theme change by @kubaflo in https://github.com/dotnet/maui/pull/24425 +* [iOS] Using long-press navigation on back button with shell pages - fix by @kubaflo in https://github.com/dotnet/maui/pull/24003 +* Fix for DatePicker displays incorrect date selection when navigating to next month. by @BagavathiPerumal in https://github.com/dotnet/maui/pull/26064 +* Fixed Unnecessary SizeChanged Event Triggering by @Dhivya-SF4094 in https://github.com/dotnet/maui/pull/27476 +* [Essentials] Longitude Validation by @kubaflo in https://github.com/dotnet/maui/pull/27784 +* Fixed latitude->longitude typo by @kubaflo in https://github.com/dotnet/maui/pull/27834 +* [iOS] CollectionView with header or footer has incorrect height - fix by @kubaflo in https://github.com/dotnet/maui/pull/27809 +* Fix concurrency issues and leak reliability by @PureWeen in https://github.com/dotnet/maui/pull/27815 +* [iOS] Fixed the Application crash when ToolbarItem is created with invalid IconImageSource name by @Ahamed-Ali in https://github.com/dotnet/maui/pull/27175 +* Revert "Fix concurrency issues and leak reliability" by @rmarinho in https://github.com/dotnet/maui/pull/27870 +* [Android] Fix app crash caused by dynamic template switching in ListView by @BagavathiPerumal in https://github.com/dotnet/maui/pull/24808 +* Don't need to register ApplicationStub by @PureWeen in https://github.com/dotnet/maui/pull/27885 +* Fixed Toolbar IconImageSource not updating with Binding Changes by @NirmalKumarYuvaraj in https://github.com/dotnet/maui/pull/27402 +* [iOS] Fixed a crash in CarouselViewHandler2 on iOS 15. by @Ahamed-Ali in https://github.com/dotnet/maui/pull/27871 +* [Android] Android: Native View not set exception on modal page - fix by @kubaflo in https://github.com/dotnet/maui/pull/27891 +* [iOS/MacCatalyst] Use newer API in FilePicker by @MartyIX in https://github.com/dotnet/maui/pull/27521 +* [Android] Map FlowDirection of shell to PlatformView on Android by @mohsenbgi in https://github.com/dotnet/maui/pull/23473 +* Fix CSS Hot Reload - Handle fingerprint when hot reloading scoped CSS bundles by @spadapet in https://github.com/dotnet/maui/pull/27788 +* [iOS] CV1's footer doesn't increase its size - fix by @kubaflo in https://github.com/dotnet/maui/pull/27979 +* [iOS] CollectionView 1's doesn't adjust its offset when resizing a footer by @kubaflo in https://github.com/dotnet/maui/pull/27963 +* [Android] Properly Resolve File Paths in FilePicker When MANAGE_EXTERNAL_STORAGE is Granted by @bhavanesh2001 in https://github.com/dotnet/maui/pull/27975 +* [net10.0] Set `UseRidGraph=false` on Windows (attempt 2) by @MartyIX in https://github.com/dotnet/maui/pull/27679 +* [Android] Fix crash starting the swipe on SwipeView inside CollectionView by @jsuarezruiz in https://github.com/dotnet/maui/pull/27669 +* Applying visibility change to child controls by @kubaflo in https://github.com/dotnet/maui/pull/20154 +* Fixed CheckBox enabled color is not updated properly by @NanthiniMahalingam in https://github.com/dotnet/maui/pull/26399 +* [android] move `IsDispatchRequiredImplementation()` to Java by @jonathanpeppers in https://github.com/dotnet/maui/pull/27936 +* remove Dispose call on ShellItemRenderer by @pictos in https://github.com/dotnet/maui/pull/27890 +* [iOS] CollectionView with grouped data crashes on iOS when the groups change - fix by @kubaflo in https://github.com/dotnet/maui/pull/27991 +* [BindingSG] Added Binding.Create support for xaml generated sources by @jkurdek in https://github.com/dotnet/maui/pull/27610 +* Make ShadowTypeConverter public & nullable for .NET 10 by @jfversluis in https://github.com/dotnet/maui/pull/27984 +* add DebuggerTypeProxy for Shell by @pictos in https://github.com/dotnet/maui/pull/27989 +* [Windows] Fixed NRE when clearing ListView after navigating back by @SubhikshaSf4851 in https://github.com/dotnet/maui/pull/27274 +* [Windows] Fix for issues caused by setting Shell.FlyoutWidth on WinUI when binding context values are changed by @Tamilarasan-Paranthaman in https://github.com/dotnet/maui/pull/27151 +* [MacCatalyst] Picker focus events by @kubaflo in https://github.com/dotnet/maui/pull/27973 +* [Android] Fixed the ScrollbarVisibility issues by @Ahamed-Ali in https://github.com/dotnet/maui/pull/27613 +* Make more internal methods public by @jsuarezruiz in https://github.com/dotnet/maui/pull/28059 +* Fixed FontImageSource icon color does not change in the TabbedPage when dynamically updated. by @NirmalKumarYuvaraj in https://github.com/dotnet/maui/pull/27742 +* [ci] Remove macios workaround to build net9 by @rmarinho in https://github.com/dotnet/maui/pull/28363 + + +### Tests + +* [Testing] Fix for MacCatalyst flaky tests in CI which fails due window position below the dock layer by @anandhan-rajagopal in https://github.com/dotnet/maui/pull/27279 +* Revert "Run every category separately" by @rmarinho in https://github.com/dotnet/maui/pull/27469 +* [Testing] UITest to measure layout passes on a common scenario by @albyrock87 in https://github.com/dotnet/maui/pull/25671 +* [Testing] Enabling some UITests from Issues folder in Appium-13 by @HarishKumarSF4517 in https://github.com/dotnet/maui/pull/27257 +* [Testing] Fix flaky UITests failing sometimes 3 by @jsuarezruiz in https://github.com/dotnet/maui/pull/27277 +* [testing] Disable BlazorWebview tests by @rmarinho in https://github.com/dotnet/maui/pull/27557 +* Fix UITest screenshot taking on MacCatalyst by @albyrock87 in https://github.com/dotnet/maui/pull/27531 +* [Testing] Fix flaky test 4 by @jsuarezruiz in https://github.com/dotnet/maui/pull/27607 +* [testing] Update tests demands by @rmarinho in https://github.com/dotnet/maui/pull/27560 +* [Testing] Implement Appium swipe action on Catalyst using the Mac Driver by @jsuarezruiz in https://github.com/dotnet/maui/pull/27441 +* [Testing] Implement PressEnter Appium action on Windows by @jsuarezruiz in https://github.com/dotnet/maui/pull/27602 +* [Testing] Implement ContextMenu UITest extension methods by @jsuarezruiz in https://github.com/dotnet/maui/pull/26204 +* [Testing] Enabling more UI Tests by removing platform specific condition - 6 by @LogishaSelvarajSF4525 in https://github.com/dotnet/maui/pull/27581 +* [tests] Run tests on x64 only for devices controls by @rmarinho in https://github.com/dotnet/maui/pull/27714 +* [Testing, CI] Increased threshold value to make Resizetizer unit tests pass on arm64 machines by @anandhan-rajagopal in https://github.com/dotnet/maui/pull/27684 +* [Testing] Enabling more UI Tests by removing platform specific condition - 7 by @HarishKumarSF4517 in https://github.com/dotnet/maui/pull/27639 +* [Testing] Implement TapCoordinates Appium action on macOS by @jsuarezruiz in https://github.com/dotnet/maui/pull/27603 +* [Testing] Enabling more UI Tests by removing platform specific condition - 8 by @nivetha-nagalingam in https://github.com/dotnet/maui/pull/27681 +* [Testing] Enabling more UI Tests by removing platform specific condition - 3 by @LogishaSelvarajSF4525 in https://github.com/dotnet/maui/pull/27501 +* [Testing] Fix DragCoordinates Appium action on Mac by @jsuarezruiz in https://github.com/dotnet/maui/pull/27339 +* [Testing] Enabling WebView UITests from Issues folder in Appium by @NafeelaNazhir in https://github.com/dotnet/maui/pull/27284 +* [Testing] Fix flaky test 5 by @jsuarezruiz in https://github.com/dotnet/maui/pull/27733 +* [Testing] Enabling more UI Tests by removing platform specific condition - 1 by @HarishKumarSF4517 in https://github.com/dotnet/maui/pull/27454 +* Add missing screen shot for Issue25502 on MAC by @PureWeen in https://github.com/dotnet/maui/pull/27813 +* [Testing] Enabling ContextMenu UITests from Xamarin.UITests to Appium by @NafeelaNazhir in https://github.com/dotnet/maui/pull/27403 +* Mark VerifyInitialEntryReturnTypeChange and VerifyGraphicsViewWithoutGrayLine tests as flaky by @jfversluis in https://github.com/dotnet/maui/pull/27776 +* [Testing] Fix for flaky UITests in CI that occasionally fail - 2 by @nivetha-nagalingam in https://github.com/dotnet/maui/pull/27878 +* [Testing] Enabling more UI Tests by removing platform specific condition - 5 by @LogishaSelvarajSF4525 in https://github.com/dotnet/maui/pull/27564 +* Update Appium Versions by @PureWeen in https://github.com/dotnet/maui/pull/27933 +* Revert "Update Appium Versions" by @PureWeen in https://github.com/dotnet/maui/pull/27938 +* [Android] Testcase for Shell FlowDirection issue by @Vignesh-SF3580 in https://github.com/dotnet/maui/pull/27931 +* [Testing] Run tests verifying snapshots on mac now that's possible by @jsuarezruiz in https://github.com/dotnet/maui/pull/27893 +* [Testing] More changes in capabilities to adjust Appium timeouts by @jsuarezruiz in https://github.com/dotnet/maui/pull/27675 +* [Testing] Migration of Compatibility.Core platform-specific unit tests into device tests - 1 by @anandhan-rajagopal in https://github.com/dotnet/maui/pull/27695 +* [Testing] Fix flaky tests 6 by @jsuarezruiz in https://github.com/dotnet/maui/pull/27874 +* [Testing] Enabling more UI Tests by removing platform specific condition - 12 by @LogishaSelvarajSF4525 in https://github.com/dotnet/maui/pull/27804 +* [Testing] Enabling more UI Tests by removing platform specific condition - 13 by @HarishKumarSF4517 in https://github.com/dotnet/maui/pull/27904 +* [Testing] Enabling more UI Tests by removing platform specific condition - 4 by @HarishKumarSF4517 in https://github.com/dotnet/maui/pull/27561 +* [Testing] Enable the Issue417 test on iOS and Catalyst by @kubaflo in https://github.com/dotnet/maui/pull/27987 +* [Testing] Enabling more UI Tests by removing platform specific condition - 2 by @LogishaSelvarajSF4525 in https://github.com/dotnet/maui/pull/27500 +* [Testing] Enabling more UI Tests by removing platform specific condition - 14 by @LogishaSelvarajSF4525 in https://github.com/dotnet/maui/pull/27906 +* Fix Android device tests on .NET 10 by @jfversluis in https://github.com/dotnet/maui/pull/28009 +* [Testing] Enabling ContextMenu UITests from Xamarin.UITests to Appium - 2 by @nivetha-nagalingam in https://github.com/dotnet/maui/pull/27405 +* [Testing] Enabling more UI Tests by removing platform specific condition - 9 by @HarishKumarSF4517 in https://github.com/dotnet/maui/pull/27743 +* [Testing] Enabling more UI Tests by removing platform specific condition - 10 by @nivetha-nagalingam in https://github.com/dotnet/maui/pull/27751 +* [Testing] Fix for flaky UITests in CI that occasionally fail - 3 by @NafeelaNazhir in https://github.com/dotnet/maui/pull/27905 +* [Testing] Fix for flaky UITests in CI that occasionally fail. by @nivetha-nagalingam in https://github.com/dotnet/maui/pull/27453 +* [Testing] Enabling more UI Tests by removing platform specific condition - 11 by @LogishaSelvarajSF4525 in https://github.com/dotnet/maui/pull/27764 +* [Testing] Feature Matrix UITest Cases for Slider Control by @NafeelaNazhir in https://github.com/dotnet/maui/pull/27433 +* [Testing] Fix flaky UITests 7 by @jsuarezruiz in https://github.com/dotnet/maui/pull/28000 +* [Testing] Implement the option to change system theme on Appium by @jsuarezruiz in https://github.com/dotnet/maui/pull/28025 +* [Testing] Resolved Shell TabBar DeviceTests CI failures on macOS by @anandhan-rajagopal in https://github.com/dotnet/maui/pull/28072 +* [release/10.0.1xx-preview2] [net10.0] Move iOS 18.0 simulators by @github-actions in https://github.com/dotnet/maui/pull/28277 +* [release/10.0.1xx-preview2] [ci] Fix platform for UItests for iOS by @github-actions in https://github.com/dotnet/maui/pull/28345 + + +### Dependency Updates + +* [net10.0] Update dependencies from dotnet/android by @dotnet-maestro in https://github.com/dotnet/maui/pull/27510 +* [net10.0] Update dependencies from dotnet/android by @dotnet-maestro in https://github.com/dotnet/maui/pull/27540 +* [net10.0] Update dependencies from dotnet/android by @dotnet-maestro in https://github.com/dotnet/maui/pull/27570 +* [net10.0] Update dependencies from dotnet/android by @dotnet-maestro in https://github.com/dotnet/maui/pull/27587 +* [net10.0] Update dependencies from dotnet/android by @dotnet-maestro in https://github.com/dotnet/maui/pull/27615 +* [net10.0] Update dependencies from dotnet/android by @dotnet-maestro in https://github.com/dotnet/maui/pull/27643 +* [main] Update dependencies from dotnet/xharness by @dotnet-maestro in https://github.com/dotnet/maui/pull/27662 +* [net10.0] Update dependencies from dotnet/android by @dotnet-maestro in https://github.com/dotnet/maui/pull/27687 +* [net10.0] Update dependencies from dotnet/android by @dotnet-maestro in https://github.com/dotnet/maui/pull/27719 +* [net10.0] Update dependencies from dotnet/android by @dotnet-maestro in https://github.com/dotnet/maui/pull/27725 +* [Windows] Upgrade Windows App SDK from 1.6.4 to 1.6.5 by @MartyIX in https://github.com/dotnet/maui/pull/27729 +* [net10.0] Update dependencies from dotnet/android by @dotnet-maestro in https://github.com/dotnet/maui/pull/27758 +* [net10.0] Update dependencies from dotnet/android by @dotnet-maestro in https://github.com/dotnet/maui/pull/27791 +* [net10.0] Update dependencies from dotnet/android by @dotnet-maestro in https://github.com/dotnet/maui/pull/27810 +* [main] Update dependencies from dotnet/xharness by @dotnet-maestro in https://github.com/dotnet/maui/pull/27835 +* [net10.0] Update dependencies from dotnet/android by @dotnet-maestro in https://github.com/dotnet/maui/pull/27887 +* [net10.0] Update dependencies from dotnet/android by @dotnet-maestro in https://github.com/dotnet/maui/pull/27902 +* [net10.0] Update dependencies from dotnet/android by @dotnet-maestro in https://github.com/dotnet/maui/pull/27937 +* [net10.0] Update dependencies from dotnet/android by @dotnet-maestro in https://github.com/dotnet/maui/pull/27960 +* [net10.0] Update aspnet as sdk, enable Blazor tests by @rmarinho in https://github.com/dotnet/maui/pull/27796 +* [net10.0] Update dependencies from dotnet/android by @dotnet-maestro in https://github.com/dotnet/maui/pull/28019 +* [release/10.0.1xx-preview2] Update with final preview2 versions by @rmarinho in https://github.com/dotnet/maui/pull/28231 +* [release/10.0.1xx-preview2] Update preview2 ios android sdk by @rmarinho in https://github.com/dotnet/maui/pull/28287 +* [release/10.0.1xx-preview2] Update sdk and runtime by @rmarinho in https://github.com/dotnet/maui/pull/28307 +* [release/10.0.1xx-preview2] Update dependencies from dotnet/sdk by @dotnet-maestro in https://github.com/dotnet/maui/pull/28329 +* [release/10.0.1xx-preview2] Update dependencies from dotnet/sdk by @dotnet-maestro in https://github.com/dotnet/maui/pull/28390 + + +### Housekeeping + +* [ci] Remove references to sdk-insertions by @pjcollins in https://github.com/dotnet/maui/pull/27480 +* [ci] Fix yaml by @rmarinho in https://github.com/dotnet/maui/pull/27497 +* Fix color checking from blocking and add logging by @PureWeen in https://github.com/dotnet/maui/pull/27400 +* [Localization] Simply Logic for Localization Handoff & Handback by @tj-devel709 in https://github.com/dotnet/maui/pull/27508 +* [ci] Run device tests in any machine by @rmarinho in https://github.com/dotnet/maui/pull/27518 +* [housekeeping] Automated PR to fix formatting errors by @github-actions in https://github.com/dotnet/maui/pull/27504 +* [net10.0] Update net10.0 with main by @rmarinho in https://github.com/dotnet/maui/pull/27539 +* [housekeeping] Automated PR to fix formatting errors by @github-actions in https://github.com/dotnet/maui/pull/27547 +* Removes setting up the JDK in pipelines by @jfversluis in https://github.com/dotnet/maui/pull/27396 +* [Localization] Fix blocking typo by @tj-devel709 in https://github.com/dotnet/maui/pull/27566 +* Localized file check-in by OneLocBuild Task: Build definition ID 13330: Build ID 10953111 by @dotnet-bot in https://github.com/dotnet/maui/pull/27569 +* [housekeeping] Automated PR to fix formatting errors by @github-actions in https://github.com/dotnet/maui/pull/27571 +* [housekeeping] Automated PR to fix formatting errors by @github-actions in https://github.com/dotnet/maui/pull/27621 +* [ci] Update variables for signing and not used by @rmarinho in https://github.com/dotnet/maui/pull/27640 +* [housekeeping] Automated PR to fix formatting errors by @github-actions in https://github.com/dotnet/maui/pull/27645 +* Update android.cake cmdline paths by @PureWeen in https://github.com/dotnet/maui/pull/27686 +* Update Versions.props to .NET 9 SR5 Branding by @PureWeen in https://github.com/dotnet/maui/pull/27691 +* Update comments by @APoukar in https://github.com/dotnet/maui/pull/27658 +* [housekeeping] Automated PR to fix formatting errors by @github-actions in https://github.com/dotnet/maui/pull/27693 +* Update bug-report.yml with 9.0.40 by @PureWeen in https://github.com/dotnet/maui/pull/27723 +* [net10.0] Merge main to net10.0 by @rmarinho in https://github.com/dotnet/maui/pull/27720 +* [housekeeping] Automated PR to fix formatting errors by @github-actions in https://github.com/dotnet/maui/pull/27726 +* Move Microsoft.Maui.Packages.slnf to eng folder by @jfversluis in https://github.com/dotnet/maui/pull/27032 +* Move Microsoft.Maui.Samples.slnf to eng folder by @jfversluis in https://github.com/dotnet/maui/pull/27033 +* Make auto applied labels more relevant for Syncfusion partner team by @jfversluis in https://github.com/dotnet/maui/pull/27295 +* Move Microsoft.Maui.Graphics.slnf to subfolder (clean up repo root) by @jfversluis in https://github.com/dotnet/maui/pull/27035 +* [ci] Builds should only take 2h max by @rmarinho in https://github.com/dotnet/maui/pull/27747 +* Add ISO information to Locale API documentation by @jfversluis in https://github.com/dotnet/maui/pull/27746 +* Delete maui.code-workspace (clean up repo root by @jfversluis in https://github.com/dotnet/maui/pull/27767 +* [housekeeping] Automated PR to fix formatting errors by @github-actions in https://github.com/dotnet/maui/pull/27757 +* [Localization] Add Localization tests and other fixes by @tj-devel709 in https://github.com/dotnet/maui/pull/25620 +* [ci] Update sdk, aspnet and runtime by @rmarinho in https://github.com/dotnet/maui/pull/27790 +* [housekeeping] Automated PR to fix formatting errors by @github-actions in https://github.com/dotnet/maui/pull/27816 +* [ci] Fix dnceng builds by @rmarinho in https://github.com/dotnet/maui/pull/27855 +* [housekeeping] Automated PR to fix formatting errors by @github-actions in https://github.com/dotnet/maui/pull/27863 +* [ci] Update slnf location and arcade by @rmarinho in https://github.com/dotnet/maui/pull/27860 +* Localized file check-in by OneLocBuild Task: Build definition ID 13330: Build ID 11029468 by @dotnet-bot in https://github.com/dotnet/maui/pull/27789 +* [ci] Move to Sequoia machines by @rmarinho in https://github.com/dotnet/maui/pull/27787 +* Update DEVELOPMENT.md with net10.0 by @PureWeen in https://github.com/dotnet/maui/pull/27913 +* [housekeeping] Automated PR to fix formatting errors by @github-actions in https://github.com/dotnet/maui/pull/27918 +* [housekeeping] Automated PR to fix formatting errors by @github-actions in https://github.com/dotnet/maui/pull/27942 +* [ci] Remove conditions for devdiv by @rmarinho in https://github.com/dotnet/maui/pull/27958 +* [net10.0] Merge main to net10 by @rmarinho in https://github.com/dotnet/maui/pull/27967 +* [ci] Move more runs to Sequoia by @rmarinho in https://github.com/dotnet/maui/pull/27972 +* LEGO: Pull request from lego/hb_7241b85a-f216-4d55-a9fa-d8030c736df5_20250219211456120 to main by @csigs in https://github.com/dotnet/maui/pull/27915 +* [housekeeping] Automated PR to fix formatting errors by @github-actions in https://github.com/dotnet/maui/pull/27986 +* Localized file check-in by OneLocBuild Task: Build definition ID 13330: Build ID 11064473 by @dotnet-bot in https://github.com/dotnet/maui/pull/27982 +* Enable generation of API docs in CI for .NET 10 by @jfversluis in https://github.com/dotnet/maui/pull/28004 +* [housekeeping] Automated PR to fix formatting errors by @github-actions in https://github.com/dotnet/maui/pull/28021 +* [ci] Publish workload VS insertion zips by @pjcollins in https://github.com/dotnet/maui/pull/28016 +* Update DEVELOPMENT.md to clarify .NET SDK version needed by @jfversluis in https://github.com/dotnet/maui/pull/28031 +* [ci] Remove usage on cake script by @rmarinho in https://github.com/dotnet/maui/pull/28037 +* [ci] Update autoformat prs version by @rmarinho in https://github.com/dotnet/maui/pull/28042 +* [ci] Last move sequoia by @rmarinho in https://github.com/dotnet/maui/pull/28029 +* [housekeeping] Automated PR to fix formatting errors by @github-actions in https://github.com/dotnet/maui/pull/28045 +* [ci] Run provisionator devdiv by @rmarinho in https://github.com/dotnet/maui/pull/28056 +* Revert "[ci] Run provisionator devdiv" by @rmarinho in https://github.com/dotnet/maui/pull/28079 +* [housekeeping] Automated PR to fix formatting errors by @github-actions in https://github.com/dotnet/maui/pull/28068 +* [code style] Prefer file-scope namespaces by @MartyIX in https://github.com/dotnet/maui/pull/28040 +* [net10.0] Merge main to net10.0 by @rmarinho in https://github.com/dotnet/maui/pull/28044 +* [iOS] Ignore for now obsoletes on iOS by @rmarinho in https://github.com/dotnet/maui/pull/28136 + + +## New Contributors +* @Ahamed-Ali made their first contribution in https://github.com/dotnet/maui/pull/27273 +* @KarthikRajaKalaimani made their first contribution in https://github.com/dotnet/maui/pull/27466 +* @rabuckley made their first contribution in https://github.com/dotnet/maui/pull/27655 +* @Zerod159 made their first contribution in https://github.com/dotnet/maui/pull/24798 +* @sthewissen made their first contribution in https://github.com/dotnet/maui/pull/27529 +* @APoukar made their first contribution in https://github.com/dotnet/maui/pull/27658 +* @piersdeseilligny made their first contribution in https://github.com/dotnet/maui/pull/23984 +* @Shalini-Ashokan made their first contribution in https://github.com/dotnet/maui/pull/27464 +* @bhavanesh2001 made their first contribution in https://github.com/dotnet/maui/pull/27718 +* @Dhivya-SF4094 made their first contribution in https://github.com/dotnet/maui/pull/27451 +* @mohsenbgi made their first contribution in https://github.com/dotnet/maui/pull/23473 + +**Full Changelog**: https://github.com/dotnet/maui/compare/{branch}..{previous branch} \ No newline at end of file diff --git a/.vscode/mcp.json b/.vscode/mcp.json new file mode 100644 index 000000000000..0273b732a393 --- /dev/null +++ b/.vscode/mcp.json @@ -0,0 +1,26 @@ +{ + "inputs": [ + { + "type": "promptString", + "id": "github-key", + "password": true, // Encrypted at-rest + "description": "GitHub PAT" + } + ], + "servers": { + "github": { + "command": "docker", + "args": [ + "run", + "-i", + "--rm", + "-e", + "GITHUB_PERSONAL_ACCESS_TOKEN", + "ghcr.io/github/github-mcp-server" + ], + "env": { + "GITHUB_PERSONAL_ACCESS_TOKEN": "${input:github-key}" + } + } + } +} \ No newline at end of file diff --git a/maui.code-workspace b/maui.code-workspace new file mode 100644 index 000000000000..ccd94e18a897 --- /dev/null +++ b/maui.code-workspace @@ -0,0 +1,10 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "dotnet.defaultSolution": "Microsoft.Maui-vscode.sln" + } +} \ No newline at end of file From 064b9136b981d8a870abb5b85a2ae9b461673f0c Mon Sep 17 00:00:00 2001 From: Rui Marinho Date: Sun, 13 Apr 2025 00:37:20 +0100 Subject: [PATCH 07/34] [ci] Produce nightly for inflight/current (#28940) --- eng/pipelines/maui-release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/eng/pipelines/maui-release.yml b/eng/pipelines/maui-release.yml index c011b4a69746..30b3cfa7c774 100644 --- a/eng/pipelines/maui-release.yml +++ b/eng/pipelines/maui-release.yml @@ -27,6 +27,7 @@ schedules: branches: include: - main + - inflight/current variables: - template: /eng/pipelines/common/variables.yml@self From 4178da7f08871bd90b312abb1080dd3bf09285cd Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 12:12:08 +0100 Subject: [PATCH 08/34] Update dependencies from https://github.com/dotnet/xharness build 20250409.2 (#28963) Microsoft.DotNet.XHarness.CLI , Microsoft.DotNet.XHarness.TestRunners.Common , Microsoft.DotNet.XHarness.TestRunners.Xunit From Version 9.0.0-prerelease.25207.3 -> To Version 9.0.0-prerelease.25209.2 Co-authored-by: dotnet-maestro[bot] --- .config/dotnet-tools.json | 2 +- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 60580813dcc0..78c54a9116bd 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -24,7 +24,7 @@ "rollForward": false }, "microsoft.dotnet.xharness.cli": { - "version": "9.0.0-prerelease.25207.3", + "version": "9.0.0-prerelease.25209.2", "commands": [ "xharness" ], diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index d19a59bf2087..6cf2a8a59c8b 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,16 +1,16 @@ - + https://github.com/dotnet/xharness - aed708d126f0776c81966db1ca17278edbef8279 + 856ea5c8f3212dc11b6ce369640ea07558706588 - + https://github.com/dotnet/xharness - aed708d126f0776c81966db1ca17278edbef8279 + 856ea5c8f3212dc11b6ce369640ea07558706588 - + https://github.com/dotnet/xharness - aed708d126f0776c81966db1ca17278edbef8279 + 856ea5c8f3212dc11b6ce369640ea07558706588 diff --git a/eng/Versions.props b/eng/Versions.props index 770868809206..3d3475618e42 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -125,9 +125,9 @@ <_HarfBuzzSharpVersion>8.3.0.1 <_SkiaSharpNativeAssetsVersion>0.0.0-commit.e57e2a11dac4ccc72bea52939dede49816842005.1728 7.0.120 - 9.0.0-prerelease.25207.3 - 9.0.0-prerelease.25207.3 - 9.0.0-prerelease.25207.3 + 9.0.0-prerelease.25209.2 + 9.0.0-prerelease.25209.2 + 9.0.0-prerelease.25209.2 0.9.2 2.0.0.4 1.3.0 From d6d822315c629aaa513f6cb37d82169fd29735cf Mon Sep 17 00:00:00 2001 From: Alberto Aldegheri Date: Mon, 14 Apr 2025 13:29:12 +0200 Subject: [PATCH 09/34] Stop iOS SetNeedsLayout propagation by looking at VisualElement computed Constraint (#28479) * Stop iOS SetNeedsLayout propagation by looking at VisualElement computed constraints * Do measure when MauiView is acting as root view due to fixed constraints --- .../Handlers/iOS/VisualElementRenderer.cs | 6 +++- .../Handlers/Items/iOS/MauiCollectionView.cs | 3 +- .../Core/Handlers/Items/iOS/TemplatedCell.cs | 5 ++- .../Handlers/Items2/iOS/TemplatedCell2.cs | 5 ++- src/Controls/src/Core/Page/Page.cs | 4 ++- .../src/Core/VisualElement/VisualElement.cs | 4 ++- src/Core/src/Core/IConstrainedView.cs | 6 ++++ src/Core/src/Handlers/Page/PageHandler.iOS.cs | 8 ----- src/Core/src/Platform/iOS/ContentView.cs | 2 -- .../IPlatformMeasureInvalidationController.cs | 2 +- src/Core/src/Platform/iOS/MauiScrollView.cs | 4 ++- src/Core/src/Platform/iOS/MauiView.cs | 31 +++++++++++++++++-- src/Core/src/Platform/iOS/ViewExtensions.cs | 22 +++++++------ src/Core/src/Platform/iOS/WrapperView.cs | 3 +- .../PublicAPI/net-ios/PublicAPI.Unshipped.txt | 1 - .../net-maccatalyst/PublicAPI.Unshipped.txt | 1 - 16 files changed, 74 insertions(+), 33 deletions(-) create mode 100644 src/Core/src/Core/IConstrainedView.cs diff --git a/src/Controls/src/Core/Compatibility/Handlers/iOS/VisualElementRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/iOS/VisualElementRenderer.cs index df68dfc77367..f1188b1bc7ef 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/iOS/VisualElementRenderer.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/iOS/VisualElementRenderer.cs @@ -99,7 +99,11 @@ void IPlatformMeasureInvalidationController.InvalidateAncestorsMeasuresWhenMoved _invalidateParentWhenMovedToWindow = true; } - void IPlatformMeasureInvalidationController.InvalidateMeasure(bool isPropagating) => SetNeedsLayout(); + bool IPlatformMeasureInvalidationController.InvalidateMeasure(bool isPropagating) + { + SetNeedsLayout(); + return true; + } public override void MovedToWindow() { diff --git a/src/Controls/src/Core/Handlers/Items/iOS/MauiCollectionView.cs b/src/Controls/src/Core/Handlers/Items/iOS/MauiCollectionView.cs index 8aa58993ea85..ee8ceb04c568 100644 --- a/src/Controls/src/Core/Handlers/Items/iOS/MauiCollectionView.cs +++ b/src/Controls/src/Core/Handlers/Items/iOS/MauiCollectionView.cs @@ -28,7 +28,7 @@ void IPlatformMeasureInvalidationController.InvalidateAncestorsMeasuresWhenMoved _invalidateParentWhenMovedToWindow = true; } - void IPlatformMeasureInvalidationController.InvalidateMeasure(bool isPropagating) + bool IPlatformMeasureInvalidationController.InvalidateMeasure(bool isPropagating) { if (isPropagating) { @@ -36,6 +36,7 @@ void IPlatformMeasureInvalidationController.InvalidateMeasure(bool isPropagating } SetNeedsLayout(); + return !isPropagating; } [UnconditionalSuppressMessage("Memory", "MEM0002", Justification = IUIViewLifeCycleEvents.UnconditionalSuppressMessage)] diff --git a/src/Controls/src/Core/Handlers/Items/iOS/TemplatedCell.cs b/src/Controls/src/Core/Handlers/Items/iOS/TemplatedCell.cs index d3c238ec10e4..b0a15d4f3562 100644 --- a/src/Controls/src/Core/Handlers/Items/iOS/TemplatedCell.cs +++ b/src/Controls/src/Core/Handlers/Items/iOS/TemplatedCell.cs @@ -306,14 +306,17 @@ public override bool Selected protected abstract (bool, Size) NeedsContentSizeUpdate(Size currentSize); - void IPlatformMeasureInvalidationController.InvalidateMeasure(bool isPropagating) + bool IPlatformMeasureInvalidationController.InvalidateMeasure(bool isPropagating) { // If the cell is not bound (or getting unbounded), we don't want to measure it // and cause a useless and harming InvalidateLayout on the collection view layout if (!_measureInvalidated && _bound) { _measureInvalidated = true; + return true; } + + return false; } protected void OnContentSizeChanged() diff --git a/src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs b/src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs index 16ba34065d9d..c78e60d4a604 100644 --- a/src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs +++ b/src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs @@ -306,14 +306,17 @@ void IPlatformMeasureInvalidationController.InvalidateAncestorsMeasuresWhenMoved // This is a no-op } - void IPlatformMeasureInvalidationController.InvalidateMeasure(bool isPropagating) + bool IPlatformMeasureInvalidationController.InvalidateMeasure(bool isPropagating) { // If the cell is not bound (or getting unbounded), we don't want to measure it // and cause a useless and harming InvalidateLayout on the collection view layout if (!_measureInvalidated && _bound) { _measureInvalidated = true; + return true; } + + return false; } } } diff --git a/src/Controls/src/Core/Page/Page.cs b/src/Controls/src/Core/Page/Page.cs index 985bc26842cf..457e9bd9ca0c 100644 --- a/src/Controls/src/Core/Page/Page.cs +++ b/src/Controls/src/Core/Page/Page.cs @@ -21,7 +21,7 @@ namespace Microsoft.Maui.Controls /// is primarily a base class for more useful derived types. Objects that are derived from the class are most prominently used as the top level UI element in .NET MAUI applications. In addition to their role as the main pages of applications, objects and their descendants can be used with navigation classes, such as or , among others, to provide rich user experiences that conform to the expected behaviors on each platform. /// [DebuggerDisplay("{GetDebuggerDisplay(), nq}")] - public partial class Page : VisualElement, ILayout, IPageController, IElementConfiguration, IPaddingElement, ISafeAreaView, ISafeAreaView2, IView, ITitledElement, IToolbarElement + public partial class Page : VisualElement, ILayout, IPageController, IElementConfiguration, IPaddingElement, ISafeAreaView, ISafeAreaView2, IView, ITitledElement, IToolbarElement, IConstrainedView #if IOS ,IiOSPageSpecifics #endif @@ -212,6 +212,8 @@ public bool IgnoresContainerArea /// bool ISafeAreaView.IgnoreSafeArea => !On().UsingSafeArea(); + bool IConstrainedView.HasFixedConstraints => true; + #if IOS /// bool IiOSPageSpecifics.IsHomeIndicatorAutoHidden diff --git a/src/Controls/src/Core/VisualElement/VisualElement.cs b/src/Controls/src/Core/VisualElement/VisualElement.cs index c392162019ce..4827cea259dd 100644 --- a/src/Controls/src/Core/VisualElement/VisualElement.cs +++ b/src/Controls/src/Core/VisualElement/VisualElement.cs @@ -22,7 +22,7 @@ namespace Microsoft.Maui.Controls /// [DebuggerDisplay("{GetDebuggerDisplay(), nq}")] - public partial class VisualElement : NavigableElement, IAnimatable, IVisualElementController, IResourcesProvider, IStyleElement, IFlowDirectionController, IPropertyPropagationController, IVisualController, IWindowController, IView, IControlsVisualElement + public partial class VisualElement : NavigableElement, IAnimatable, IVisualElementController, IResourcesProvider, IStyleElement, IFlowDirectionController, IPropertyPropagationController, IVisualController, IWindowController, IView, IControlsVisualElement, IConstrainedView { /// Bindable property for . public new static readonly BindableProperty NavigationProperty = NavigableElement.NavigationProperty; @@ -945,6 +945,8 @@ internal LayoutConstraint ComputedConstraint internal LayoutConstraint Constraint => ComputedConstraint | SelfConstraint; + bool IConstrainedView.HasFixedConstraints => Constraint == LayoutConstraint.Fixed; + /// /// Gets a value that indicates that layout for this element is disabled. /// diff --git a/src/Core/src/Core/IConstrainedView.cs b/src/Core/src/Core/IConstrainedView.cs new file mode 100644 index 000000000000..e392e188d194 --- /dev/null +++ b/src/Core/src/Core/IConstrainedView.cs @@ -0,0 +1,6 @@ +namespace Microsoft.Maui; + +internal interface IConstrainedView +{ + bool HasFixedConstraints { get; } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/Page/PageHandler.iOS.cs b/src/Core/src/Handlers/Page/PageHandler.iOS.cs index a8ec163f1386..2a11d919ed8a 100644 --- a/src/Core/src/Handlers/Page/PageHandler.iOS.cs +++ b/src/Core/src/Handlers/Page/PageHandler.iOS.cs @@ -21,14 +21,6 @@ protected override ContentView CreatePlatformView() throw new InvalidOperationException($"PageViewController.View must be a {nameof(ContentView)}"); } - public override void SetVirtualView(IView view) - { - base.SetVirtualView(view); - - // Ensure we tag the ContentView as a Page so that InvalidateAncestorsMeasures can stop propagation here - PlatformView.IsPage = true; - } - public static void MapBackground(IPageHandler handler, IContentView page) { if (handler is IPlatformViewHandler platformViewHandler && platformViewHandler.ViewController is not null) diff --git a/src/Core/src/Platform/iOS/ContentView.cs b/src/Core/src/Platform/iOS/ContentView.cs index 1979a25ef36b..5f6f14398f95 100644 --- a/src/Core/src/Platform/iOS/ContentView.cs +++ b/src/Core/src/Platform/iOS/ContentView.cs @@ -16,8 +16,6 @@ public class ContentView : MauiView // verify we're using the correct subview for masking (and any other purposes) internal const nint ContentTag = 0x63D2A0; - internal bool IsPage { get; set; } - public ContentView() { if (OperatingSystem.IsIOSVersionAtLeast(13) || OperatingSystem.IsMacCatalystVersionAtLeast(13, 1)) diff --git a/src/Core/src/Platform/iOS/IPlatformMeasureInvalidationController.cs b/src/Core/src/Platform/iOS/IPlatformMeasureInvalidationController.cs index ed7be737f8b0..5b41012335c0 100644 --- a/src/Core/src/Platform/iOS/IPlatformMeasureInvalidationController.cs +++ b/src/Core/src/Platform/iOS/IPlatformMeasureInvalidationController.cs @@ -3,5 +3,5 @@ namespace Microsoft.Maui.Platform; internal interface IPlatformMeasureInvalidationController { void InvalidateAncestorsMeasuresWhenMovedToWindow(); - void InvalidateMeasure(bool isPropagating = false); + bool InvalidateMeasure(bool isPropagating = false); } \ No newline at end of file diff --git a/src/Core/src/Platform/iOS/MauiScrollView.cs b/src/Core/src/Platform/iOS/MauiScrollView.cs index 1036b4ef7a87..f8774da4eeb6 100644 --- a/src/Core/src/Platform/iOS/MauiScrollView.cs +++ b/src/Core/src/Platform/iOS/MauiScrollView.cs @@ -87,10 +87,12 @@ void IPlatformMeasureInvalidationController.InvalidateAncestorsMeasuresWhenMoved _invalidateParentWhenMovedToWindow = true; } - void IPlatformMeasureInvalidationController.InvalidateMeasure(bool isPropagating) + bool IPlatformMeasureInvalidationController.InvalidateMeasure(bool isPropagating) { SetNeedsLayout(); InvalidateConstraintsCache(); + + return !isPropagating; } bool IsMeasureValid(double widthConstraint, double heightConstraint) diff --git a/src/Core/src/Platform/iOS/MauiView.cs b/src/Core/src/Platform/iOS/MauiView.cs index 00669b776fa7..e5b09f47a171 100644 --- a/src/Core/src/Platform/iOS/MauiView.cs +++ b/src/Core/src/Platform/iOS/MauiView.cs @@ -24,6 +24,8 @@ public IView? View set => _reference = value == null ? null : new(value); } + bool HasFixedConstraints => CrossPlatformLayout is IConstrainedView { HasFixedConstraints: true }; + bool RespondsToSafeArea() { if (_respondsToSafeArea.HasValue) @@ -55,6 +57,11 @@ protected bool IsMeasureValid(double widthConstraint, double heightConstraint) return heightConstraint == _lastMeasureHeight && widthConstraint == _lastMeasureWidth; } + bool HasBeenMeasured() + { + return !double.IsNaN(_lastMeasureWidth) && !double.IsNaN(_lastMeasureHeight); + } + protected void InvalidateConstraintsCache() { _lastMeasureWidth = double.NaN; @@ -128,10 +135,11 @@ public override void LayoutSubviews() // If the SuperView is a cross-platform layout backed view (i.e. MauiView, MauiScrollView, LayoutView, ..), // then measurement has already happened via SizeThatFits and doesn't need to be repeated in LayoutSubviews. // This is especially important to avoid overriding potentially infinite measurement constraints - // imposed by the parent (i.e. scroll view) with the current bounds. + // imposed by the parent (i.e. scroll view) with the current bounds, except when our bounds are fixed by constraints. // But we _do_ need LayoutSubviews to make a measurement pass if the parent is something else (for example, // the window); there's no guarantee that SizeThatFits has been called in that case. - if (!IsMeasureValid(widthConstraint, heightConstraint) && !this.IsFinalMeasureHandledBySuperView()) + if (!IsMeasureValid(widthConstraint, heightConstraint) && !this.IsFinalMeasureHandledBySuperView() || + !HasBeenMeasured() && HasFixedConstraints) { CrossPlatformMeasure(widthConstraint, heightConstraint); CacheMeasureConstraints(widthConstraint, heightConstraint); @@ -163,10 +171,27 @@ void IPlatformMeasureInvalidationController.InvalidateAncestorsMeasuresWhenMoved _invalidateParentWhenMovedToWindow = true; } - void IPlatformMeasureInvalidationController.InvalidateMeasure(bool isPropagating) + bool IPlatformMeasureInvalidationController.InvalidateMeasure(bool isPropagating) { InvalidateConstraintsCache(); SetNeedsLayout(); + + // If we're propagating, we can stop at the first view with fixed constraints + if (isPropagating && HasFixedConstraints) + { + // We're stopping propagation here, but we have to account for the wrapper view + // which needs to be invalidated for consistency too. + if (Superview is WrapperView wrapper) + { + wrapper.SetNeedsLayout(); + } + + return false; + } + + // If we're not propagating, then this view is the one triggering the invalidation + // and one possible cause is that constraints have changed, so we have to propagate the invalidation. + return true; } [UnconditionalSuppressMessage("Memory", "MEM0002", Justification = IUIViewLifeCycleEvents.UnconditionalSuppressMessage)] diff --git a/src/Core/src/Platform/iOS/ViewExtensions.cs b/src/Core/src/Platform/iOS/ViewExtensions.cs index 0d5fb61fff6f..b834a925c274 100644 --- a/src/Core/src/Platform/iOS/ViewExtensions.cs +++ b/src/Core/src/Platform/iOS/ViewExtensions.cs @@ -287,16 +287,21 @@ public static void InvalidateMeasure(this UIView platformView, IView view) internal static void InvalidateMeasure(this UIView platformView) { + var propagate = true; + if (platformView is IPlatformMeasureInvalidationController mauiPlatformView) { - mauiPlatformView.InvalidateMeasure(); + propagate = mauiPlatformView.InvalidateMeasure(); } else { platformView.SetNeedsLayout(); } - platformView.InvalidateAncestorsMeasures(); + if (propagate) + { + platformView.InvalidateAncestorsMeasures(); + } } internal static void InvalidateAncestorsMeasures(this UIView child) @@ -322,22 +327,20 @@ internal static void InvalidateAncestorsMeasures(this UIView child) } // Now invalidate the parent view + var propagate = true; var superviewMauiPlatformLayout = superview as IPlatformMeasureInvalidationController; if (superviewMauiPlatformLayout is not null) { - superviewMauiPlatformLayout.InvalidateMeasure(isPropagating: true); + propagate = superviewMauiPlatformLayout.InvalidateMeasure(isPropagating: true); } else { superview.SetNeedsLayout(); } - // Potential improvement: if the MAUI view (superview here) is constrained to a fixed size, we could stop propagating - // when doing this, we must pay attention to a scenario where a non-fixed-size view becomes fixed-size - if (superview is ContentView { IsPage: true } or UIScrollView) + if (!propagate) { - // We reached the root view or a scrollable area (includes collection view), stop propagating - // The view will eventually watch its content size and invoke InvalidateAncestorsMeasures when needed + // We've been asked to stop propagation, so let's stop here return; } @@ -1013,7 +1016,8 @@ internal static float GetDisplayDensity(this UIView? view) => private const nint NativeViewControlledByCrossPlatformLayout = 0x63D2A1; - internal static bool IsFinalMeasureHandledBySuperView(this UIView? view) => view?.Superview is ICrossPlatformLayoutBacking { CrossPlatformLayout: not null } or { Tag: NativeViewControlledByCrossPlatformLayout }; + internal static bool IsFinalMeasureHandledBySuperView(this UIView? view) + => view?.Superview is ICrossPlatformLayoutBacking { CrossPlatformLayout: not null } or { Tag: NativeViewControlledByCrossPlatformLayout }; internal static void MarkAsCrossPlatformLayoutBacking(this UIView view) { diff --git a/src/Core/src/Platform/iOS/WrapperView.cs b/src/Core/src/Platform/iOS/WrapperView.cs index ed58e1db4192..b75189a2f877 100644 --- a/src/Core/src/Platform/iOS/WrapperView.cs +++ b/src/Core/src/Platform/iOS/WrapperView.cs @@ -319,10 +319,11 @@ void IPlatformMeasureInvalidationController.InvalidateAncestorsMeasuresWhenMoved _invalidateParentWhenMovedToWindow = true; } - void IPlatformMeasureInvalidationController.InvalidateMeasure(bool isPropagating) + bool IPlatformMeasureInvalidationController.InvalidateMeasure(bool isPropagating) { InvalidateConstraintsCache(); SetNeedsLayout(); + return true; } [UnconditionalSuppressMessage("Memory", "MEM0002", Justification = IUIViewLifeCycleEvents.UnconditionalSuppressMessage)] diff --git a/src/Core/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt b/src/Core/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt index 19bf7d6f03af..e15cf1f30789 100644 --- a/src/Core/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt +++ b/src/Core/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt @@ -87,6 +87,5 @@ override Microsoft.Maui.Handlers.EditorHandler.NeedsContainer.get -> bool override Microsoft.Maui.Handlers.WindowHandler.DisconnectHandler(UIKit.UIWindow! platformView) -> void *REMOVED*override Microsoft.Maui.Handlers.ScrollViewHandler.NeedsContainer.get -> bool override Microsoft.Maui.Handlers.ImageButtonHandler.SetupContainer() -> void -override Microsoft.Maui.Handlers.PageHandler.SetVirtualView(Microsoft.Maui.IView! view) -> void *REMOVED*override Microsoft.Maui.Platform.WrapperView.SetNeedsLayout() -> void *REMOVED*override Microsoft.Maui.Platform.MauiView.SetNeedsLayout() -> void diff --git a/src/Core/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt b/src/Core/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt index 731fd8731bd3..5be19f9f8925 100644 --- a/src/Core/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt +++ b/src/Core/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt @@ -88,6 +88,5 @@ override Microsoft.Maui.Handlers.EditorHandler.NeedsContainer.get -> bool override Microsoft.Maui.Handlers.WindowHandler.DisconnectHandler(UIKit.UIWindow! platformView) -> void *REMOVED*override Microsoft.Maui.Handlers.ScrollViewHandler.NeedsContainer.get -> bool override Microsoft.Maui.Handlers.ImageButtonHandler.SetupContainer() -> void -override Microsoft.Maui.Handlers.PageHandler.SetVirtualView(Microsoft.Maui.IView! view) -> void *REMOVED*override Microsoft.Maui.Platform.WrapperView.SetNeedsLayout() -> void *REMOVED*override Microsoft.Maui.Platform.MauiView.SetNeedsLayout() -> void From ef1ec07908eda7b7bf9979fbbf9c374fbe7f2acf Mon Sep 17 00:00:00 2001 From: Bhavanesh N Date: Mon, 14 Apr 2025 20:21:42 +0530 Subject: [PATCH 10/34] [Testing]Fix some Flaky UI tests that fails on android (#28956) * Fix some Flaky UI tests that fails on android * Add helper to wait for more button * throw when platform is not supported * space --- .../Issues/CarouselViewUITests.RemoveAt.cs | 2 ++ .../Tests/Issues/XFIssue/Issue10608.cs | 2 ++ .../Tests/Issues/XFIssue/Issue2809.cs | 3 +++ .../src/UITest.Appium/HelperExtensions.cs | 21 +++++++++++++++++++ 4 files changed, 28 insertions(+) diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/CarouselViewUITests.RemoveAt.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/CarouselViewUITests.RemoveAt.cs index 6229790a9cbb..8aab56270196 100644 --- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/CarouselViewUITests.RemoveAt.cs +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/CarouselViewUITests.RemoveAt.cs @@ -17,7 +17,9 @@ public CarouselViewRemoveAt(TestDevice device) [Category(UITestCategories.CarouselView)] public void Issue10300Test() { + App.WaitForElement("AddMe"); App.Click("AddMe"); + App.WaitForElement("DeleteMe"); App.Click("DeleteMe"); App.WaitForElement("CloseMe"); App.Click("CloseMe"); diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue10608.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue10608.cs index 0b87e51b1fa9..572a63c41ea4 100644 --- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue10608.cs +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue10608.cs @@ -27,7 +27,9 @@ public Issue10608(TestDevice testDevice) : base(testDevice) [Category(UITestCategories.Shell)] public void ShellWithTopTabsFreezesWhenNavigatingFlyoutItems() { + App.WaitForElement(FlyoutItem6); App.Tap(FlyoutItem6); + App.WaitForElement("FlyoutItem0"); App.Tap("FlyoutItem0"); for (int i = 0; i < 5; i++) { diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue2809.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue2809.cs index c5d277c6e097..86bf6cd6e137 100644 --- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue2809.cs +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue2809.cs @@ -16,6 +16,9 @@ public Issue2809(TestDevice testDevice) : base(testDevice) [Category(UITestCategories.ToolbarItem)] public void TestPageDoesntCrash() { +#if ANDROID && WINDOWS // WaitForMoreButton is only supported on Android and Windows + App.WaitForMoreButton(); +#endif App.TapMoreButton(); App.Tap("Item 1"); } diff --git a/src/TestUtils/src/UITest.Appium/HelperExtensions.cs b/src/TestUtils/src/UITest.Appium/HelperExtensions.cs index d8e72e9f864d..954e3c8dd2f0 100644 --- a/src/TestUtils/src/UITest.Appium/HelperExtensions.cs +++ b/src/TestUtils/src/UITest.Appium/HelperExtensions.cs @@ -2280,6 +2280,27 @@ public static void ToggleSecondaryToolbarItems(this IApp app) app.CommandExecutor.Execute("toggleSecondaryToolbarItems", ImmutableDictionary.Empty); } + /// + /// Waits for the "More" button in the app, with platform-specific logic for Android and Windows. + /// This method does not currently support iOS and macOS platforms, where the "More" button is not shown. + /// + /// Represents the main gateway to interact with an app. + public static void WaitForMoreButton(this IApp app) + { + if (app is AppiumAndroidApp) + { + app.WaitForElement(AppiumQuery.ByXPath("//android.widget.ImageView[@content-desc=\"More options\"]")); + } + else if (app is AppiumWindowsApp) + { + app.WaitForElement(AppiumQuery.ByAccessibilityId("MoreButton")); + } + else + { + throw new InvalidOperationException($"WaitForMoreButton is not supported on this platform."); + } + } + /// /// Taps the "More" button in the app, with platform-specific logic for Android and Windows. /// This method does not currently support iOS and macOS platforms, where the "More" button is not shown. From 8e875b73fd7a1500fc012559cf66118f2bbfd633 Mon Sep 17 00:00:00 2001 From: Rui Marinho Date: Tue, 15 Apr 2025 12:34:35 +0100 Subject: [PATCH 11/34] [ci] Update arcade (#29000) --- .config/dotnet-tools.json | 2 +- eng/Version.Details.xml | 44 +++++++++++++++++++-------------------- eng/Versions.props | 18 ++++++++-------- global.json | 4 ++-- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 78c54a9116bd..13d2d547569b 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -24,7 +24,7 @@ "rollForward": false }, "microsoft.dotnet.xharness.cli": { - "version": "9.0.0-prerelease.25209.2", + "version": "9.0.0-prerelease.25214.1", "commands": [ "xharness" ], diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 6cf2a8a59c8b..2bd630107456 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,50 +1,50 @@ - + https://github.com/dotnet/xharness - 856ea5c8f3212dc11b6ce369640ea07558706588 + 7b61da39ea1692a607459913167673c6096fd7f1 - + https://github.com/dotnet/xharness - 856ea5c8f3212dc11b6ce369640ea07558706588 + 7b61da39ea1692a607459913167673c6096fd7f1 - + https://github.com/dotnet/xharness - 856ea5c8f3212dc11b6ce369640ea07558706588 + 7b61da39ea1692a607459913167673c6096fd7f1 - + https://github.com/dotnet/arcade - 5ba9ca776c1d0bb72b2791591e54cf51fc52dfee + aa61e8c20a869bcc994f8b29eb07d927d2bec6f4 - + https://github.com/dotnet/arcade - 5ba9ca776c1d0bb72b2791591e54cf51fc52dfee + aa61e8c20a869bcc994f8b29eb07d927d2bec6f4 - + https://github.com/dotnet/arcade - 5ba9ca776c1d0bb72b2791591e54cf51fc52dfee + aa61e8c20a869bcc994f8b29eb07d927d2bec6f4 - + https://github.com/dotnet/arcade - 5ba9ca776c1d0bb72b2791591e54cf51fc52dfee + aa61e8c20a869bcc994f8b29eb07d927d2bec6f4 - + https://github.com/dotnet/arcade - 5ba9ca776c1d0bb72b2791591e54cf51fc52dfee + aa61e8c20a869bcc994f8b29eb07d927d2bec6f4 - + https://github.com/dotnet/arcade - 5ba9ca776c1d0bb72b2791591e54cf51fc52dfee + aa61e8c20a869bcc994f8b29eb07d927d2bec6f4 - + https://github.com/dotnet/arcade - 5ba9ca776c1d0bb72b2791591e54cf51fc52dfee + aa61e8c20a869bcc994f8b29eb07d927d2bec6f4 - + https://github.com/dotnet/arcade - 5ba9ca776c1d0bb72b2791591e54cf51fc52dfee + aa61e8c20a869bcc994f8b29eb07d927d2bec6f4 diff --git a/eng/Versions.props b/eng/Versions.props index 3d3475618e42..47cd6c052da6 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -125,22 +125,22 @@ <_HarfBuzzSharpVersion>8.3.0.1 <_SkiaSharpNativeAssetsVersion>0.0.0-commit.e57e2a11dac4ccc72bea52939dede49816842005.1728 7.0.120 - 9.0.0-prerelease.25209.2 - 9.0.0-prerelease.25209.2 - 9.0.0-prerelease.25209.2 + 9.0.0-prerelease.25214.1 + 9.0.0-prerelease.25214.1 + 9.0.0-prerelease.25214.1 0.9.2 2.0.0.4 1.3.0 0.9.0 4.2.3 9.0.0 - 9.0.0-beta.25164.2 - 9.0.0-beta.25164.2 - 9.0.0-beta.25164.2 - 9.0.0-beta.25164.2 + 9.0.0-beta.25208.6 + 9.0.0-beta.25208.6 + 9.0.0-beta.25208.6 + 9.0.0-beta.25208.6 1.1.87-gba258badda - 9.0.0-beta.25164.2 - 9.0.0-beta.25164.2 + 9.0.0-beta.25208.6 + 9.0.0-beta.25208.6 17.6.0 diff --git a/global.json b/global.json index 679feeee8d3e..4a2c7f91c8f3 100644 --- a/global.json +++ b/global.json @@ -1,11 +1,11 @@ { "tools": { - "dotnet": "9.0.104" + "dotnet": "9.0.105" }, "msbuild-sdks": { "MSBuild.Sdk.Extras": "3.0.44", "Microsoft.Build.NoTargets": "3.7.0", - "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.25164.2" + "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.25208.6" }, "sdk": { "allowPrerelease": false From b83b19ce0f78cc5d1dadc58096c6bdc63a4ca56f Mon Sep 17 00:00:00 2001 From: Rui Marinho Date: Tue, 15 Apr 2025 17:33:05 +0100 Subject: [PATCH 12/34] [ci] Update sdk --- NuGet.config | 1 - eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/NuGet.config b/NuGet.config index 58d274efbdd7..3ef655cf3880 100644 --- a/NuGet.config +++ b/NuGet.config @@ -6,7 +6,6 @@ - diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 60ddda22533c..7d858414240f 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,8 +1,8 @@ - + https://github.com/dotnet/sdk - 90a1f93877806fe281973ec619c3e30fbbbbc3dc + a081488f32ee97b730ac15197a1b0044a89a3995 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 5fd9d3279199..ed3671d93dba 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 9.0.14 - 10.0.100-preview.4.25210.19 + 10.0.100-preview.4.25211.22 $(MicrosoftNETSdkPackageVersion) 10.0.0-preview.4.25209.13 From a7253742bcc148a4a842afc79b28c27f93c597b0 Mon Sep 17 00:00:00 2001 From: Rui Marinho Date: Tue, 15 Apr 2025 19:01:57 +0100 Subject: [PATCH 13/34] Fix public api --- src/Core/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt | 2 +- src/Core/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Core/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt b/src/Core/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt index 19d7cea6dd55..057dd8c28dc2 100644 --- a/src/Core/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt +++ b/src/Core/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt @@ -135,6 +135,6 @@ override Microsoft.Maui.Handlers.ImageButtonHandler.SetupContainer() -> void *REMOVED*virtual Microsoft.Maui.MauiUIApplicationDelegate.FinishedLaunching(UIKit.UIApplication! application, Foundation.NSDictionary! launchOptions) -> bool *REMOVED*virtual Microsoft.Maui.MauiUIApplicationDelegate.WillFinishLaunching(UIKit.UIApplication! application, Foundation.NSDictionary! launchOptions) -> bool *REMOVED*static Microsoft.Maui.Platform.ApplicationExtensions.CreatePlatformWindow(this UIKit.IUIApplicationDelegate! platformApplication, Microsoft.Maui.IApplication! application, UIKit.UIApplication! uiApplication, Foundation.NSDictionary! launchOptions) -> void -override Microsoft.Maui.Handlers.PageHandler.SetVirtualView(Microsoft.Maui.IView! view) -> void +*REMOVED*override Microsoft.Maui.Handlers.PageHandler.SetVirtualView(Microsoft.Maui.IView! view) -> void *REMOVED*override Microsoft.Maui.Platform.WrapperView.SetNeedsLayout() -> void *REMOVED*override Microsoft.Maui.Platform.MauiView.SetNeedsLayout() -> void diff --git a/src/Core/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt b/src/Core/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt index f9585992e2dc..77d3453427fa 100644 --- a/src/Core/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt +++ b/src/Core/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt @@ -133,6 +133,6 @@ override Microsoft.Maui.Handlers.ImageButtonHandler.SetupContainer() -> void *REMOVED*virtual Microsoft.Maui.MauiUIApplicationDelegate.FinishedLaunching(UIKit.UIApplication! application, Foundation.NSDictionary! launchOptions) -> bool *REMOVED*virtual Microsoft.Maui.MauiUIApplicationDelegate.WillFinishLaunching(UIKit.UIApplication! application, Foundation.NSDictionary! launchOptions) -> bool *REMOVED*static Microsoft.Maui.Platform.ApplicationExtensions.CreatePlatformWindow(this UIKit.IUIApplicationDelegate! platformApplication, Microsoft.Maui.IApplication! application, UIKit.UIApplication! uiApplication, Foundation.NSDictionary! launchOptions) -> void -override Microsoft.Maui.Handlers.PageHandler.SetVirtualView(Microsoft.Maui.IView! view) -> void +*REMOVED*override Microsoft.Maui.Handlers.PageHandler.SetVirtualView(Microsoft.Maui.IView! view) -> void *REMOVED*override Microsoft.Maui.Platform.WrapperView.SetNeedsLayout() -> void *REMOVED*override Microsoft.Maui.Platform.MauiView.SetNeedsLayout() -> void From 3314e147d7d6ef31174af8bf91d412df1b1893af Mon Sep 17 00:00:00 2001 From: NirmalKumarYuvaraj <97871636+NirmalKumarYuvaraj@users.noreply.github.com> Date: Mon, 24 Mar 2025 04:56:20 +0530 Subject: [PATCH 14/34] Fixed Keyboard Scrolling in editors with Center or End VerticalTextAlignment (#25827) * Fixed Keyboard scrolling in editors with Center or end VerticalTextAlignment is off * Modified the code change to consider content offset value * Removed unwanted file changes * Removed test cases * Modified changes * Modified the code changes and included UI test * Removed unwanted code changes * updated changes * optimized changes * updated test case * Added a button for Start * Changes in MauiTextView --------- Co-authored-by: Matthew Leibowitz Co-authored-by: Dhivya-SF4094 <127717131+Dhivya-SF4094@users.noreply.github.com> --- .../TestCases.HostApp/Issues/Issue24977.cs | 146 ++++++++++++++++++ .../Tests/Issues/Issue24977.cs | 74 +++++++++ .../Platform/iOS/KeyboardAutoManagerScroll.cs | 2 +- src/Core/src/Platform/iOS/MauiTextView.cs | 13 ++ 4 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 src/Controls/tests/TestCases.HostApp/Issues/Issue24977.cs create mode 100644 src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue24977.cs diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue24977.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue24977.cs new file mode 100644 index 000000000000..d55ef4f10198 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue24977.cs @@ -0,0 +1,146 @@ +namespace Maui.Controls.Sample.Issues; + +[Issue(IssueTracker.Github, 24977, "Keyboard Scrolling in editors with Center or End VerticalTextAlignment is off", PlatformAffected.iOS)] +public class Issue24977 : TestNavigationPage +{ + protected override void Init() + { + PushAsync(new ContentPage + { + Content = new VerticalStackLayout + { + Spacing = 12, + Padding = new Thickness(12, 24), + Children = + { + CreateButton(TextAlignment.Start), + CreateButton(TextAlignment.Center), + CreateButton(TextAlignment.End), + } + } + }); + } + + Button CreateButton(TextAlignment textAlignment) + { + var btn = new Button + { + Text = textAlignment.ToString(), + AutomationId = $"{textAlignment}Button" + }; + btn.Clicked += (s, e) => Navigation.PushAsync(new Issue24977_1(textAlignment)); + return btn; + } +} + +public class Issue24977_1 : TestContentPage +{ + Editor editor; + Label cursorHeightTracker; + + public Issue24977_1(TextAlignment textAlignment) + { + editor.VerticalTextAlignment = textAlignment; + } + + protected override void Init() + { + var rootGrid = new Grid + { + RowDefinitions = + { + new RowDefinition { Height = 50 }, + new RowDefinition { Height = 50 }, + new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }, + new RowDefinition { Height = 50 } + }, + Margin = new Thickness(30) + }; + + var entry = new Entry + { + Text = "Content before", + AutomationId = "EntryBefore", + ReturnType = ReturnType.Next, + BackgroundColor = Colors.Aquamarine, + }; + + cursorHeightTracker = new Label + { + Text = "0", + AutomationId = "CursorHeightTracker", + BackgroundColor = Colors.Aquamarine, + }; + + editor = new Editor + { + Text = "Hello World!", + AutomationId = "IssueEditor", + BackgroundColor = Colors.Orange, + }; + editor.TextChanged += Editor_TextChanged; + + var button = new Button { Text = "Erase" }; + button.Clicked += (s, e) => editor.Text = string.Empty; + + rootGrid.Add(entry, 0, 0); + rootGrid.Add(cursorHeightTracker, 0, 1); + rootGrid.Add(editor, 0, 2); + + rootGrid.Add(button, 0, 3); + + Content = rootGrid; + } + + private void Editor_TextChanged(object sender, TextChangedEventArgs e) + { + if (sender is Editor editor) + { + AddCursorHeightToLabel(editor); + } + } + + void AddCursorHeightToLabel(Editor editor) + { +#if IOS + var textInput = editor.Handler.PlatformView as UIKit.UITextView; + var selectedTextRange = textInput?.SelectedTextRange; + var localCursor = selectedTextRange is not null ? textInput?.GetCaretRectForPosition(selectedTextRange.Start) : null; + + if (localCursor is CoreGraphics.CGRect local && textInput is not null) + { + var container = GetContainerView(textInput); + var cursorInContainer = container.ConvertRectFromView(local, textInput); + var cursorInWindow = container.ConvertRectToView(cursorInContainer, null); + + cursorHeightTracker.Text = cursorInWindow.Y.ToString(); + } + + UIKit.UIView GetContainerView(UIKit.UIView startingPoint) + { + var rootView = FindResponder(startingPoint)?.View; + + if (rootView is not null) + { + return rootView; + } + + return null; + } + + T FindResponder(UIKit.UIView view) + where T : UIKit.UIResponder + { + var nextResponder = view as UIKit.UIResponder; + while (nextResponder is not null) + { + nextResponder = nextResponder.NextResponder; + + if (nextResponder is T responder) + return responder; + } + return null; + } +#endif + } +} diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue24977.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue24977.cs new file mode 100644 index 000000000000..b51f785f790f --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue24977.cs @@ -0,0 +1,74 @@ +#if IOS +using System.Drawing; +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; +using System.Text; + +namespace Microsoft.Maui.TestCases.Tests.Issues; +public class Issue24977 : _IssuesUITest +{ + public Issue24977(TestDevice device) : base(device) { } + + public override string Issue => "Keyboard Scrolling in editors with Center or End VerticalTextAlignment is off"; + + [Test] + [Category(UITestCategories.Editor)] + public void KeepEditorCursorAboveKeyboardWithVerticalAlignmentAsCenter() + { + TestKeepEditorCursorAboveKeyboard("CenterButton", true); + } + + [Test] + [Category(UITestCategories.Editor)] + public void KeepEditorCursorAboveKeyboardWithVerticalAlignmentAsEnd() + { + TestKeepEditorCursorAboveKeyboard("EndButton"); + } + + void TestKeepEditorCursorAboveKeyboard(string buttonId, bool fromCenter = false) + { + App.WaitForElement(buttonId); + App.Tap(buttonId); + Thread.Sleep(1000); + + var app = App as AppiumApp; + if (app == null) + return; + + var editorRect = app.WaitForElement("IssueEditor").GetRect(); + app.Click("IssueEditor"); + + var sb = new StringBuilder(); + for (int i = 1; i <= 20; i++) + { + sb.Append($"\n{i}"); + } + + app.EnterText("IssueEditor", sb.ToString()); + + var keyboardLocation = KeyboardScrolling.FindiOSKeyboardLocation(app.Driver); + + var cursorLabel = app.WaitForElement("CursorHeightTracker").GetText(); + var cursorHeight1 = Convert.ToDouble(cursorLabel); + try + { + if (keyboardLocation is Point keyboardPoint) + { + Assert.That(cursorHeight1 < keyboardPoint.Y); + } + else + { + Assert.Fail("keyboardLocation is null"); + } + } + finally + { + if (fromCenter) + { + App.Back(); + } + } + } +} +#endif \ No newline at end of file diff --git a/src/Core/src/Platform/iOS/KeyboardAutoManagerScroll.cs b/src/Core/src/Platform/iOS/KeyboardAutoManagerScroll.cs index a041ee679d76..85865b5df29a 100644 --- a/src/Core/src/Platform/iOS/KeyboardAutoManagerScroll.cs +++ b/src/Core/src/Platform/iOS/KeyboardAutoManagerScroll.cs @@ -24,7 +24,7 @@ public static class KeyboardAutoManagerScroll static CGPoint StartingContentOffset; static UIEdgeInsets StartingScrollIndicatorInsets; static UIEdgeInsets StartingContentInsets; - static CGRect KeyboardFrame = CGRect.Empty; + internal static CGRect KeyboardFrame = CGRect.Empty; static CGPoint TopViewBeginOrigin = new(nfloat.MaxValue, nfloat.MaxValue); static readonly CGPoint InvalidPoint = new(nfloat.MaxValue, nfloat.MaxValue); static double AnimationDuration = 0.25; diff --git a/src/Core/src/Platform/iOS/MauiTextView.cs b/src/Core/src/Platform/iOS/MauiTextView.cs index 80a561e7b2c6..abd5be6475b1 100644 --- a/src/Core/src/Platform/iOS/MauiTextView.cs +++ b/src/Core/src/Platform/iOS/MauiTextView.cs @@ -172,6 +172,19 @@ void ShouldCenterVertically() Maui.TextAlignment.End => new CGPoint(0, -Math.Max(1, availableSpace)), _ => ContentOffset, }; + + // Scroll the content to the cursor position if it is hidden by the keyboard + if (KeyboardAutoManagerScroll.IsKeyboardShowing && (VerticalTextAlignment == Maui.TextAlignment.Center || VerticalTextAlignment == Maui.TextAlignment.End)) + { + var cursorRect = KeyboardAutoManagerScroll.FindCursorPosition(); + var keyboardTop = KeyboardAutoManagerScroll.KeyboardFrame.Top; + + if (cursorRect.HasValue && cursorRect.Value.Bottom > keyboardTop) + { + var offset = cursorRect.Value.Bottom - KeyboardAutoManagerScroll.KeyboardFrame.Top; + ContentOffset = new CGPoint(ContentOffset.X, ContentOffset.Y + offset); + } + } } void UpdatePlaceholderFont(UIFont? value) From 61991e646a12a2e48ef8c9bd4acc56af2a8bfce0 Mon Sep 17 00:00:00 2001 From: Stephane Delcroix Date: Mon, 24 Mar 2025 00:55:21 +0100 Subject: [PATCH 15/34] [XC] better support for nullable props and BPs (#28550) --- .../src/Build.Tasks/SetPropertiesVisitor.cs | 61 +++++++++++++------ .../Xaml.UnitTests/Issues/Bz24910.xaml.cs | 7 ++- .../Xaml.UnitTests/Issues/Unreported008.xaml | 38 ++++++------ .../Issues/Unreported008.xaml.cs | 13 ++++ 4 files changed, 82 insertions(+), 37 deletions(-) diff --git a/src/Controls/src/Build.Tasks/SetPropertiesVisitor.cs b/src/Controls/src/Build.Tasks/SetPropertiesVisitor.cs index 537fbb0698d3..a51cf6a2c0a9 100644 --- a/src/Controls/src/Build.Tasks/SetPropertiesVisitor.cs +++ b/src/Controls/src/Build.Tasks/SetPropertiesVisitor.cs @@ -1410,6 +1410,25 @@ static IEnumerable SetBinding(VariableDefinition parent, FieldRefer static bool CanSetValue(FieldReference bpRef, bool attached, INode node, IXmlLineInfo iXmlLineInfo, ILContext context) { + static bool CanSetValue (TypeReference bpTypeRef, VariableDefinition varValue, ILContext context, IXmlLineInfo iXmlLineInfo) + { + // If it's an attached BP, there's no second chance to handle IMarkupExtensions, so we try here. + // Worst case scenario ? InvalidCastException at runtime + if (varValue.VariableType.FullName == "System.Object") + return true; + var implicitOperator = varValue.VariableType.GetImplicitOperatorTo(context.Cache, bpTypeRef, context.Body.Method.Module); + if (implicitOperator != null) + return true; + + //as we're in the SetValue Scenario, we can accept value types, they'll be boxed + if (varValue.VariableType.IsValueType && bpTypeRef.FullName == "System.Object") + return true; + + if (varValue.VariableType.InheritsFromOrImplements(context.Cache, bpTypeRef) || varValue.VariableType.FullName == "System.Object") + return true; + return false; + } + var module = context.Body.Method.Module; if (bpRef == null) @@ -1424,22 +1443,23 @@ static bool CanSetValue(FieldReference bpRef, bool attached, INode node, IXmlLin if (!context.Variables.TryGetValue(elementNode, out VariableDefinition varValue)) return false; + var bpTypeRef = bpRef.GetBindablePropertyType(context.Cache, iXmlLineInfo, module); - // If it's an attached BP, there's no second chance to handle IMarkupExtensions, so we try here. - // Worst case scenario ? InvalidCastException at runtime - if (varValue.VariableType.FullName == "System.Object") - return true; - var implicitOperator = varValue.VariableType.GetImplicitOperatorTo(context.Cache, bpTypeRef, module); - if (implicitOperator != null) - return true; - //as we're in the SetValue Scenario, we can accept value types, they'll be boxed - if (varValue.VariableType.IsValueType && bpTypeRef.FullName == "System.Object") + if (CanSetValue(bpTypeRef, varValue, context, iXmlLineInfo)) return true; - return varValue.VariableType.InheritsFromOrImplements(context.Cache, bpTypeRef) || varValue.VariableType.FullName == "System.Object"; + if (bpTypeRef.ResolveCached(context.Cache).FullName == "System.Nullable`1") + { + bpTypeRef = ((GenericInstanceType)bpTypeRef).GenericArguments[0]; + if (CanSetValue(bpTypeRef, varValue, context, iXmlLineInfo)) + return true; + } + + return false; } + static bool CanGetValue(VariableDefinition parent, FieldReference bpRef, bool attached, IXmlLineInfo iXmlLineInfo, ILContext context, out TypeReference propertyType) { var module = context.Body.Method.Module; @@ -1483,32 +1503,37 @@ static IEnumerable SetValue(VariableDefinition parent, FieldReferen var @else = Create(OpCodes.Nop); var endif = Create(OpCodes.Nop); - if (context.Variables[elementNode].VariableType.FullName == "System.Object") + + var varValue = context.Variables[elementNode]; + if (varValue.VariableType.FullName == "System.Object") { //if(value != null && value.GetType().IsAssignableFrom(typeof(BindingBase))) - yield return Create(Ldloc, context.Variables[elementNode]); + yield return Create(Ldloc, varValue); yield return Create(Brfalse, @else); - yield return Create(Ldtoken, module.ImportReference(context.Cache, ("Microsoft.Maui.Controls", "Microsoft.Maui.Controls", "BindingBase"))); yield return Create(Call, module.ImportMethodReference(context.Cache, ("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true)); - yield return Create(Ldloc, context.Variables[elementNode]); + yield return Create(Ldloc, varValue); yield return Create(Callvirt, module.ImportMethodReference(context.Cache, ("mscorlib", "System", "Object"), methodName: "GetType", paramCount: 0)); yield return Create(Callvirt, module.ImportMethodReference(context.Cache, ("mscorlib", "System", "Type"), methodName: "IsAssignableFrom", parameterTypes: new[] { ("mscorlib", "System", "Type") })); yield return Create(Brfalse, @else); //then - yield return Create(Ldloc, context.Variables[elementNode]); + yield return Create(Ldloc, varValue); yield return Create(Br, endif); //else yield return @else; } var bpTypeRef = bpRef.GetBindablePropertyType(context.Cache, iXmlLineInfo, module); - foreach (var instruction in context.Variables[elementNode].LoadAs(context.Cache, bpTypeRef, module)) + foreach (var instruction in varValue.LoadAs(context.Cache, bpTypeRef, module)) yield return instruction; if (bpTypeRef.IsValueType) + { + if ( bpTypeRef.ResolveCached(context.Cache).FullName == "System.Nullable`1" + && TypeRefComparer.Default.Equals(varValue.VariableType, ((GenericInstanceType)bpTypeRef).GenericArguments[0])) + bpTypeRef = ((GenericInstanceType)bpTypeRef).GenericArguments[0]; yield return Create(Box, module.ImportReference(bpTypeRef)); - + } //endif - if (context.Variables[elementNode].VariableType.FullName == "System.Object") + if (varValue.VariableType.FullName == "System.Object") yield return endif; } diff --git a/src/Controls/tests/Xaml.UnitTests/Issues/Bz24910.xaml.cs b/src/Controls/tests/Xaml.UnitTests/Issues/Bz24910.xaml.cs index fc4c19ae7ab5..a820be8ef0d2 100644 --- a/src/Controls/tests/Xaml.UnitTests/Issues/Bz24910.xaml.cs +++ b/src/Controls/tests/Xaml.UnitTests/Issues/Bz24910.xaml.cs @@ -47,6 +47,9 @@ public void ConversionForNullable(bool useCompiledXaml) [TestCase(true), TestCase(false)] public void AllowNull(bool useCompiledXaml) { + if (useCompiledXaml) + MockCompiler.Compile(typeof(Bz24910)); + var page = new Bz24910(useCompiledXaml); var control = page.control2; Assert.Null(control.NullableInt); @@ -85,7 +88,7 @@ public void AllowNonBindableNullable(bool useCompiledXaml) public class Bz24910Control : Button { public static readonly BindableProperty NullableIntProperty = - BindableProperty.Create("NullableInt", typeof(int?), typeof(Bz24910Control), default(int?)); + BindableProperty.Create(nameof(NullableInt), typeof(int?), typeof(Bz24910Control), default(int?)); public int? NullableInt { @@ -94,7 +97,7 @@ public int? NullableInt } public static readonly BindableProperty NullableDoubleProperty = - BindableProperty.Create("NullableDouble", typeof(double?), typeof(Bz24910Control), default(double?)); + BindableProperty.Create(nameof(NullableDouble), typeof(double?), typeof(Bz24910Control), default(double?)); public double? NullableDouble { diff --git a/src/Controls/tests/Xaml.UnitTests/Issues/Unreported008.xaml b/src/Controls/tests/Xaml.UnitTests/Issues/Unreported008.xaml index fac231519002..896c9873ec14 100644 --- a/src/Controls/tests/Xaml.UnitTests/Issues/Unreported008.xaml +++ b/src/Controls/tests/Xaml.UnitTests/Issues/Unreported008.xaml @@ -2,22 +2,26 @@ - - yyyy-MM-dd - - - - Jan 1 2000 - - - - - - - Dec 31 2050 - - - - + + + yyyy-MM-dd + + + + Jan 1 2000 + + + + + + + Dec 31 2050 + + + + + + \ No newline at end of file diff --git a/src/Controls/tests/Xaml.UnitTests/Issues/Unreported008.xaml.cs b/src/Controls/tests/Xaml.UnitTests/Issues/Unreported008.xaml.cs index 5866e5458d4a..410ff8fbab4d 100644 --- a/src/Controls/tests/Xaml.UnitTests/Issues/Unreported008.xaml.cs +++ b/src/Controls/tests/Xaml.UnitTests/Issues/Unreported008.xaml.cs @@ -4,6 +4,17 @@ namespace Microsoft.Maui.Controls.Xaml.UnitTests { + public class Unreported008View : ContentView + { + public static readonly BindableProperty DateProperty = BindableProperty.Create(nameof(Date), typeof(DateTime?), typeof(Unreported008View), null); + + public DateTime? Date + { + get { return (DateTime?)GetValue(DateProperty); } + set { SetValue(DateProperty, value); } + } + } + public partial class Unreported008 : ContentPage { public Unreported008() @@ -27,6 +38,8 @@ public void PickerDateTimesAndXamlC(bool useCompiledXaml) Assert.AreEqual(DateTime.Today, picker.Date.Date); Assert.AreEqual(new DateTime(2000, 1, 1), picker.MinimumDate); Assert.AreEqual(new DateTime(2050, 12, 31), picker.MaximumDate); + + Assert.AreEqual(DateTime.Today, page.view0.Date.Value.Date); } } } From 4c09dd7f60a041dd63e68ca1508f0731ae4ee0bc Mon Sep 17 00:00:00 2001 From: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com> Date: Mon, 24 Mar 2025 00:56:25 +0100 Subject: [PATCH 16/34] [iOS] Changing carousel view orientation with disabled loop - fix (#28545) * [iOS] Changing carousel view orientation with disabled loop - fix * Added snapshots --- .../Items/iOS/CarouselViewController.cs | 14 +++++++++ .../PublicAPI/net-ios/PublicAPI.Unshipped.txt | 1 + .../net-maccatalyst/PublicAPI.Unshipped.txt | 1 + .../CarouselViewItemShouldScaleProperly.png | Bin 0 -> 15478 bytes .../TestCases.HostApp/Issues/Issue28523.xaml | 28 ++++++++++++++++++ .../Issues/Issue28523.xaml.cs | 11 +++++++ .../Tests/Issues/Issue28523.cs | 25 ++++++++++++++++ .../CarouselViewItemShouldScaleProperly.png | Bin 0 -> 15528 bytes 8 files changed, 80 insertions(+) create mode 100644 src/Controls/tests/TestCases.Android.Tests/snapshots/android/CarouselViewItemShouldScaleProperly.png create mode 100644 src/Controls/tests/TestCases.HostApp/Issues/Issue28523.xaml create mode 100644 src/Controls/tests/TestCases.HostApp/Issues/Issue28523.xaml.cs create mode 100644 src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28523.cs create mode 100644 src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CarouselViewItemShouldScaleProperly.png diff --git a/src/Controls/src/Core/Handlers/Items/iOS/CarouselViewController.cs b/src/Controls/src/Core/Handlers/Items/iOS/CarouselViewController.cs index ca07824e4a11..afa9ea62f139 100644 --- a/src/Controls/src/Core/Handlers/Items/iOS/CarouselViewController.cs +++ b/src/Controls/src/Core/Handlers/Items/iOS/CarouselViewController.cs @@ -32,6 +32,20 @@ public class CarouselViewController : ItemsViewController bool _isRotating; + public override void TraitCollectionDidChange(UITraitCollection previousTraitCollection) + { + if (previousTraitCollection.VerticalSizeClass == TraitCollection.VerticalSizeClass) + { + return; + } + + if (ItemsView?.Loop == false || _carouselViewLoopManager is null) + { + CollectionView.ReloadData(); + InitialPositionSet = false; + } + } + public CarouselViewController(CarouselView itemsView, ItemsViewLayout layout) : base(itemsView, layout) { CollectionView.AllowsSelection = false; diff --git a/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt index e33dcb76f5a2..9089f402c400 100644 --- a/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt +++ b/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt @@ -71,6 +71,7 @@ Microsoft.Maui.Controls.HybridWebView.SetInvokeJavaScriptTarget(T! target) -> ~Microsoft.Maui.Controls.Xaml.IXamlTypeResolver.Resolve(string qualifiedTypeName, System.IServiceProvider serviceProvider = null, bool expandToExtension = true) -> System.Type ~Microsoft.Maui.Controls.Xaml.RequireServiceAttribute.RequireServiceAttribute(System.Type[] serviceTypes) -> void ~Microsoft.Maui.Controls.Xaml.RequireServiceAttribute.ServiceTypes.get -> System.Type[] +~override Microsoft.Maui.Controls.Handlers.Items.CarouselViewController.TraitCollectionDidChange(UIKit.UITraitCollection previousTraitCollection) -> void ~override Microsoft.Maui.Controls.Handlers.Items2.CarouselViewController2.CreateDelegator() -> UIKit.UICollectionViewDelegateFlowLayout ~override Microsoft.Maui.Controls.Handlers.Items2.CarouselViewController2.CreateItemsViewSource() -> Microsoft.Maui.Controls.Handlers.Items.IItemsViewSource ~override Microsoft.Maui.Controls.Handlers.Items2.CarouselViewController2.DetermineCellReuseId(Foundation.NSIndexPath indexPath) -> string diff --git a/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt index 6950a4815676..44b640bc304f 100644 --- a/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt +++ b/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt @@ -71,6 +71,7 @@ Microsoft.Maui.Controls.HybridWebView.SetInvokeJavaScriptTarget(T! target) -> ~Microsoft.Maui.Controls.Xaml.IXamlTypeResolver.Resolve(string qualifiedTypeName, System.IServiceProvider serviceProvider = null, bool expandToExtension = true) -> System.Type ~Microsoft.Maui.Controls.WebViewProcessTerminatedEventArgs.PlatformArgs.get -> Microsoft.Maui.Controls.PlatformWebViewProcessTerminatedEventArgs ~Microsoft.Maui.Controls.Xaml.RequireServiceAttribute.RequireServiceAttribute(System.Type[] serviceTypes) -> void +~override Microsoft.Maui.Controls.Handlers.Items.CarouselViewController.TraitCollectionDidChange(UIKit.UITraitCollection previousTraitCollection) -> void ~Microsoft.Maui.Controls.Xaml.RequireServiceAttribute.ServiceTypes.get -> System.Type[] ~override Microsoft.Maui.Controls.Handlers.Items2.CarouselViewController2.CreateDelegator() -> UIKit.UICollectionViewDelegateFlowLayout ~override Microsoft.Maui.Controls.Handlers.Items2.CarouselViewController2.CreateItemsViewSource() -> Microsoft.Maui.Controls.Handlers.Items.IItemsViewSource diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/CarouselViewItemShouldScaleProperly.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/CarouselViewItemShouldScaleProperly.png new file mode 100644 index 0000000000000000000000000000000000000000..daf55575bde69605b5325321f9d46e4169bed078 GIT binary patch literal 15478 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 + + + + + + + + + + + Baboon + Capuchin Monkey + Blue Monkey + Squirrel Monkey + Golden Lion Tamarin + Howler Monkey + + + + \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue28523.xaml.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue28523.xaml.cs new file mode 100644 index 000000000000..0836b66b0283 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue28523.xaml.cs @@ -0,0 +1,11 @@ +namespace Maui.Controls.Sample.Issues +{ + [Issue(IssueTracker.Github, 28523, "Different behavior on iOS and Android when Loop = False", PlatformAffected.iOS)] + public partial class Issue28523 : ContentPage + { + public Issue28523() + { + InitializeComponent(); + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28523.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28523.cs new file mode 100644 index 000000000000..0af63c3a42af --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28523.cs @@ -0,0 +1,25 @@ +#if ANDROID || IOS +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues; +public class Issue28523 : _IssuesUITest +{ + public Issue28523(TestDevice testDevice) : base(testDevice) + { + } + + public override string Issue => "Different behavior on iOS and Android when Loop = False"; + + [Test] + [Category(UITestCategories.CarouselView)] + public void CarouselViewItemShouldScaleProperly() + { + App.WaitForElement("Baboon"); + App.SetOrientationLandscape(); + App.WaitForElement("Baboon"); + VerifyScreenshot(); + } +} +#endif \ No newline at end of file diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CarouselViewItemShouldScaleProperly.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CarouselViewItemShouldScaleProperly.png new file mode 100644 index 0000000000000000000000000000000000000000..6f97047fc856bfab57204f52280608376f8f45c4 GIT binary patch literal 15528 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 Pq6R=to_kC8969q(_)yiT literal 0 HcmV?d00001 From ef98fa45a6bad8c301e72a1200a957c6cbb08484 Mon Sep 17 00:00:00 2001 From: Vignesh-SF3580 <102575140+Vignesh-SF3580@users.noreply.github.com> Date: Mon, 24 Mar 2025 05:40:57 +0530 Subject: [PATCH 17/34] Fixed ScrollView Orientation Neither issue (#27231) * Fixed - 18418 : ScrollView Orientation=Neither not working * updated ScrollViewerExtensions.cs * Disable the scroll in ios when orientation is neither. * updated ScrollViewHandler.iOS.cs * testcases updated. * Apply suggestions from code review * Apply suggestions from code review --------- Co-authored-by: Gerald Versluis --- .../Issues/Issue2680ScrollView.cs | 29 ++++++++++--- .../Tests/Issues/Issue2680ScrollView.cs | 23 +++-------- .../ScrollView/ScrollViewHandler.Windows.cs | 2 +- .../ScrollView/ScrollViewHandler.iOS.cs | 8 ++++ .../Windows/ScrollViewerExtensions.cs | 41 +++++++++++-------- .../src/Platform/iOS/ScrollViewExtensions.cs | 9 +++- 6 files changed, 70 insertions(+), 42 deletions(-) diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue2680ScrollView.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue2680ScrollView.cs index a2d374f19c8f..5ac041126626 100644 --- a/src/Controls/tests/TestCases.HostApp/Issues/Issue2680ScrollView.cs +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue2680ScrollView.cs @@ -16,6 +16,11 @@ public void ToggleButtonText() protected override void Init() { + var contentView = new ContentView + { + HeightRequest = 2000 + }; + // Initialize ui here instead of ctor var longStackLayout = new StackLayout(); @@ -24,21 +29,26 @@ protected override void Init() longStackLayout.Children.Add(toggleButton); - longStackLayout.Children.Add(new Label - { - Text = "First label", - AutomationId = FirstItemMark - }); + firstItemLabel = new Label + { + Text = "Not scrolled", + AutomationId = FirstItemMark + }; + + longStackLayout.Children.Add(firstItemLabel); Enumerable.Range(2, 50).Select(i => new Label { Text = $"Test label {i}" }) .ToList().ForEach(label => longStackLayout.Children.Add(label)); + contentView.Content = longStackLayout; + scrollView = new ScrollView { Orientation = ScrollOrientation.Neither, AutomationId = ScrollViewMark, - Content = longStackLayout + Content = contentView }; + scrollView.Scrolled += ScrollViewOnScrolled; Content = scrollView; } @@ -48,9 +58,16 @@ void ToggleButtonOnClicked(object sender, EventArgs e) scrollView.Orientation = IsScrollEnabled ? ScrollOrientation.Vertical : ScrollOrientation.Neither; } + void ScrollViewOnScrolled(object sender, ScrolledEventArgs e) + { + firstItemLabel.Text = "Scrolled"; + } + ScrollView scrollView; Button toggleButton; + Label firstItemLabel; + const string ScrollViewMark = "ScrollView"; const string FirstItemMark = "FirstItem"; const string ToggleButtonMark = "ToggleButton"; diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue2680ScrollView.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue2680ScrollView.cs index 5c64d85c88d5..e46b79e7d961 100644 --- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue2680ScrollView.cs +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue2680ScrollView.cs @@ -1,6 +1,4 @@ -#if TEST_FAILS_ON_WINDOWS && TEST_FAILS_ON_IOS && TEST_FAILS_ON_CATALYST // In iOS and Catalyst, WaitForNoElement throws a timeout exception eventhough the text is not visible on the screen by scrolling. -//In Windows, The ScrollView remains scrollable even when ScrollOrientation.Neither is set. Issue Link: https://github.com/dotnet/maui/issues/27140 -using NUnit.Framework; +using NUnit.Framework; using UITest.Appium; using UITest.Core; @@ -20,32 +18,21 @@ public Issue2680ScrollView(TestDevice testDevice) : base(testDevice) [Test] [Category(UITestCategories.ScrollView)] - [FailsOnIOSWhenRunningOnXamarinUITest] - [FailsOnMacWhenRunningOnXamarinUITest] public void Issue2680Test_ScrollDisabled() { - App.WaitForElement(ScrollViewMark); + var label = App.WaitForElement(FirstItemMark); App.ScrollDown(ScrollViewMark); - App.ScrollDown(ScrollViewMark); - - App.WaitForElement(FirstItemMark, timeout: TimeSpan.FromSeconds(5)); + Assert.That(label.GetText(), Is.EqualTo("Not scrolled")); } [Test] [Category(UITestCategories.ScrollView)] - [FailsOnIOSWhenRunningOnXamarinUITest] - [FailsOnMacWhenRunningOnXamarinUITest] - [FailsOnWindowsWhenRunningOnXamarinUITest] public void Issue2680Test_ScrollEnabled() { - App.WaitForElement(ToggleButtonMark); + var label = App.WaitForElement(FirstItemMark); App.Tap(ToggleButtonMark); - App.ScrollDown(ScrollViewMark); - App.ScrollDown(ScrollViewMark); - - App.WaitForNoElement(FirstItemMark, timeout: TimeSpan.FromSeconds(5)); + Assert.That(label.GetText(), Is.EqualTo("Scrolled")); } } } -#endif \ No newline at end of file diff --git a/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Windows.cs b/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Windows.cs index 0309f84bb32e..1a6752f2e4a0 100644 --- a/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Windows.cs +++ b/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Windows.cs @@ -62,7 +62,7 @@ public static void MapHorizontalScrollBarVisibility(IScrollViewHandler handler, public static void MapVerticalScrollBarVisibility(IScrollViewHandler handler, IScrollView scrollView) { - handler.PlatformView.VerticalScrollBarVisibility = scrollView.VerticalScrollBarVisibility.ToWindowsScrollBarVisibility(); + handler.PlatformView?.UpdateScrollBarVisibility(scrollView.Orientation, scrollView.VerticalScrollBarVisibility); } public static void MapOrientation(IScrollViewHandler handler, IScrollView scrollView) diff --git a/src/Core/src/Handlers/ScrollView/ScrollViewHandler.iOS.cs b/src/Core/src/Handlers/ScrollView/ScrollViewHandler.iOS.cs index 7c5883653223..c8e7d6620fba 100644 --- a/src/Core/src/Handlers/ScrollView/ScrollViewHandler.iOS.cs +++ b/src/Core/src/Handlers/ScrollView/ScrollViewHandler.iOS.cs @@ -83,6 +83,14 @@ public static void MapOrientation(IScrollViewHandler handler, IScrollView scroll return; } + if (scrollView.Orientation == ScrollOrientation.Neither) + { + platformView.ScrollEnabled = false; + } + else + { + platformView.ScrollEnabled = true; + } platformView.InvalidateMeasure(scrollView); } diff --git a/src/Core/src/Platform/Windows/ScrollViewerExtensions.cs b/src/Core/src/Platform/Windows/ScrollViewerExtensions.cs index d04e1dedd633..81350563f0bf 100644 --- a/src/Core/src/Platform/Windows/ScrollViewerExtensions.cs +++ b/src/Core/src/Platform/Windows/ScrollViewerExtensions.cs @@ -19,35 +19,44 @@ public static WScrollBarVisibility ToWindowsScrollBarVisibility(this ScrollBarVi public static void UpdateScrollBarVisibility(this ScrollViewer scrollViewer, ScrollOrientation orientation, ScrollBarVisibility horizontalScrollBarVisibility) { + if (orientation == ScrollOrientation.Neither) + { + scrollViewer.HorizontalScrollBarVisibility = scrollViewer.VerticalScrollBarVisibility = WScrollBarVisibility.Disabled; + return; + } + if (horizontalScrollBarVisibility == ScrollBarVisibility.Default) { // If the user has not explicitly set a horizontal scroll bar visibility, then the orientation will // determine what the horizontal scroll bar does - scrollViewer.HorizontalScrollBarVisibility = orientation switch { ScrollOrientation.Horizontal or ScrollOrientation.Both => WScrollBarVisibility.Auto, _ => WScrollBarVisibility.Disabled, }; - return; + scrollViewer.VerticalScrollBarVisibility = orientation switch + { + ScrollOrientation.Vertical or ScrollOrientation.Both => WScrollBarVisibility.Auto, + _ => WScrollBarVisibility.Disabled, + }; } - - // If the user _has_ set a horizontal scroll bar visibility preference, then convert that preference to the native equivalent - // if the orientation allows for it - - scrollViewer.HorizontalScrollBarVisibility = orientation switch + else { - ScrollOrientation.Horizontal or ScrollOrientation.Both => horizontalScrollBarVisibility.ToWindowsScrollBarVisibility(), - _ => WScrollBarVisibility.Disabled, - }; - - // TODO ezhart 2021-07-08 RE: the note below - do we actually need to be accounting for Neither in the measurement code? - // Could we just disable the scroll bars entirely? - // Accounting for Neither in the xplat measurement code is a leftover from Forms, it may be easier to do that on the native side here. + // If the user _has_ set a horizontal scroll bar visibility preference, then convert that preference to the native equivalent + // if the orientation allows for it + scrollViewer.HorizontalScrollBarVisibility = orientation switch + { + ScrollOrientation.Horizontal or ScrollOrientation.Both => horizontalScrollBarVisibility.ToWindowsScrollBarVisibility(), + _ => WScrollBarVisibility.Disabled, + }; - // Note that the Orientation setting of "Neither" is covered by the measurement code (the size of the content is limited - // so that no scrolling is possible) and the xplat scrolling code (the ScrollTo methods are disabled when Orientation=Neither) + scrollViewer.VerticalScrollBarVisibility = orientation switch + { + ScrollOrientation.Vertical or ScrollOrientation.Both => horizontalScrollBarVisibility.ToWindowsScrollBarVisibility(), + _ => WScrollBarVisibility.Disabled, + }; + } } public static void UpdateContent(this ScrollViewer scrollViewer, IView? content, IMauiContext context) diff --git a/src/Core/src/Platform/iOS/ScrollViewExtensions.cs b/src/Core/src/Platform/iOS/ScrollViewExtensions.cs index 98a7a9ba4686..02c65a3d10e6 100644 --- a/src/Core/src/Platform/iOS/ScrollViewExtensions.cs +++ b/src/Core/src/Platform/iOS/ScrollViewExtensions.cs @@ -52,7 +52,14 @@ public static void UpdateContentSize(this UIScrollView scrollView, Size contentS public static void UpdateIsEnabled(this UIScrollView nativeScrollView, IScrollView scrollView) { - nativeScrollView.ScrollEnabled = scrollView.IsEnabled; + if (scrollView.Orientation == ScrollOrientation.Neither) + { + nativeScrollView.ScrollEnabled = false; + } + else + { + nativeScrollView.ScrollEnabled = scrollView.IsEnabled; + } } } } From 055d9ecae1e9c0d62d8c071c89a4e8ec4b3ac2b4 Mon Sep 17 00:00:00 2001 From: SuthiYuvaraj <92777079+SuthiYuvaraj@users.noreply.github.com> Date: Mon, 24 Mar 2025 18:30:45 +0530 Subject: [PATCH 18/34] Fix HideSoftInputOnTapped Not Working Net9 (#28534) * fix for 26792 * Update HideSoftInputOnTappedChangedManager.Platform.cs * Testcases added * Comments updated * Condition modification --- ...SoftInputOnTappedChangedManager.Android.cs | 2 +- ...oftInputOnTappedChangedManager.Platform.cs | 2 +- .../HideSoftInputOnTappedChangedManager.cs | 2 +- .../TestCases.HostApp/Issues/Issue26792.cs | 40 +++++++++++++++++++ .../Tests/Issues/Issue26792.cs | 29 ++++++++++++++ 5 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 src/Controls/tests/TestCases.HostApp/Issues/Issue26792.cs create mode 100644 src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26792.cs diff --git a/src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.Android.cs b/src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.Android.cs index 3dc75e168a60..3501898dcfcf 100644 --- a/src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.Android.cs +++ b/src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.Android.cs @@ -20,7 +20,7 @@ void OnWindowDispatchedTouch(object? sender, MotionEvent? e) foreach (var page in _contentPages) { - if (page.HasNavigatedTo && + if ((page.HasNavigatedTo || page.Parent is Window) && page.HideSoftInputOnTapped && page.Handler is IPlatformViewHandler pvh && pvh.MauiContext?.Context is not null) diff --git a/src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.Platform.cs b/src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.Platform.cs index b5ed8c838a64..45b49052c65b 100644 --- a/src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.Platform.cs +++ b/src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.Platform.cs @@ -14,7 +14,7 @@ partial class HideSoftInputOnTappedChangedManager internal void UpdatePage(ContentPage page) { - if (page.HideSoftInputOnTapped && page.HasNavigatedTo) + if (page.HideSoftInputOnTapped && (page.HasNavigatedTo || page.Parent is Window)) { if (!_contentPages.Contains(page)) { diff --git a/src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.cs b/src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.cs index 1f369165f5f8..17f1c41e75d7 100644 --- a/src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.cs +++ b/src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.cs @@ -13,7 +13,7 @@ bool FeatureEnabled { foreach (var page in _contentPages) { - if (page.HideSoftInputOnTapped && page.HasNavigatedTo) + if (page.HideSoftInputOnTapped && (page.HasNavigatedTo || page.Parent is Window)) return true; } return false; diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue26792.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue26792.cs new file mode 100644 index 000000000000..cb4045de9468 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue26792.cs @@ -0,0 +1,40 @@ +namespace Maui.Controls.Sample.Issues; + +[Issue(IssueTracker.Github, 26792, "HideSoftInputOnTapped Not Working", PlatformAffected.Android)] +public class Issue26792 : ContentPage +{ + + VerticalStackLayout stackLayout; + Button _button; + + Entry _entry; + public Issue26792() + { + this.HideSoftInputOnTapped = true; + stackLayout = new VerticalStackLayout + { + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + AutomationId = "Issue26792StackLayout", + }; + _button = new Button + { + Text = "Click Me", + AutomationId = "Issue26792Button", + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + }; + _entry = new Entry + { + Placeholder = "Enter text", + AutomationId = "Issue26792Entry", + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + }; + + stackLayout.Children.Add(_button); + stackLayout.Children.Add(_entry); + Content = stackLayout; + } +} + diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26792.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26792.cs new file mode 100644 index 000000000000..88bd8968731c --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26792.cs @@ -0,0 +1,29 @@ +#if TEST_FAILS_ON_CATALYST && TEST_FAILS_ON_WINDOWS //As SoftKeyboard is not supported +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues; + +public class Issue26792 : _IssuesUITest +{ + public Issue26792(TestDevice testDevice) : base(testDevice) + { + } + + public override string Issue => "HideSoftInputOnTapped Not Working"; + + [Test] + [Category(UITestCategories.Page)] + public void SoftInputShouldHiddenOnTap() + { + App.WaitForElement("Issue26792Entry"); + App.Tap("Issue26792Entry"); + App.WaitForElement("Issue26792Button"); + App.Tap("Issue26792Button"); + App.WaitForElement("Issue26792Entry"); + Assert.That(App.IsKeyboardShown(), Is.False); + + } +} +#endif From 99f3cc5c2c92d8cfed117ee74f62442d8bcb1e7e Mon Sep 17 00:00:00 2001 From: Anandhan Rajagopal <97146406+anandhan-rajagopal@users.noreply.github.com> Date: Wed, 26 Mar 2025 19:15:55 +0530 Subject: [PATCH 19/34] [Testing] Migration of Compatibility.Core platform-specific unit tests into device tests - 3 (#28103) * Added the CornerRadius and IsEnabled property for DeviceTest * IsEnabled property for Device tests * Addressed the feedbacks * Update BoxViewTests.cs * modified code changes * resolved windows build error * Update RadioButtonTests.Windows.cs * Update CheckBoxTests.iOS.cs * removed unwanted namespace * Update CheckBoxTests.cs * Update SwipeViewTests.Android.cs * Update BoxViewTests.Android.cs * Resolved build error in windows * Update RadioButtonTests.Windows.cs * Added the CornerRadius and IsEnabled property for DeviceTest * IsEnabled property for Device tests * Addressed the feedbacks * Update BoxViewTests.cs * modified code changes * resolved windows build error * Update RadioButtonTests.Windows.cs * Update CheckBoxTests.iOS.cs * removed unwanted namespace * Update CheckBoxTests.cs * Update SwipeViewTests.Android.cs * Resolved build error in windows * Update RadioButtonTests.Windows.cs * Update CheckBoxTests.Android.cs * Resolved conflict errors * Update BoxViewTests.Android.cs --------- Co-authored-by: nivetha-nagalingam --- .../Elements/BoxView/BoxViewTests.Android.cs | 21 +++++++++ .../Elements/BoxView/BoxViewTests.Windows.cs | 23 ++++++++++ .../Elements/BoxView/BoxViewTests.cs | 17 ++++++- .../Elements/Button/ButtonTests.iOS.cs | 20 ++++++++ .../CheckBox/CheckBoxTests.Android.cs | 16 +++++++ .../CheckBox/CheckBoxTests.Windows.cs | 17 +++++++ .../Elements/CheckBox/CheckBoxTests.iOS.cs | 17 +++++++ .../Elements/Editor/EditorTests.Android.cs | 20 ++++++++ .../Elements/Label/LabelTests.Android.cs | 20 ++++++++ .../RadioButton/RadioButtonTests.Windows.cs | 46 ++++++++++++++++++- .../SearchBar/SearchBarTests.Android.cs | 20 ++++++++ .../SearchBar/SearchBarTests.Windows.cs | 22 +++++++++ .../SwipeView/SwipeViewTests.Android.cs | 19 ++++++++ 13 files changed, 275 insertions(+), 3 deletions(-) diff --git a/src/Controls/tests/DeviceTests/Elements/BoxView/BoxViewTests.Android.cs b/src/Controls/tests/DeviceTests/Elements/BoxView/BoxViewTests.Android.cs index 0d84d49eb8e3..1add2de04889 100644 --- a/src/Controls/tests/DeviceTests/Elements/BoxView/BoxViewTests.Android.cs +++ b/src/Controls/tests/DeviceTests/Elements/BoxView/BoxViewTests.Android.cs @@ -2,11 +2,13 @@ using System.ComponentModel; using System.Threading.Tasks; using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Handlers; using Microsoft.Maui.Graphics; using Microsoft.Maui.Handlers; using Microsoft.Maui.Platform; using Xunit; + namespace Microsoft.Maui.DeviceTests { public partial class BoxViewTests @@ -96,6 +98,25 @@ public async Task RotationConsistent() var platformRotation = await InvokeOnMainThreadAsync(() => platformBoxView.Rotation); Assert.Equal(expected, platformRotation); } + + [Fact] + [Description("The IsEnabled property of a BoxView should match with native IsEnabled")] + public async Task VerifyBoxViewIsEnabledProperty() + { + var boxView = new BoxView + { + IsEnabled = false + }; + var expectedValue = boxView.IsEnabled; + + var handler = await CreateHandlerAsync(boxView); + var nativeView = GetNativeBoxView(handler); + await InvokeOnMainThreadAsync(() => + { + var isEnabled = nativeView.Enabled; + Assert.Equal(expectedValue, isEnabled); + }); + } Task GetPlatformIsVisible(ShapeViewHandler boxViewViewHandler) { diff --git a/src/Controls/tests/DeviceTests/Elements/BoxView/BoxViewTests.Windows.cs b/src/Controls/tests/DeviceTests/Elements/BoxView/BoxViewTests.Windows.cs index 88e0735833b1..da087c8ae9d7 100644 --- a/src/Controls/tests/DeviceTests/Elements/BoxView/BoxViewTests.Windows.cs +++ b/src/Controls/tests/DeviceTests/Elements/BoxView/BoxViewTests.Windows.cs @@ -3,6 +3,10 @@ using Microsoft.Maui.Graphics.Platform; using Microsoft.Maui.Graphics.Win2D; using Microsoft.Maui.Handlers; +using Xunit; +using System.ComponentModel; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Handlers; namespace Microsoft.Maui.DeviceTests { @@ -20,6 +24,25 @@ Task GetPlatformOpacity(ShapeViewHandler handler) }); } + [Fact] + [Description("The IsEnabled property of a BoxView should match with native IsEnabled")] + public async Task BoxViewIsEnabled() + { + var boxView = new BoxView + { + IsEnabled = false + }; + var expectedValue = boxView.IsEnabled; + + var handler = await CreateHandlerAsync(boxView); + var nativeView = GetNativeBoxView(handler); + await InvokeOnMainThreadAsync(() => + { + var isEnabled = nativeView.IsEnabled; + Assert.Equal(expectedValue, isEnabled); + }); + } + Task GetPlatformIsVisible(ShapeViewHandler boxViewHandler) { return InvokeOnMainThreadAsync(() => diff --git a/src/Controls/tests/DeviceTests/Elements/BoxView/BoxViewTests.cs b/src/Controls/tests/DeviceTests/Elements/BoxView/BoxViewTests.cs index cf574048faf1..5f271391ad18 100644 --- a/src/Controls/tests/DeviceTests/Elements/BoxView/BoxViewTests.cs +++ b/src/Controls/tests/DeviceTests/Elements/BoxView/BoxViewTests.cs @@ -4,9 +4,9 @@ using Microsoft.Maui.Controls; using Microsoft.Maui.Graphics; using Microsoft.Maui.Handlers; +using Microsoft.Maui.Controls.Handlers; using Microsoft.Maui.Hosting; using Xunit; -using Microsoft.Maui.Controls.Handlers; namespace Microsoft.Maui.DeviceTests { @@ -47,6 +47,21 @@ public async Task BoxViewBackgroundColorConsistent() await ValidateHasColor(boxView, expected, typeof(ShapeViewHandler)); } + [Fact] + [Description("The Background of a BoxView should match with native Background")] + public async Task BoxViewBackgroundConsistent() + { + var boxView = new BoxView + { + HeightRequest = 100, + WidthRequest = 200, + Background = Brush.Red + }; + var expected = (boxView.Background as SolidColorBrush)?.Color; + + await ValidateHasColor(boxView, expected, typeof(BoxViewHandler)); + } + [Fact] [Description("The Opacity property of a BoxView should match with native Opacity")] public async Task VerifyBoxViewOpacityProperty() diff --git a/src/Controls/tests/DeviceTests/Elements/Button/ButtonTests.iOS.cs b/src/Controls/tests/DeviceTests/Elements/Button/ButtonTests.iOS.cs index 0b1f27eef54b..b16315e26605 100644 --- a/src/Controls/tests/DeviceTests/Elements/Button/ButtonTests.iOS.cs +++ b/src/Controls/tests/DeviceTests/Elements/Button/ButtonTests.iOS.cs @@ -1,5 +1,6 @@ #nullable enable using System; +using System.ComponentModel; using System.Threading.Tasks; using Microsoft.Maui.Controls; using Microsoft.Maui.Graphics; @@ -87,5 +88,24 @@ await InvokeOnMainThreadAsync(async () => Assert.True(button.Width < gridWidth, $"Button shouldn't occupy entire layout width. Expected: {gridWidth}<, was {button.Width}"); Assert.True(button.Height < gridHeight, $"Button shouldn't occupy entire layout height. Expected: {gridHeight}<, was {button.Height}"); } + + [Fact] + [Description("The CornerRadius of a Button should match with native CornerRadius")] + public async Task ButtonCornerRadius() + { + var button = new Button + { + CornerRadius = 15, + }; + var expectedValue = button.CornerRadius; + + var handler = await CreateHandlerAsync(button); + var nativeView = GetPlatformButton(handler); + await InvokeOnMainThreadAsync(() => + { + var platformCornerRadius = nativeView.Layer.CornerRadius; + Assert.Equal(expectedValue, platformCornerRadius); + }); + } } } diff --git a/src/Controls/tests/DeviceTests/Elements/CheckBox/CheckBoxTests.Android.cs b/src/Controls/tests/DeviceTests/Elements/CheckBox/CheckBoxTests.Android.cs index 7403625f6268..e31c3eab2fa5 100644 --- a/src/Controls/tests/DeviceTests/Elements/CheckBox/CheckBoxTests.Android.cs +++ b/src/Controls/tests/DeviceTests/Elements/CheckBox/CheckBoxTests.Android.cs @@ -98,6 +98,22 @@ public async Task RotationConsistent() Assert.Equal(expected, platformRotation); } + [Fact("The IsEnabled of a CheckBox should match with native IsEnabled")] + public async Task CheckBoxIsEnabled() + { + var checkBox = new CheckBox(); + checkBox.IsEnabled = false; + var expectedValue = checkBox.IsEnabled; + + var handler = await CreateHandlerAsync(checkBox); + var nativeView = GetNativeCheckBox(handler); + await InvokeOnMainThreadAsync(() => + { + var isEnabled = nativeView.Enabled; + Assert.Equal(expectedValue, isEnabled); + }); + } + Task GetPlatformIsVisible(CheckBoxHandler checkBoxHandler) { return InvokeOnMainThreadAsync(() => diff --git a/src/Controls/tests/DeviceTests/Elements/CheckBox/CheckBoxTests.Windows.cs b/src/Controls/tests/DeviceTests/Elements/CheckBox/CheckBoxTests.Windows.cs index b37682a406a4..da7a3b43ae4f 100644 --- a/src/Controls/tests/DeviceTests/Elements/CheckBox/CheckBoxTests.Windows.cs +++ b/src/Controls/tests/DeviceTests/Elements/CheckBox/CheckBoxTests.Windows.cs @@ -3,6 +3,7 @@ using Microsoft.Maui.Graphics; using Microsoft.Maui.Handlers; using Microsoft.UI.Xaml.Controls; +using Xunit; namespace Microsoft.Maui.DeviceTests { @@ -19,6 +20,22 @@ Task GetPlatformOpacity(CheckBoxHandler checkBoxHandler) return (float)nativeView.Opacity; }); } + + [Fact("The IsEnabled of a CheckBox should match with native IsEnabled")] + public async Task CheckBoxIsEnabled() + { + var checkBox = new Microsoft.Maui.Controls.CheckBox(); + checkBox.IsEnabled = false; + var expectedValue = checkBox.IsEnabled; + + var handler = await CreateHandlerAsync(checkBox); + var nativeView = GetNativeCheckBox(handler); + await InvokeOnMainThreadAsync(() => + { + var isEnabled = nativeView.IsEnabled; + Assert.Equal(expectedValue, isEnabled); + }); + } Task GetPlatformIsVisible(CheckBoxHandler checkBoxHandler) { diff --git a/src/Controls/tests/DeviceTests/Elements/CheckBox/CheckBoxTests.iOS.cs b/src/Controls/tests/DeviceTests/Elements/CheckBox/CheckBoxTests.iOS.cs index c907dcf606ff..c1cbbfe2a5a5 100644 --- a/src/Controls/tests/DeviceTests/Elements/CheckBox/CheckBoxTests.iOS.cs +++ b/src/Controls/tests/DeviceTests/Elements/CheckBox/CheckBoxTests.iOS.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using Microsoft.Maui.Graphics; +using Microsoft.Maui.Controls; using Microsoft.Maui.Handlers; using Microsoft.Maui.Platform; using Xunit; @@ -21,6 +22,22 @@ Task GetPlatformOpacity(CheckBoxHandler checkBoxHandler) return (float)nativeView.Alpha; }); } + + [Fact("The IsEnabled of a CheckBox should match with native IsEnabled")] + public async Task CheckBoxIsEnabled() + { + var checkBox = new CheckBox(); + checkBox.IsEnabled = false; + var expectedValue = checkBox.IsEnabled; + + var handler = await CreateHandlerAsync(checkBox); + var nativeView = GetNativeCheckBox(handler); + await InvokeOnMainThreadAsync(() => + { + var isEnabled = nativeView.Enabled; + Assert.Equal(expectedValue, isEnabled); + }); + } Task GetPlatformIsVisible(CheckBoxHandler checkBoxHandler) { diff --git a/src/Controls/tests/DeviceTests/Elements/Editor/EditorTests.Android.cs b/src/Controls/tests/DeviceTests/Elements/Editor/EditorTests.Android.cs index 00b457c78179..0df2cb8c285a 100644 --- a/src/Controls/tests/DeviceTests/Elements/Editor/EditorTests.Android.cs +++ b/src/Controls/tests/DeviceTests/Elements/Editor/EditorTests.Android.cs @@ -150,5 +150,25 @@ public async Task RotationConsistent() var platformRotation = await InvokeOnMainThreadAsync(() => PlatformEditor.Rotation); Assert.Equal(expected, platformRotation); } + + [Fact] + [Description("The IsEnabled property of a Editor should match with native IsEnabled")] + public async Task VerifyEditorIsEnabledProperty() + { + var editor = new Editor + { + IsEnabled = false + }; + var expectedValue = editor.IsEnabled; + + var handler = await CreateHandlerAsync(editor); + var nativeView = GetPlatformControl(handler); + await InvokeOnMainThreadAsync(() => + { + var isEnabled = nativeView.Enabled; + + Assert.Equal(expectedValue, isEnabled); + }); + } } } diff --git a/src/Controls/tests/DeviceTests/Elements/Label/LabelTests.Android.cs b/src/Controls/tests/DeviceTests/Elements/Label/LabelTests.Android.cs index 03e1aadb80aa..e584366a7174 100644 --- a/src/Controls/tests/DeviceTests/Elements/Label/LabelTests.Android.cs +++ b/src/Controls/tests/DeviceTests/Elements/Label/LabelTests.Android.cs @@ -162,6 +162,26 @@ public async Task RotationConsistent() var platformRotation = await InvokeOnMainThreadAsync(() => platformLabel.Rotation); Assert.Equal(expected, platformRotation); } + + [Fact] + [Description("The IsEnabled property of a Label should match with native IsEnabled")] + public async Task VerifyLabelIsEnabledProperty() + { + var label = new Label + { + IsEnabled = false + }; + var expectedValue = label.IsEnabled; + + var handler = await CreateHandlerAsync(label); + var nativeView = GetPlatformLabel(handler); + await InvokeOnMainThreadAsync(() => + { + var isEnabled = nativeView.Enabled; + Assert.Equal(expectedValue, isEnabled); + }); + } + TextView GetPlatformLabel(LabelHandler labelHandler) => labelHandler.PlatformView; diff --git a/src/Controls/tests/DeviceTests/Elements/RadioButton/RadioButtonTests.Windows.cs b/src/Controls/tests/DeviceTests/Elements/RadioButton/RadioButtonTests.Windows.cs index 30853568b48e..c4097d6720aa 100644 --- a/src/Controls/tests/DeviceTests/Elements/RadioButton/RadioButtonTests.Windows.cs +++ b/src/Controls/tests/DeviceTests/Elements/RadioButton/RadioButtonTests.Windows.cs @@ -1,4 +1,5 @@ using System.ComponentModel; +using Xunit; using System.Threading.Tasks; using Microsoft.Maui.Controls; using Microsoft.Maui.Handlers; @@ -27,12 +28,54 @@ public async Task VerifyRadioButtonOpacityProperty() var handler = await CreateHandlerAsync(radioButton); var nativeView = GetNativeRadioButton(handler); await InvokeOnMainThreadAsync(() => - { + { var nativeOpacityValue = (float)nativeView.Opacity; Assert.Equal(expectedValue, nativeOpacityValue); }); } + [Fact] + [Description("The CornerRadius of a RadioButton should match with native CornerRadius")] + public async Task RadioButtonCornerRadius() + { + var radioButton = new RadioButton(); + radioButton.CornerRadius = 15; + var expectedValue = radioButton.CornerRadius; + + var handler = await CreateHandlerAsync(radioButton); + var nativeView = GetNativeRadioButton(handler); + await InvokeOnMainThreadAsync(() => + { + var cornerRadiusTopLeft = (float)nativeView.CornerRadius.TopLeft; + var cornerRadiusTopRight = (float)nativeView.CornerRadius.TopRight; + var cornerRadiusBottomLeft = (float)nativeView.CornerRadius.BottomLeft; + var cornerRadiusBottomRight = (float)nativeView.CornerRadius.BottomRight; + Assert.Equal(expectedValue, cornerRadiusTopLeft); + Assert.Equal(expectedValue, cornerRadiusTopRight); + Assert.Equal(expectedValue, cornerRadiusBottomLeft); + Assert.Equal(expectedValue, cornerRadiusBottomRight); + }); + } + + [Fact] + [Description("The IsEnabled of a RadioButton should match with native IsEnabled")] + public async Task VerifyRadioButtonIsEnabledProperty() + { + var radioButton = new RadioButton + { + IsEnabled = false + }; + var expectedValue = radioButton.IsEnabled; + + var handler = await CreateHandlerAsync(radioButton); + var nativeView = GetNativeRadioButton(handler); + await InvokeOnMainThreadAsync(() => + { + var isEnabled = nativeView.IsEnabled; + Assert.Equal(expectedValue, isEnabled); + }); + } + [Fact] [Description("The IsVisible property of a RadioButton should match with native IsVisible")] public async Task VerifyRadioButtonIsVisibleProperty() @@ -50,4 +93,3 @@ await InvokeOnMainThreadAsync(() => }); } } -} diff --git a/src/Controls/tests/DeviceTests/Elements/SearchBar/SearchBarTests.Android.cs b/src/Controls/tests/DeviceTests/Elements/SearchBar/SearchBarTests.Android.cs index 335b55cebb19..8d573064ac4b 100644 --- a/src/Controls/tests/DeviceTests/Elements/SearchBar/SearchBarTests.Android.cs +++ b/src/Controls/tests/DeviceTests/Elements/SearchBar/SearchBarTests.Android.cs @@ -117,6 +117,26 @@ public async Task RotationConsistent() Assert.Equal(expected, platformRotation); } + [Fact] + [Description("The IsEnabled of a SearchBar should match with native IsEnabled")] + public async Task VerifySearchBarIsEnabledProperty() + { + var searchBar = new SearchBar + { + IsEnabled = false + }; + var expectedValue = searchBar.IsEnabled; + + var handler = await CreateHandlerAsync(searchBar); + var nativeView = GetPlatformControl(handler); + await InvokeOnMainThreadAsync(() => + { + var isEnabled = nativeView.Enabled; + + Assert.Equal(expectedValue, isEnabled); + }); + } + Task GetPlatformIsVisible(SearchBarHandler searchBarHandler) { return InvokeOnMainThreadAsync(() => diff --git a/src/Controls/tests/DeviceTests/Elements/SearchBar/SearchBarTests.Windows.cs b/src/Controls/tests/DeviceTests/Elements/SearchBar/SearchBarTests.Windows.cs index 30a2ed3c6d6a..3fbf5f0cdfdf 100644 --- a/src/Controls/tests/DeviceTests/Elements/SearchBar/SearchBarTests.Windows.cs +++ b/src/Controls/tests/DeviceTests/Elements/SearchBar/SearchBarTests.Windows.cs @@ -1,8 +1,11 @@ #nullable enable +using System.ComponentModel; using System.Threading.Tasks; +using Microsoft.Maui.Controls; using Microsoft.Maui.Handlers; using Microsoft.Maui.Platform; using Microsoft.UI.Xaml.Controls; +using Xunit; namespace Microsoft.Maui.DeviceTests { @@ -52,6 +55,25 @@ Task GetPlatformOpacity(SearchBarHandler searchBarHandler) return (float)nativeView.Opacity; }); } + + [Fact] + [Description("The IsEnabled of a SearchBar should match with native IsEnabled")] + public async Task VerifySearchBarIsEnabledProperty() + { + var searchBar = new SearchBar + { + IsEnabled = false + }; + var expectedValue = searchBar.IsEnabled; + + var handler = await CreateHandlerAsync(searchBar); + var nativeView = GetPlatformControl(handler); + await InvokeOnMainThreadAsync(() => + { + var isEnabled = nativeView.IsEnabled; + Assert.Equal(expectedValue, isEnabled); + }); + } Task GetPlatformIsVisible(SearchBarHandler searchBarHandler) { diff --git a/src/Controls/tests/DeviceTests/Elements/SwipeView/SwipeViewTests.Android.cs b/src/Controls/tests/DeviceTests/Elements/SwipeView/SwipeViewTests.Android.cs index 37ed82a30149..da925a7dfb15 100644 --- a/src/Controls/tests/DeviceTests/Elements/SwipeView/SwipeViewTests.Android.cs +++ b/src/Controls/tests/DeviceTests/Elements/SwipeView/SwipeViewTests.Android.cs @@ -189,5 +189,24 @@ await InvokeOnMainThreadAsync(() => Assert.Equal(expectedValue, isVisible); }); } + + [Fact] + [Description("The IsEnabled of a SwipeView should match with native IsEnabled")] + public async Task VerifySwipeViewIsEnabledProperty() + { + var swipeView = new SwipeView + { + IsEnabled = false + }; + var expectedValue = swipeView.IsEnabled; + + var handler = await CreateHandlerAsync(swipeView); + var nativeView = GetPlatformControl(handler); + await InvokeOnMainThreadAsync(() => + { + var isEnabled = nativeView.Enabled; + Assert.Equal(expectedValue, isEnabled); + }); + } } } \ No newline at end of file From d0c2ac6bf645339b74b4e71cd7aad7690c49072f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Thu, 27 Mar 2025 19:36:09 +0100 Subject: [PATCH 20/34] Fix mistake in RadioButtonTests.Windows.cs --- .../Elements/RadioButton/RadioButtonTests.Windows.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Controls/tests/DeviceTests/Elements/RadioButton/RadioButtonTests.Windows.cs b/src/Controls/tests/DeviceTests/Elements/RadioButton/RadioButtonTests.Windows.cs index c4097d6720aa..84e80f647bcd 100644 --- a/src/Controls/tests/DeviceTests/Elements/RadioButton/RadioButtonTests.Windows.cs +++ b/src/Controls/tests/DeviceTests/Elements/RadioButton/RadioButtonTests.Windows.cs @@ -3,7 +3,6 @@ using System.Threading.Tasks; using Microsoft.Maui.Controls; using Microsoft.Maui.Handlers; -using Xunit; namespace Microsoft.Maui.DeviceTests { @@ -77,7 +76,7 @@ await InvokeOnMainThreadAsync(() => } [Fact] - [Description("The IsVisible property of a RadioButton should match with native IsVisible")] + [Description("The IsVisible property of a RadioButton should match with native IsVisible")] public async Task VerifyRadioButtonIsVisibleProperty() { var radioButton = new RadioButton(); @@ -90,6 +89,7 @@ await InvokeOnMainThreadAsync(() => { var isVisible = nativeView.Visibility == Microsoft.UI.Xaml.Visibility.Visible; Assert.Equal(expectedValue, isVisible); - }); + }); } } +} \ No newline at end of file From a9108aa691ec2ecd527bbe521e60b570db5d6ee2 Mon Sep 17 00:00:00 2001 From: NirmalKumarYuvaraj <97871636+NirmalKumarYuvaraj@users.noreply.github.com> Date: Fri, 28 Mar 2025 21:28:41 +0530 Subject: [PATCH 21/34] [Windows] Flyout Menu Icon disappears from Window Title Bar after Navigation (#28240) * Fixed drawer toggle button visiblity * Update ToolbarExtensions.cs * added test cases * added shell test cases * Update NavigationPageToolbar.cs --- .../NavigationPage/NavigationPageToolbar.cs | 6 +- .../Windows/Extensions/ToolbarExtensions.cs | 6 +- src/Controls/src/Core/ShellToolbar.cs | 4 ++ .../Issues/Issue28130_flyout.cs | 57 +++++++++++++++++++ .../Issues/Issue28130_shell.cs | 30 ++++++++++ .../Tests/Issues/Issue24547.cs | 6 +- .../Tests/Issues/Issue28130_flyout.cs | 27 +++++++++ .../Tests/Issues/Issue28130_shell.cs | 28 +++++++++ 8 files changed, 156 insertions(+), 8 deletions(-) create mode 100644 src/Controls/tests/TestCases.HostApp/Issues/Issue28130_flyout.cs create mode 100644 src/Controls/tests/TestCases.HostApp/Issues/Issue28130_shell.cs create mode 100644 src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28130_flyout.cs create mode 100644 src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28130_shell.cs diff --git a/src/Controls/src/Core/NavigationPage/NavigationPageToolbar.cs b/src/Controls/src/Core/NavigationPage/NavigationPageToolbar.cs index e6cc1113cb59..cb679d4fc62c 100644 --- a/src/Controls/src/Core/NavigationPage/NavigationPageToolbar.cs +++ b/src/Controls/src/Core/NavigationPage/NavigationPageToolbar.cs @@ -180,7 +180,11 @@ void UpdateBackButton() // Set this before BackButtonVisible triggers an update to the handler // This way all useful information is present - if (Parent is FlyoutPage flyout && flyout.ShouldShowToolbarButton() && !anyPagesPushed.Value) + if (Parent is FlyoutPage flyout && flyout.ShouldShowToolbarButton() +#if !WINDOWS // TODO NET 10 : Move this logic to ShouldShowToolbarButton + && !anyPagesPushed.Value +#endif + ) _drawerToggleVisible = true; else _drawerToggleVisible = false; diff --git a/src/Controls/src/Core/Platform/Windows/Extensions/ToolbarExtensions.cs b/src/Controls/src/Core/Platform/Windows/Extensions/ToolbarExtensions.cs index 1fe23332fa72..7348dbd80992 100644 --- a/src/Controls/src/Core/Platform/Windows/Extensions/ToolbarExtensions.cs +++ b/src/Controls/src/Core/Platform/Windows/Extensions/ToolbarExtensions.cs @@ -87,9 +87,9 @@ public static void UpdateToolbarDynamicOverflowEnabled(this MauiToolbar platform private static void UpdateBackButtonVisibility(MauiToolbar platformToolbar, Toolbar toolbar) { - platformToolbar.IsBackButtonVisible = - toolbar.BackButtonVisible - ? NavigationViewBackButtonVisible.Visible + platformToolbar.IsBackButtonVisible = + toolbar.BackButtonVisible + ? NavigationViewBackButtonVisible.Visible : NavigationViewBackButtonVisible.Collapsed; } } diff --git a/src/Controls/src/Core/ShellToolbar.cs b/src/Controls/src/Core/ShellToolbar.cs index 2b3ebfb63c6a..beb4e6374a62 100644 --- a/src/Controls/src/Core/ShellToolbar.cs +++ b/src/Controls/src/Core/ShellToolbar.cs @@ -91,7 +91,11 @@ internal void ApplyChanges() } var flyoutBehavior = (_shell as IFlyoutView).FlyoutBehavior; +#if WINDOWS + _drawerToggleVisible = flyoutBehavior is FlyoutBehavior.Flyout; +#else _drawerToggleVisible = stack.Count <= 1 && flyoutBehavior is FlyoutBehavior.Flyout; +#endif BackButtonVisible = backButtonVisible && stack.Count > 1; BackButtonEnabled = _backButtonBehavior?.IsEnabled ?? true; ToolbarItems = _toolbarTracker.ToolbarItems; diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue28130_flyout.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue28130_flyout.cs new file mode 100644 index 000000000000..e143f740b7d5 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue28130_flyout.cs @@ -0,0 +1,57 @@ +namespace Maui.Controls.Sample.Issues +{ + [Issue(IssueTracker.Github, 28130, "[Windows] Flyout Menu Icon disappears from Window Title Bar after Navigation", PlatformAffected.UWP)] + public class Issue28130_Flyout : TestFlyoutPage + { + NavigationPage _navigationPage; + string pageTitle = "Issue28130"; + protected override void Init() + { + Flyout = CreateFlyoutContent(); + FlyoutLayoutBehavior = FlyoutLayoutBehavior.Popover; + Detail = _navigationPage = new NavigationPage(new Issue28130_DetailPage(pageTitle) { AutomationId = pageTitle}); + } + + ContentPage CreateFlyoutContent() + { + var flyoutContent = new ContentPage() { Title = "Menu"}; + var layout = new VerticalStackLayout(); + var navigateButton = new Button() { Text = "Navigate to Page 2", AutomationId = "NavigateButton"}; + navigateButton.Clicked += (s, e) => _navigationPage.PushAsync(new Issue28130_Page1()); + layout.Add(navigateButton); + flyoutContent.Content = layout; + return flyoutContent; + } + } + + public class Issue28130_Page1 : TestContentPage + { + protected override void Init() + { + Content = new VerticalStackLayout() + { + new Label() + { + Text = "Tap flyout", + AutomationId="newPageLabel" + } + }; + } + } + + public class Issue28130_DetailPage : ContentPage + { + public Issue28130_DetailPage(string title) + { + Title = title; + Content = new VerticalStackLayout() + { + new Label() + { + Text = "Once Loaded, Tap the flyout", + AutomationId = "detailLabel" + } + }; + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue28130_shell.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue28130_shell.cs new file mode 100644 index 000000000000..7d7adac12c32 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue28130_shell.cs @@ -0,0 +1,30 @@ +namespace Maui.Controls.Sample.Issues +{ + [Issue(IssueTracker.None,28130, "[Windows] Shell Flyout Menu Icon disappears from Window Title Bar after Navigation", PlatformAffected.UWP)] + public class Issue28130_Shell : TestShell + { + + protected override void Init() + { + Routing.RegisterRoute(nameof(Issue28130_Page1), typeof(Issue28130_Page1)); + FlyoutBehavior = FlyoutBehavior.Flyout; + FlyoutWidth = 300; + ItemTemplate = new DataTemplate(() => CreateShellItemTemplate()); + ShellItem shellItem = new ShellItem() { Title = "Issue28130" }; + shellItem.Items.Add(new ShellContent() { Content = new Issue28130_DetailPage("Issue28130") }); + Items.Add(shellItem); + } + + Button CreateShellItemTemplate() + { + var navigateButton = new Button() { Text = "Navigate to Page 2" ,AutomationId = "NavigateButton"}; + navigateButton.Clicked += NavigateButton_Clicked; + return navigateButton; + } + + private void NavigateButton_Clicked(object sender, EventArgs e) + { + GoToAsync(nameof(Issue28130_Page1)); + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue24547.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue24547.cs index d4db591fb568..d448f7b27a76 100644 --- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue24547.cs +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue24547.cs @@ -1,5 +1,4 @@ -#if TEST_FAILS_ON_WINDOWS // Fix reverted. Refer For further info - https://github.com/dotnet/maui/issues/24547 -using NUnit.Framework; +using NUnit.Framework; using UITest.Appium; using UITest.Core; @@ -17,5 +16,4 @@ public void VerifyInitialToolbarButtonHidden() App.WaitForElement("DetailButton"); VerifyScreenshot(); } -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28130_flyout.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28130_flyout.cs new file mode 100644 index 000000000000..8d9523d9c0e7 --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28130_flyout.cs @@ -0,0 +1,27 @@ +#if WINDOWS +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues +{ + public class Issue28130_Flyout : _IssuesUITest + { + public Issue28130_Flyout(TestDevice testDevice) : base(testDevice) + { + } + + public override string Issue => "[Windows] Flyout Menu Icon disappears from Window Title Bar after Navigation"; + + [Test] + [Category(UITestCategories.FlyoutPage)] + public void FlyoutMenuShouldNotDisappearAfterNavigation_FlyoutPage() + { + App.WaitForElement("detailLabel"); + App.TapInFlyoutPageFlyout("NavigateButton"); + App.WaitForElement("newPageLabel"); + App.TapFlyoutPageIcon(); + } + } +} +#endif \ No newline at end of file diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28130_shell.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28130_shell.cs new file mode 100644 index 000000000000..9e4fa7649c6d --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28130_shell.cs @@ -0,0 +1,28 @@ +#if WINDOWS +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues +{ + public class Issue28130_Shell : _IssuesUITest + { + public Issue28130_Shell(TestDevice testDevice) : base(testDevice) + { + } + + public override string Issue => "[Windows] Shell Flyout Menu Icon disappears from Window Title Bar after Navigation"; + + [Test] + [Category(UITestCategories.Shell)] + public void FlyoutMenuShouldNotDisappearAfterNavigation_Shell() + { + App.WaitForElement("detailLabel"); + App.TapShellFlyoutIcon(); + App.Tap("Navigate to Page 2"); + App.WaitForElement("newPageLabel"); + App.TapShellFlyoutIcon(); + } + } +} +#endif \ No newline at end of file From 559da79488fb1539820a7491fefe40c9de6f8b67 Mon Sep 17 00:00:00 2001 From: HarishwaranVijayakumar Date: Fri, 28 Mar 2025 21:30:35 +0530 Subject: [PATCH 22/34] [Android, iOS] Dynamically setting SearchHandler Query property does not update text in the search box (#28400) * Fix for query not updating during runtime * Fix for SearchHandler * Fix for SearchHandler Dynamic Update * Fix for Dynamic SearchHandler QueryProperty * Fix for query not updating in runtime * Fix for searchHandler * Updating the images * Revert "Updating the images" This reverts commit d3959fed89ca4e5268ab55be7254f67424656b32. * Modified Test case for search Handler * Modifying the testcase and. the code --- .../Android/SearchHandlerAppearanceTracker.cs | 22 +++++++ .../iOS/SearchHandlerAppearanceTracker.cs | 13 +++++ .../TestCases.HostApp/Issues/Issue14497.cs | 57 +++++++++++++++++++ .../Tests/Issues/Issue14497.cs | 23 ++++++++ .../src/UITest.Appium/HelperExtensions.cs | 33 +++++++++++ 5 files changed, 148 insertions(+) create mode 100644 src/Controls/tests/TestCases.HostApp/Issues/Issue14497.cs create mode 100644 src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue14497.cs diff --git a/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/SearchHandlerAppearanceTracker.cs b/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/SearchHandlerAppearanceTracker.cs index 6b21640b0ca2..e09a56b39f98 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/SearchHandlerAppearanceTracker.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/SearchHandlerAppearanceTracker.cs @@ -82,6 +82,28 @@ protected virtual void SearchHandlerPropertyChanged(object sender, System.Compon { UpdateAutomationId(); } + else if (e.Is(SearchHandler.QueryProperty)) + { + UpdateText(); + } + } + + void UpdateText() + { + int cursorPosition = _editText.SelectionStart; + bool selectionExists = _editText.HasSelection; + + _editText.Text = _searchHandler.Query ?? string.Empty; + + UpdateTextTransform(); + + // If we had a selection, place the cursor at the end of text + // Otherwise try to maintain the cursor at its previous position + int textLength = _editText.Text?.Length ?? 0; + int newPosition = selectionExists ? textLength : Math.Min(cursorPosition, textLength); + + // Prevents the cursor from resetting to position zero when text is set programmatically + _editText.SetSelection(newPosition); } void EditTextFocusChange(object s, AView.FocusChangeEventArgs args) diff --git a/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/SearchHandlerAppearanceTracker.cs b/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/SearchHandlerAppearanceTracker.cs index ecea8c950e70..7d8e11076e63 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/SearchHandlerAppearanceTracker.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/SearchHandlerAppearanceTracker.cs @@ -115,6 +115,19 @@ void SearchHandlerPropertyChanged(object sender, System.ComponentModel.PropertyC { UpdateSearchBarVerticalTextAlignment(_uiSearchBar.FindDescendantView()); } + else if (e.Is(SearchHandler.QueryProperty)) + { + UpdateText(_uiSearchBar.FindDescendantView()); + } + } + + void UpdateText(UITextField uiTextField) + { + if (uiTextField is null) + return; + + uiTextField.Text = _searchHandler.Query; + UpdateTextTransform(uiTextField); } void GetDefaultSearchBarColors(UISearchBar searchBar) diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue14497.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue14497.cs new file mode 100644 index 000000000000..85ef977a95a0 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue14497.cs @@ -0,0 +1,57 @@ +namespace Maui.Controls.Sample.Issues; + +[Issue(IssueTracker.Github, 14497, "Dynamically setting SearchHandler Query property does not update text in the search box", PlatformAffected.Android | PlatformAffected.iOS)] +public class Issue14497 : Shell +{ + public Issue14497() + { + ShellContent shellContent = new ShellContent + { + Title = "Home", + ContentTemplate = new DataTemplate(typeof(Issue14497Page)), + Route = "MainPage" + }; + + Items.Add(shellContent); + } +} + +public class Issue14497Page : ContentPage +{ + Issue14497CustomSearchHandler _searchHandler; + public Issue14497Page() + { + _searchHandler = new Issue14497CustomSearchHandler(); + + Button button = new Button + { + Text = "Change Search Text", + AutomationId = "ChangeSearchText" + }; + + button.Clicked += (s,e) => _searchHandler.SetQuery("Hello World"); + + VerticalStackLayout stackLayout = new VerticalStackLayout + { + Children = { button } + }; + + Content = stackLayout; + Shell.SetSearchHandler(this, _searchHandler); + } +} + +public class Issue14497CustomSearchHandler : SearchHandler +{ + public Issue14497CustomSearchHandler() + { + Placeholder = "Search..."; + ShowsResults = false; + } + + public void SetQuery(string searchText) + { + Query = searchText; + } + +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue14497.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue14497.cs new file mode 100644 index 000000000000..825c93d804c0 --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue14497.cs @@ -0,0 +1,23 @@ +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues; + +public class Issue14497 : _IssuesUITest +{ + public Issue14497(TestDevice device) : base(device) { } + + public override string Issue => "Dynamically setting SearchHandler Query property does not update text in the search box"; + const string ChangeSearchText = "ChangeSearchText"; + + [Test] + [Category(UITestCategories.Shell)] + public void DynamicallyQueryNotUpdating() + { + App.WaitForElement(ChangeSearchText); + App.Tap(ChangeSearchText); + var searchHandlerString = App.GetShellSearchHandler().GetText(); + Assert.That(searchHandlerString, Is.EqualTo("Hello World")); + } +} \ No newline at end of file diff --git a/src/TestUtils/src/UITest.Appium/HelperExtensions.cs b/src/TestUtils/src/UITest.Appium/HelperExtensions.cs index 954e3c8dd2f0..576472c47b94 100644 --- a/src/TestUtils/src/UITest.Appium/HelperExtensions.cs +++ b/src/TestUtils/src/UITest.Appium/HelperExtensions.cs @@ -2466,5 +2466,38 @@ public static void SetTestConfigurationArg(this IConfig config, string key, stri startupArg.Add(key, value); config.SetProperty("TestConfigurationArgs", startupArg); } + + ///

+ /// Gets the search handler element for the shell. + /// This method is used to find the search handler element in the app. + /// It uses different queries based on the app type (Android, iOS, Catalyst, or Windows). + /// + /// The IApp instance representing the application. + /// The search handler element for the shell. + public static IUIElement GetShellSearchHandler(this IApp app) + { + IUIElement? element = null; + + if (app is AppiumAndroidApp) + { + element = app.WaitForElement(AppiumQuery.ByXPath("//android.widget.EditText")); + } + else if (app is AppiumIOSApp || app is AppiumCatalystApp) + { + element = app.WaitForElement(AppiumQuery.ByXPath("//XCUIElementTypeSearchField")); + } + else if (app is AppiumWindowsApp) + { + element = app.WaitForElement("TextBox"); + } + + // Ensure the element is not null before returning + if (element is null) + { + throw new InvalidOperationException("SearchHandler element not found."); + } + + return element; + } } } \ No newline at end of file From 589fd52f20fee4bfa50de1c4726ffe79feebfd8e Mon Sep 17 00:00:00 2001 From: Ahamed-Ali <102580874+Ahamed-Ali@users.noreply.github.com> Date: Sun, 30 Mar 2025 05:47:04 +0530 Subject: [PATCH 23/34] [Catalyst] Fixed the CanMixGroups Set to False Still Allows Reordering Between Groups in CollectionView (#28623) * Fixed the CanMixGroups Set to False Still Allows Reordering Between Groups in CollectionView * Committed the test case and sample * Committed the pending snap --- .../iOS/ReorderableItemsViewController.cs | 5 ++ .../iOS/ReorderableItemsViewController2.cs | 5 ++ ...sShouldNotOccurWhenCanMixGroupsIsFalse.png | Bin 0 -> 11022 bytes .../TestCases.HostApp/Issues/Issue28530.xaml | 33 +++++++++++ .../Issues/Issue28530.xaml.cs | 56 ++++++++++++++++++ ...sShouldNotOccurWhenCanMixGroupsIsFalse.png | Bin 0 -> 9907 bytes .../Tests/Issues/Issue28530.cs | 23 +++++++ ...sShouldNotOccurWhenCanMixGroupsIsFalse.png | Bin 0 -> 15363 bytes 8 files changed, 122 insertions(+) create mode 100644 src/Controls/tests/TestCases.Android.Tests/snapshots/android/ReorderBetweenGroupsShouldNotOccurWhenCanMixGroupsIsFalse.png create mode 100644 src/Controls/tests/TestCases.HostApp/Issues/Issue28530.xaml create mode 100644 src/Controls/tests/TestCases.HostApp/Issues/Issue28530.xaml.cs create mode 100644 src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/ReorderBetweenGroupsShouldNotOccurWhenCanMixGroupsIsFalse.png create mode 100644 src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28530.cs create mode 100644 src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/ReorderBetweenGroupsShouldNotOccurWhenCanMixGroupsIsFalse.png diff --git a/src/Controls/src/Core/Handlers/Items/iOS/ReorderableItemsViewController.cs b/src/Controls/src/Core/Handlers/Items/iOS/ReorderableItemsViewController.cs index 8878d36194b6..63dc064fd595 100644 --- a/src/Controls/src/Core/Handlers/Items/iOS/ReorderableItemsViewController.cs +++ b/src/Controls/src/Core/Handlers/Items/iOS/ReorderableItemsViewController.cs @@ -21,6 +21,11 @@ public ReorderableItemsViewController(TItemsView reorderableItemsView, ItemsView // For some reason it only seemed to work when the CollectionView was inside the Flyout section of a FlyoutPage. // The UILongPressGestureRecognizer is simple enough to set up so let's just add our own. InstallsStandardGestureForInteractiveMovement = false; +#if MACCATALYST + // On Mac Catalyst, the default normal press and drag interactions occur, causing the CanMixGroups = false logic to not work. + // Since all reordering logic is handled exclusively by UILongPressGestureRecognizer, we can set DragInteractionEnabled to false, ensuring that only the long press gesture is used. + CollectionView.DragInteractionEnabled = false; +#endif } public override bool CanMoveItem(UICollectionView collectionView, NSIndexPath indexPath) diff --git a/src/Controls/src/Core/Handlers/Items2/iOS/ReorderableItemsViewController2.cs b/src/Controls/src/Core/Handlers/Items2/iOS/ReorderableItemsViewController2.cs index 12e33e65ef62..2114d4eecc35 100644 --- a/src/Controls/src/Core/Handlers/Items2/iOS/ReorderableItemsViewController2.cs +++ b/src/Controls/src/Core/Handlers/Items2/iOS/ReorderableItemsViewController2.cs @@ -21,6 +21,11 @@ public ReorderableItemsViewController2(TItemsView reorderableItemsView, UICollec // For some reason it only seemed to work when the CollectionView was inside the Flyout section of a FlyoutPage. // The UILongPressGestureRecognizer is simple enough to set up so let's just add our own. InstallsStandardGestureForInteractiveMovement = false; +#if MACCATALYST + // On Mac Catalyst, the default normal press and drag interactions occur, causing the CanMixGroups = false logic to not work. + // Since all reordering logic is handled exclusively by UILongPressGestureRecognizer, we can set DragInteractionEnabled to false, ensuring that only the long press gesture is used. + CollectionView.DragInteractionEnabled = false; +#endif } public override bool CanMoveItem(UICollectionView collectionView, NSIndexPath indexPath) diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/ReorderBetweenGroupsShouldNotOccurWhenCanMixGroupsIsFalse.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/ReorderBetweenGroupsShouldNotOccurWhenCanMixGroupsIsFalse.png new file mode 100644 index 0000000000000000000000000000000000000000..f03b47c2e3a3d9cc7af5a65c760f7bcfc22ca990 GIT binary patch literal 11022 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 TX*vNmpbO`%&Y{1*`qTdbM(tLU literal 0 HcmV?d00001 diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue28530.xaml b/src/Controls/tests/TestCases.HostApp/Issues/Issue28530.xaml new file mode 100644 index 000000000000..3d4a843a08d6 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue28530.xaml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue28530.xaml.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue28530.xaml.cs new file mode 100644 index 000000000000..84218d89b59f --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue28530.xaml.cs @@ -0,0 +1,56 @@ +using System.Collections.ObjectModel; +using System.ComponentModel; + +namespace Maui.Controls.Sample.Issues; +[Issue(IssueTracker.Github, 28530, "[Catalyst] CanMixGroups Set to False Still Allows Reordering Between Groups in CollectionView", PlatformAffected.macOS)] +public partial class Issue28530 : ContentPage +{ + public Issue28530() + { + InitializeComponent(); + BindingContext = new Issue28530CollectionViewViewModel(); + } +} + +public class Issue28530CollectionViewViewModel : INotifyPropertyChanged +{ + public ObservableCollection GroupedItems { get; set; } + public event PropertyChangedEventHandler PropertyChanged; + + public Issue28530CollectionViewViewModel() + { + GroupedItems = new ObservableCollection + { + new Issue28530GroupedItem("Group 1") + { + new Issue28530Item { Name = "Item 1" }, + new Issue28530Item { Name = "Item 2" } + }, + new Issue28530GroupedItem("Group 2") + { + new Issue28530Item { Name = "Item 3" }, + new Issue28530Item { Name = "Item 4" } + } + }; + } + + protected void OnPropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } +} + +public class Issue28530GroupedItem : ObservableCollection +{ + public string GroupHeaderName { get; set; } + + public Issue28530GroupedItem(string groupHeaderName) + { + GroupHeaderName = groupHeaderName; + } +} + +public class Issue28530Item +{ + public string Name { get; set; } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/ReorderBetweenGroupsShouldNotOccurWhenCanMixGroupsIsFalse.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/ReorderBetweenGroupsShouldNotOccurWhenCanMixGroupsIsFalse.png new file mode 100644 index 0000000000000000000000000000000000000000..dc986a7d75c5402f444e140cda50a533ab7893b8 GIT binary patch literal 9907 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 "[Catalyst] CanMixGroups Set to False Still Allows Reordering Between Groups in CollectionView"; + + [Test] + [Category(UITestCategories.CollectionView)] + public void ReorderBetweenGroupsShouldNotOccurWhenCanMixGroupsIsFalse() + { + App.WaitForElement("CollectionViewControl"); + App.DragAndDrop("Item 2", "Item 3"); + VerifyScreenshot(); + } +} +#endif \ No newline at end of file diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/ReorderBetweenGroupsShouldNotOccurWhenCanMixGroupsIsFalse.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/ReorderBetweenGroupsShouldNotOccurWhenCanMixGroupsIsFalse.png new file mode 100644 index 0000000000000000000000000000000000000000..f64c10a261ffe6dd6a6c4c8f306e42b5d9c02551 GIT binary patch literal 15363 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 WvD+<3X{sp(K^^isSowAE5B~w^zNfVS literal 0 HcmV?d00001 From 712745486c93f59ae9fc4b9ca5040fabf30eaa47 Mon Sep 17 00:00:00 2001 From: Tamilarasan Paranthaman <93904422+Tamilarasan-Paranthaman@users.noreply.github.com> Date: Thu, 3 Apr 2025 20:34:01 +0530 Subject: [PATCH 24/34] [Android] Fix for SearchHandler Placeholder did not update when changed at runtime (#28636) * Placeholder issue fix * Added Android snapshot * Added Mac and Windows snapshots --- .../Android/SearchHandlerAppearanceTracker.cs | 9 ++++ .../VerifySearchHandlerPlaceholderText.png | Bin 0 -> 28452 bytes .../TestCases.HostApp/Issues/Issue28634.cs | 49 ++++++++++++++++++ .../VerifySearchHandlerPlaceholderText.png | Bin 0 -> 13054 bytes .../Tests/Issues/Issue28634.cs | 23 ++++++++ .../VerifySearchHandlerPlaceholderText.png | Bin 0 -> 10574 bytes .../VerifySearchHandlerPlaceholderText.png | Bin 0 -> 39194 bytes 7 files changed, 81 insertions(+) create mode 100644 src/Controls/tests/TestCases.Android.Tests/snapshots/android/VerifySearchHandlerPlaceholderText.png create mode 100644 src/Controls/tests/TestCases.HostApp/Issues/Issue28634.cs create mode 100644 src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/VerifySearchHandlerPlaceholderText.png create mode 100644 src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28634.cs create mode 100644 src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifySearchHandlerPlaceholderText.png create mode 100644 src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/VerifySearchHandlerPlaceholderText.png diff --git a/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/SearchHandlerAppearanceTracker.cs b/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/SearchHandlerAppearanceTracker.cs index e09a56b39f98..52fadb15e8fe 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/SearchHandlerAppearanceTracker.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/SearchHandlerAppearanceTracker.cs @@ -54,6 +54,10 @@ protected virtual void SearchHandlerPropertyChanged(object sender, System.Compon { UpdateTextTransform(); } + else if (e.Is(SearchHandler.PlaceholderProperty)) + { + UpdatePlaceholder(); + } else if (e.Is(SearchHandler.PlaceholderColorProperty)) { UpdatePlaceholderColor(); @@ -137,6 +141,11 @@ void UpdateFont() _editText.SetTextSize(ComplexUnitType.Sp, (float)_searchHandler.FontSize); } + void UpdatePlaceholder() + { + _editText.Hint = _searchHandler.Placeholder; + } + void UpdatePlaceholderColor() { _editText.UpdatePlaceholderColor(_searchHandler.PlaceholderColor); diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/VerifySearchHandlerPlaceholderText.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/VerifySearchHandlerPlaceholderText.png new file mode 100644 index 0000000000000000000000000000000000000000..3065fce5870784f7fd95bb66f41b3190d36ff69d GIT binary patch literal 28452 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 CM5Sy1 literal 0 HcmV?d00001 diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue28634.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue28634.cs new file mode 100644 index 000000000000..3397fa26a9bf --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue28634.cs @@ -0,0 +1,49 @@ +namespace Maui.Controls.Sample.Issues; + +[Issue(IssueTracker.Github, 28634, "[Android] SearchHandler Placeholder Text", PlatformAffected.Android)] +public class Issue28634 : TestShell +{ + + protected override void Init() + { + this.FlyoutBehavior = FlyoutBehavior.Flyout; + + var shellContent = new ShellContent + { + Title = "Home", + Route = "MainPage", + Content = new Issue28634ContentPage() { Title = "Home" } + }; + + Items.Add(shellContent); + + } + class Issue28634ContentPage : ContentPage + { + public Issue28634ContentPage() + { + + var searchHandler = new SearchHandler + { + Placeholder = "Type a fruit name to search", + PlaceholderColor = Colors.Red, + }; + + var button = new Button + { + Text = "Change SearchHandler Placeholder", + AutomationId = "button", + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + }; + button.Clicked += (s, e) => + { + searchHandler.Placeholder = "Type a vegetable name to search"; + }; + + Shell.SetSearchHandler(this, searchHandler); + + Content = button; + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/VerifySearchHandlerPlaceholderText.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/VerifySearchHandlerPlaceholderText.png new file mode 100644 index 0000000000000000000000000000000000000000..b148ed2453473758e1f4d0679c4ca8667771a2ab GIT binary patch literal 13054 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 KO!z6_*Z%?tTKu*E literal 0 HcmV?d00001 diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28634.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28634.cs new file mode 100644 index 000000000000..ed13a444331f --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28634.cs @@ -0,0 +1,23 @@ +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues; + +public class Issue28634 : _IssuesUITest +{ + public override string Issue => "[Android] SearchHandler Placeholder Text"; + + public Issue28634(TestDevice device) + : base(device) + { } + + [Test] + [Category(UITestCategories.Shell)] + public void VerifySearchHandlerPlaceholderText() + { + App.WaitForElement("button"); + App.Tap("button"); + VerifyScreenshot(); + } +} diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifySearchHandlerPlaceholderText.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifySearchHandlerPlaceholderText.png new file mode 100644 index 0000000000000000000000000000000000000000..8a28a5837faadd66d3eb908811759363f67f3e8f GIT binary patch literal 10574 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 Date: Thu, 3 Apr 2025 20:51:44 +0530 Subject: [PATCH 25/34] [Testing] Migration of Compatibility.Core platform-specific unit tests into device tests - 8 (#28496) * code changes added * updated code --- .../Elements/Editor/EditorTests.Windows.cs | 37 ++++++++++++++++ .../Elements/Editor/EditorTests.iOS.cs | 39 +++++++++++++++-- .../Elements/Entry/EntryTests.Windows.cs | 35 ++++++++++++++++ .../Elements/Entry/EntryTests.iOS.cs | 42 ++++++++++++++++--- .../NavigationPage/NavigationPageTests.iOS.cs | 26 ++++++++++++ .../Elements/Page/PageTests.Android.cs | 37 ++++++++++++++++ .../Elements/Page/PageTests.iOS.cs | 21 ++++++++++ .../ImageButtonHandlerTests.iOS.cs | 17 ++++++++ 8 files changed, 246 insertions(+), 8 deletions(-) create mode 100644 src/Controls/tests/DeviceTests/Elements/Page/PageTests.Android.cs diff --git a/src/Controls/tests/DeviceTests/Elements/Editor/EditorTests.Windows.cs b/src/Controls/tests/DeviceTests/Elements/Editor/EditorTests.Windows.cs index e9bb56dc2acf..6dc9ab2f9d7c 100644 --- a/src/Controls/tests/DeviceTests/Elements/Editor/EditorTests.Windows.cs +++ b/src/Controls/tests/DeviceTests/Elements/Editor/EditorTests.Windows.cs @@ -1,7 +1,14 @@ #nullable enable +using Xunit; +using System; +using System.ComponentModel; using System.Threading.Tasks; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Dispatching; using Microsoft.Maui.Handlers; using Microsoft.UI.Xaml.Controls; +using WFlowDirection = Microsoft.UI.Xaml.FlowDirection; +using WTextAlignment = Microsoft.UI.Xaml.TextAlignment; namespace Microsoft.Maui.DeviceTests { @@ -41,5 +48,35 @@ Task GetPlatformIsVisible(EditorHandler editorHandler) return nativeView.Visibility == Microsoft.UI.Xaml.Visibility.Visible; }); } + //src/Compatibility/Core/tests/WinUI/FlowDirectionTests.cs + [Theory] + [InlineData(true, FlowDirection.RightToLeft, WTextAlignment.Left, WFlowDirection.RightToLeft)] + [InlineData(true, FlowDirection.LeftToRight, WTextAlignment.Left, WFlowDirection.LeftToRight)] + [InlineData(false, FlowDirection.LeftToRight, WTextAlignment.Left, WFlowDirection.LeftToRight)] + [Description("The Editor's text alignment and flow direction should match the expected values when FlowDirection is applied explicitly or implicitly.")] + public async Task EditorAlignmentMatchesFlowDirection(bool isExplicit, FlowDirection flowDirection, WTextAlignment expectedAlignment, WFlowDirection expectedFlowDirection) + { + var editor = new Editor { Text = " تسجيل الدخول" }; + var contentPage = new ContentPage { Title = "Flow Direction", Content = editor }; + + if (isExplicit) + { + editor.FlowDirection = flowDirection; + } + else + { + contentPage.FlowDirection = flowDirection; + } + + var handler = await CreateHandlerAsync(editor); + var (nativeAlignment, nativeFlowDirection) = await contentPage.Dispatcher.DispatchAsync(() => + { + var textField = GetPlatformControl(handler); + return (textField.TextAlignment, textField.FlowDirection); + }); + + Assert.Equal(expectedAlignment, nativeAlignment); + Assert.Equal(expectedFlowDirection, nativeFlowDirection); + } } } diff --git a/src/Controls/tests/DeviceTests/Elements/Editor/EditorTests.iOS.cs b/src/Controls/tests/DeviceTests/Elements/Editor/EditorTests.iOS.cs index 6be8fb8fb7b4..6f89153da58c 100644 --- a/src/Controls/tests/DeviceTests/Elements/Editor/EditorTests.iOS.cs +++ b/src/Controls/tests/DeviceTests/Elements/Editor/EditorTests.iOS.cs @@ -1,11 +1,14 @@ -using System.Linq; +using UIKit; +using Xunit; +using System.Linq; using System.Threading.Tasks; using Microsoft.Maui.Controls; +using Microsoft.Maui.Dispatching; using Microsoft.Maui.Handlers; using Microsoft.Maui.Hosting; using Microsoft.Maui.Platform; -using Xunit; using static Microsoft.Maui.DeviceTests.AssertHelpers; +using System.ComponentModel; namespace Microsoft.Maui.DeviceTests { @@ -48,7 +51,7 @@ Task GetPlatformOpacity(EditorHandler editorHandler) return InvokeOnMainThreadAsync(() => { var nativeView = GetPlatformControl(editorHandler); - return (float)nativeView.Alpha; + return (float)nativeView.Alpha; }); } @@ -103,5 +106,35 @@ await CreateHandlerAndAddToWindow(contentPage, async () => }); } } + + //src/Compatibility/Core/tests/iOS/FlowDirectionTests.cs + [Theory] + [InlineData(true, FlowDirection.LeftToRight, UITextAlignment.Left)] + [InlineData(true, FlowDirection.RightToLeft, UITextAlignment.Right)] + [InlineData(false, FlowDirection.LeftToRight, UITextAlignment.Left)] + [Description("The Editor's text alignment should match the expected alignment when FlowDirection is applied explicitly or implicitly")] + public async Task EditorAlignmentMatchesFlowDirection(bool isExplicit, FlowDirection flowDirection, UITextAlignment expectedAlignment) + { + var editor = new Editor { Text = "Checking flow direction" }; + var contentPage = new ContentPage { Title = "Flow Direction", Content = editor }; + + if (isExplicit) + { + editor.FlowDirection = flowDirection; + } + else + { + contentPage.FlowDirection = flowDirection; + } + + var handler = await CreateHandlerAsync(editor); + var nativeAlignment = await contentPage.Dispatcher.DispatchAsync(() => + { + var textField = GetPlatformControl(handler); + return textField.TextAlignment; + }); + + Assert.Equal(expectedAlignment, nativeAlignment); + } } } diff --git a/src/Controls/tests/DeviceTests/Elements/Entry/EntryTests.Windows.cs b/src/Controls/tests/DeviceTests/Elements/Entry/EntryTests.Windows.cs index f76b6526f23b..a41c816bea69 100644 --- a/src/Controls/tests/DeviceTests/Elements/Entry/EntryTests.Windows.cs +++ b/src/Controls/tests/DeviceTests/Elements/Entry/EntryTests.Windows.cs @@ -1,7 +1,12 @@ #nullable enable +using Xunit; +using System.ComponentModel; using System.Threading.Tasks; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Dispatching; using Microsoft.Maui.Handlers; using Microsoft.UI.Xaml.Controls; +using WTextAlignment = Microsoft.UI.Xaml.TextAlignment; namespace Microsoft.Maui.DeviceTests { @@ -41,5 +46,35 @@ Task GetPlatformIsVisible(EntryHandler entryHandler) return nativeView.Visibility == Microsoft.UI.Xaml.Visibility.Visible; }); } + //src/Compatibility/Core/tests/WinUI/FlowDirectionTests.cs + [Theory] + [InlineData(true, FlowDirection.LeftToRight, WTextAlignment.Left)] + [InlineData(true, FlowDirection.RightToLeft, WTextAlignment.Left)] + [InlineData(false, FlowDirection.LeftToRight, WTextAlignment.Left)] + [InlineData(false, FlowDirection.RightToLeft, WTextAlignment.Left)] + [Description("The Entry's text alignment should match the expected alignment when FlowDirection is applied explicitly or implicitly.")] + public async Task EntryAlignmentMatchesFlowDirection(bool isExplicit, FlowDirection flowDirection, WTextAlignment expectedAlignment) + { + var entry = new Entry { Text = "Checking flow direction", HorizontalTextAlignment = TextAlignment.Start }; + var contentPage = new ContentPage { Title = "Flow Direction", Content = entry }; + + if (isExplicit) + { + entry.FlowDirection = flowDirection; + } + else + { + contentPage.FlowDirection = flowDirection; + } + + var handler = await CreateHandlerAsync(entry); + var nativeAlignment = await contentPage.Dispatcher.DispatchAsync(() => + { + var textField = GetPlatformControl(handler); + return textField.TextAlignment; + }); + + Assert.Equal(expectedAlignment, nativeAlignment); + } } } diff --git a/src/Controls/tests/DeviceTests/Elements/Entry/EntryTests.iOS.cs b/src/Controls/tests/DeviceTests/Elements/Entry/EntryTests.iOS.cs index 4a2e9e48c957..282b8a5647ef 100644 --- a/src/Controls/tests/DeviceTests/Elements/Entry/EntryTests.iOS.cs +++ b/src/Controls/tests/DeviceTests/Elements/Entry/EntryTests.iOS.cs @@ -1,13 +1,15 @@ -using System.Linq; +using UIKit; +using Xunit; +using System.ComponentModel; +using System.Linq; using System.Threading.Tasks; using Microsoft.Maui.Controls; using Microsoft.Maui.Controls.Handlers.Compatibility; using Microsoft.Maui.DeviceTests.TestCases; +using Microsoft.Maui.Dispatching; using Microsoft.Maui.Handlers; using Microsoft.Maui.Hosting; using Microsoft.Maui.Platform; -using UIKit; -using Xunit; using static Microsoft.Maui.DeviceTests.AssertHelpers; namespace Microsoft.Maui.DeviceTests @@ -44,13 +46,13 @@ static int GetPlatformSelectionLength(EntryHandler entryHandler) return -1; } - + Task GetPlatformOpacity(EntryHandler entryHandler) { return InvokeOnMainThreadAsync(() => { var nativeView = GetPlatformControl(entryHandler); - return (float)nativeView.Alpha; + return (float)nativeView.Alpha; }); } @@ -332,5 +334,35 @@ await CreateHandlerAndAddToWindow(contentPage, async () => }); } } + + //src/Compatibility/Core/tests/iOS/FlowDirectionTests.cs + [Theory] + [InlineData(true, FlowDirection.LeftToRight, UITextAlignment.Left)] + [InlineData(true, FlowDirection.RightToLeft, UITextAlignment.Right)] + [InlineData(false, FlowDirection.LeftToRight, UITextAlignment.Left)] + [Description("The Entry's text alignment should match the expected alignment when FlowDirection is applied explicitly or implicitly")] + public async Task EntryAlignmentMatchesFlowDirection(bool isExplicit, FlowDirection flowDirection, UITextAlignment expectedAlignment) + { + var entry = new Entry { Text = "Checking flow direction", HorizontalTextAlignment = TextAlignment.Start }; + var contentPage = new ContentPage { Title = "Flow Direction", Content = entry }; + + if (isExplicit) + { + entry.FlowDirection = flowDirection; + } + else + { + contentPage.FlowDirection = flowDirection; + } + + var handler = await CreateHandlerAsync(entry); + var nativeAlignment = await contentPage.Dispatcher.DispatchAsync(() => + { + var textField = GetPlatformControl(handler); + return textField.TextAlignment; + }); + + Assert.Equal(expectedAlignment, nativeAlignment); + } } } \ No newline at end of file diff --git a/src/Controls/tests/DeviceTests/Elements/NavigationPage/NavigationPageTests.iOS.cs b/src/Controls/tests/DeviceTests/Elements/NavigationPage/NavigationPageTests.iOS.cs index eca6b8284954..89cd1b7ed98b 100644 --- a/src/Controls/tests/DeviceTests/Elements/NavigationPage/NavigationPageTests.iOS.cs +++ b/src/Controls/tests/DeviceTests/Elements/NavigationPage/NavigationPageTests.iOS.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -7,6 +8,7 @@ using Microsoft.Maui.Controls.Handlers.Compatibility; using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.DeviceTests.Stubs; +using Microsoft.Maui.Dispatching; using Microsoft.Maui.Handlers; using Microsoft.Maui.Hosting; using Microsoft.Maui.Platform; @@ -65,5 +67,29 @@ public async Task TranslucentNavigationBar(bool enabled) var translucent = await GetValueAsync(navPage, (handler) => (handler.ViewController as UINavigationController).NavigationBar.Translucent); Assert.Equal(enabled, translucent); } + + //src/Compatibility/Core/tests/iOS/NavigationTests.cs + [Fact] + [Description("Multiple calls to NavigationRenderer.Dispose shouldn't crash")] + public async Task NavigationRendererDoubleDisposal() + { + SetupBuilder(); + + var root = new ContentPage() + { + Title = "root", + Content = new Label { Text = "Hello" } + }; + + await root.Dispatcher.DispatchAsync(() => + { + var navPage = new NavigationPage(root); + var handler = CreateHandler(navPage); + + // Calling Dispose more than once should be fine + (handler as NavigationRenderer).Dispose(); + (handler as NavigationRenderer).Dispose(); + }); + } } } diff --git a/src/Controls/tests/DeviceTests/Elements/Page/PageTests.Android.cs b/src/Controls/tests/DeviceTests/Elements/Page/PageTests.Android.cs new file mode 100644 index 000000000000..8ee2bf4a9524 --- /dev/null +++ b/src/Controls/tests/DeviceTests/Elements/Page/PageTests.Android.cs @@ -0,0 +1,37 @@ +using System.Threading.Tasks; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Dispatching; +using Microsoft.Maui.Handlers; +using Microsoft.Maui.Platform; +using Xunit; +using AView = Android.Views.View; +using AndroidX.Fragment.App; + +namespace Microsoft.Maui.DeviceTests +{ + public partial class PageTests : ControlsHandlerTestBase + { + //src/Compatibility/Core/tests/Android/EmbeddingTests.cs + [Fact(DisplayName = "Can Create Platform View From ContentPage")] + public async Task CanCreatePlatformViewFromContentPage() + { + + var contentPage = new ContentPage { Title = "Embedded Page" }; + var handler = CreateHandler(contentPage); + var mauiContext = handler.MauiContext; + + await contentPage.Dispatcher.DispatchAsync(() => + { + + AView platformView = contentPage.ToPlatform(mauiContext); + if (platformView is FragmentContainerView containerView) + { + var activity = mauiContext.Context as AndroidX.Fragment.App.FragmentActivity; + var fragmentManager = activity.SupportFragmentManager; + var fragment = fragmentManager.FindFragmentById(containerView.Id); + Assert.NotNull(fragment); + } + }); + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/DeviceTests/Elements/Page/PageTests.iOS.cs b/src/Controls/tests/DeviceTests/Elements/Page/PageTests.iOS.cs index 1c71d20140cb..045e31fb2c72 100644 --- a/src/Controls/tests/DeviceTests/Elements/Page/PageTests.iOS.cs +++ b/src/Controls/tests/DeviceTests/Elements/Page/PageTests.iOS.cs @@ -3,9 +3,12 @@ using Microsoft.Maui.Controls; using Microsoft.Maui.Controls.PlatformConfiguration; using Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific; +using Microsoft.Maui.Dispatching; +using Microsoft.Maui.Platform; using Microsoft.Maui.Graphics; using Microsoft.Maui.Handlers; using Microsoft.Maui.Hosting; +using UIKit; using Xunit; namespace Microsoft.Maui.DeviceTests @@ -40,5 +43,23 @@ await CreateHandlerAndAddToWindow(shell, (handler) => } }); } + + //src/Compatibility/Core/tests/iOS/EmbeddingTests.cs + [Fact(DisplayName = "Can Create Platform View From ContentPage")] + public async Task CanCreateViewControllerFromContentPage() + { + var contentPage = new ContentPage { Title = "Embedded Page" }; + await contentPage.Dispatcher.DispatchAsync(async () => + { + var handler = CreateHandler(contentPage); + var mauiContext = handler.MauiContext; + + await contentPage.Dispatcher.DispatchAsync(() => + { + UIViewController viewController = contentPage.ToUIViewController(mauiContext); + Assert.NotNull(viewController); + }); + }); + } } } diff --git a/src/Core/tests/DeviceTests/Handlers/ImageButton/ImageButtonHandlerTests.iOS.cs b/src/Core/tests/DeviceTests/Handlers/ImageButton/ImageButtonHandlerTests.iOS.cs index ed1c2a690008..3817c8c1d01b 100644 --- a/src/Core/tests/DeviceTests/Handlers/ImageButton/ImageButtonHandlerTests.iOS.cs +++ b/src/Core/tests/DeviceTests/Handlers/ImageButton/ImageButtonHandlerTests.iOS.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using CoreGraphics; +using Microsoft.Maui.Controls; using Microsoft.Maui.DeviceTests.Stubs; using Microsoft.Maui.Graphics; using Microsoft.Maui.Handlers; @@ -40,6 +41,22 @@ public async Task StrokeColorInitializesCorrectly() Assert.Equal(expectedValue, values.PlatformViewValue); } + //src/Compatibility/Core/tests/iOS/ImageButtonTests.cs + [Fact] + [Trait("Category", "ImageButton")] + public async Task CreatedWithCorrectButtonType() + { + var imageButton = new ImageButton(); + var handler = await CreateHandlerAsync(imageButton); + + var buttonType = await InvokeOnMainThreadAsync(() => + { + var uiButton = GetPlatformImageButton(handler); + return uiButton.ButtonType; + }); + + Assert.NotEqual(UIButtonType.Custom, buttonType); + } UIButton GetPlatformImageButton(ImageButtonHandler imageButtonHandler) => imageButtonHandler.PlatformView; From 2266e0d612a3d55827a0706c8b72c401a8ff68c0 Mon Sep 17 00:00:00 2001 From: Vignesh-SF3580 <102575140+Vignesh-SF3580@users.noreply.github.com> Date: Tue, 8 Apr 2025 22:01:59 +0530 Subject: [PATCH 26/34] Fixed Test case failure in PR 28486 (#28780) * Resolved the ScrollView TestFailures in Inflight. * updated ReorderBetweenGroupsShouldNotOccurWhenCanMixGroupsIsFalse ios image * Updated EntryClearButtonColorShouldMatchTextColor mac image --- ...sShouldNotOccurWhenCanMixGroupsIsFalse.png | Bin 15363 -> 30956 bytes .../ScrollView/ScrollViewHandler.iOS.cs | 9 +-------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/ReorderBetweenGroupsShouldNotOccurWhenCanMixGroupsIsFalse.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/ReorderBetweenGroupsShouldNotOccurWhenCanMixGroupsIsFalse.png index f64c10a261ffe6dd6a6c4c8f306e42b5d9c02551..8d1ec88316fec510d8d56d447ed7100483a95a3a 100644 GIT binary patch literal 30956 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 literal 15363 zcmeI32~< z`@4U?&))m;F)#NmfB5td5C~)o>d3)AK_DMsAdnB2KGbADB5t(yX*Rn z*VnQz*fyYx)nsYKV7165+Aq(krLuqwCgDdHOMW(F=*V9PLrxmC$1GsFCDTHWjAjK zF`7KM@!rRJKYxR{@Wpkl2fu@z@B8Meo+@Vb2{ql7jprQZ^B_?@<@yDMUQWu48C31e zHtS@S$>GN$B%VKkDp`HK&DFJfYuM)Uy1{`?%9FI2{;ja)@1Z9H)iM~>3^XQUKk?pL zQ5Z2W9jRSh^Gyi0GqOZR-a_Yk1j)z!9Tj!!eD)Q0rE%`L4CTjxx2aKY4b_t|gk(3Q zsm+$Y2AJrH+If{foyizk%Gf~hzXm<29wbJ!e3pc3N2^G32aZUqZ@;)}TzmxzHt87V zLsOVswPFyema5o}Q$Z|6Cf5`+aYR>ZQ9jAPdLM1oEX{yADR?0{U=K@8ogi~2^o8|3 zLktff#LD%%^$3`ar4NEkTkMAxh}tb-T)3*@u9;ujY$U*W+(>8ru+AVPl$|hJ9-aQQemgJ6K zzK~#(f2U^b5&Bg0){>kI1>HBMKMOwJ=Rv)dT-&S)YhU{!BxbWE zW%#*1nPa{2Vbs~>^l(yDJf}=Dc3F)~86|1T*Pw)*KKPGXH}0FUFJPL17wL_oP2^d# zk?(KnRViM)6iDewW1O|8Lqw%9)t}0hGVJ+=#>M#Qypo#P(!v&Yw7vhxhKz^@*J(-x zG(|OUuLD0Xp6fm-O&)h*2G-BJsj*#${42Ueij@J0*HvN)he~-YD<#Qt8*P`(&uZ+j zhXAsen^6-*$YZotEz;Q5?xD1ZYDorNJ6*<^$5bL zvImUtgZFgwt1HVtE$}B}$V#KM+dG`zJkmZ_2u)%4qJ+A9%Jrs&we>Mag+p{=u+iun z12Gr~6e)jbM_H})7-!4A)atVzpjHzBs0+Mbc`by#Qc=@k;p~caz ziv1d3swbS`bH3r{kPgY<24hcQPP;!zc0{YsZlKG;%hyRslLS75$G^Z}wiX6VWub&O z+`W$);lBnbfos|DKZmP2Uc4PJ_N-m;chCOKth>w*;K(vheK&(2(FZUr5Tx0YIi0*^ zI5`JI6q0gU{1KTdX?rl?8Ue8mpqZvc~_`V|67 z*am{eUJL{C*BJjwzqocHMR8H&0aT=lcCFpCo9Tk%)KDjht2uWZw@`)(GiaXo&AAr%IaxzK_qp+JC*s&)9}4PRy3M|l)DVr_;8aIWhtm)f;2V59Jw z2K!A!iW=6Mk|mlXs@`x`Nj>sZ06x!oVg+aa2&M7fZX#PKc}XyEDMUBG-3_#5fKstrdlOZtS}7v0vSxAfJlGIXdo?v*uw=|C~{3W;4=9jazN3^kc>5U7w9 z+Qtx409=QD+%GQc6<2OCjFZNe%wvL-ea-I5{R&LAF#e1ZWZKCZr_65X_P?>ab{UMhnxMV~QUwNKY z*({iSBpHw6>qSPf-{=!%_h9g_97=0ye-6sZc`s;9OztbeNp~43z9~$^r1~D-xHjPU zsN3{Hf~nn?H@hGw_N@Q*^5$dvbE688yy8s-&gr>kHan>|)pT-U7}k~4eYsviqV z5g&iq9?!%WIYkamfS=Wc^~x58v!CheOw3-+WK7KF$9P*{dn^3nYFAFwQT7otVMSz4 ziG(qkpsK_*ujR_4qewAL9wAd_zJGe%@9}rXf%dGOmZx)}ezH3(S4UJXC3g8TJ8Sb! z%cm}#_;?gxPD)1aT#~SK&HR??n+PH(s5J&-jya+1*k4}1sLtCAvkQl2 z9?edgbTMy%+r}=h)%Bpv&Mm1@vGRN9{ngJlbK~stU~-F+{QS7+o!L6!Oe5o-BW4-? zIWp7r`mc}esXKc{=>CwAulZPZA-p$d_aC!6-znT5o-GU2($BhG1V%ZAT-%;hoPQc& zkIVTj^I%w=Au;!^(f;|oby3+FaYGm{EO-z7QT6fD^sb|d?*?9h(o%wH>){C3J#}~? zTQF@~$a$#oD_Hnn&NT+w%;#;0vKTb6ivxT*yhB$B(O5<2Nhm0GCrSnbw;GAN*E#Iu z#j+)H+?ggkH%1PmpeEy1Po$r0n!A=xB($H*4U>~{WGA%rbHqRO2<}eY;8k|_aZN{N zf6y%{bYVD~qr!;O7v^FQAzXf(z9+b}w&c22^7)qMAHEZV|Nd6~uP^$y_V1`ro)Y8`pDvUy z2>SCF`r>U`8Q*sVUonTX{hh=OxA`4AtW_kzE27dLc5?ZAt&zG^LUEDQezw>y^_G&L zq)7)*o%+hP6k*o-$4BlMLVWLjxA|wD)&al-B2FYu3Q7yWcJQ-h`4G2#GdQ~~eE)pc z7C{4MR!cid>FC5QWPU2%s^wN^I}Y&^f}B#eBN^G?j+Na@`fyjtnZscMVo77}rhA8w z4O5KEf@t0G`do2kv$;LR);9Ktu=Kd`C&9^@;K7}7DaJ1rVG6*z&vY$1tEdP!aydP2;4P?P)ONux*LN&fS*bR8L*zelB zG5sOH8P?=XJ#7XGQeHE)HOT~2W$IL~+O4*aS^m_!wIlL?BOwN9>ok4So*X5WFkfDw z9z~q*x*KMevM>hH$=t;vXhG~$`oS=eKVGsv$aX$t-R4&snK_K@dXcPowQst&Z`URvyNfsl z>^g!gO{wKj_lDF$E=JVZrp0UT%AHPoBN1XK?c2A_Hb5 z^fHHW{h1%^D!+X&to=EMltNX#sAjCXdYx9UkrbezJyM0Kf>CtIo zQ*)te=&I~Iq|Kp-ik*e#Rj_tir9NwRnxp5)zJs_?3D*nO7-EeG@t)l7Cd!wZl+mS# zU9HQS&%EB707t;X$Z6tcHoH-0G@81pyx~5Nq)3@uQ|HJ|K{oKV6*z&Pv+vsB=nhUQ zwzTSQbm*aYP}$sas3pN#K%hNQnS z_o!2Lme=2IBsDomhdQf@Vn;8QA}m^~E8H)Qy&DuhJjpl(e2z{G~m&Ebt1j)ox zu@`y!rkI8Vs?!)rwnIz*rZ{_ZYr3fM5C7oI{C}fgg;z%N1z(p#>p{QCezgaQlUaQ^eR%n~g zIDOKXI4Hd7<5INpU|T>!v07;Cc{N-`-A)}{#z895BM!|*(v!IJ_9eph35S)d>P1S` zsRZF1+DC7AuP4mTIAx-Ce|WEQc1b^xPG3>fbo3P2wphDUXlIfjryTo!>KP(LF0k5k zit8q}Y(h|XqiXrTq6K-SEAcv}&(X*shRi33IXh5T#cuNsHRdT&g+70LL3vZY}!?P?qGLaJ*hclw9#&9hRqfx2U}= zSo1B=p&mVof~yM!d-d1q|5)v{(Pw2E3hMe6CLII}_P-M=S2E|0Tm?l5uRqi9i1C%z zpd(>bR=9)xaQqh34^eZ;(F{ay_8oaKrOh-#&vkk5soRHOpa~2Xg8~8^2Q*Fs#7AW_ z8BXT3vI3(gQE}u7*-oK3vId)`;!ij@wJeFz>dwW%#grCN53bWa9KBW+ULlw=iFp}Z z-Ol0UplX#N86!c#M>Hg0jOh(#N!-j8Xv$K$^~&9J3>i;t4n2(R?9MXRPuyy>(fP+IxJo#U%4BV+qA0CHt(`#QJ^Astl~nZ%|MstxeFI0Q=1-jZHsX| zKL!Q$W4r)*vO1d++G(5|0?<{;^`c*Pa_@OB0h|S03oq=maMjdTx%jpmR6TxT?^fgG zW9724QVn9*YHxh@{=dT|T)P1E@?~fWw<@}|bYn%`{Sr_CMVYCQtp6&ZK>h-tQw{+J z(u`LI$f?gXA%7P6gcorMKlFu;p{-s)o0;y~SpYusYCGATa*Y$Ni!jldE1=ujri$G) zQS0C~o$4ui^Hd8|o;Dhd9zNhH#ztg9X{yh5rVeu6WxFx^& zqRkwz2;luG&p_G@bs@4H2hU`+9{KmdMx_5+ZTIm4&QMFaZMEP(Asm+Ip`e=C>~7z! z*2JH4(1bN6c|q2jxz@kc<{KYX?4%o+qll?=;IjaZAQDGTp<QNKau`9A#H9d;d(AL7t|nAJqA#?L}P;7<(-@1$AIB;sK|) ziX-G`T3GK6HC_nYYlW(v?`4B0O7J+qo#L3ZPkZYrN1v-bbrNqNj#Y?-$cU?fy$NBz|y=ZoA6wu0jn8b9(ek5_|wXuB&tF;plnd_@cCG?G&KktJCJb z@*Z)fQUue+W?-pT5bwFY*BTj`WQd>d1Imn3l7Iz7;_4KG6+uB-=2h305e5?Fz~a7!#;iTOS(yAx6QngHrSVmY zs-fY`yPAYtoT=V7pZ?J}YoBU`?ZEX)iw>5G**PQgRaet~E<>&sq5vL)_EuLDp8dI| zgL6$cM~P#315Lc2pnhVW``^*Y(D?i)0=qEgQEhvR!OENXJ3_fgU$2bRZHgZ_p_WE( zZ_{BG7RkqAo~l!g5#M8zhld6QFqext%*U#q#IrE8RA^{+*GNROMy`Ifb5iKT^;Q6D zlWNiYP2@ODM2j(&xAs)t#Yb4;Y6kMup$l0zwbPa!j$M`Q)#`J2M88xF?QX%V9#Jhv zW4ScuB=@#%Q2b(!V@xx*1XmS%sBYmO5X$Kke{LSKDT3J?hFqDwm^1X)q%V$+>ujy6 zjtI2Usxbe@L68UciAndD43kU+?e59>!ymGqZ#41>u+sVqU-_SMNe0S&0;dyj zNii;~BWX6TN}j%>6tTB;S>x8di=QN$BdmjBpYOJYi=N`D6g^sCILmcDecfi};n)aa zu{WlVu2j4t6-(DxNJ$bve;V2E^1QA(4?S!^M>m(!d~*NTz_gG zvL06+_pfkD`X}CU+ES()cV zFWk82;(DmCowTsQ3MW6=gAwmr^tSB`6qbn#=Q|UJnuF51l@6=ZRcSNT;N?X?)8fCq zaJyispy$pZRP6z<77D)3OGBV)71{P)nxNwPvpZ3RY%dQDcv;X5k z4i|p$4s=QWfnER<%vJo zVbJYukBox#(GAufm2{!cCNHI;^QzIW)xGz+UyY5l^hEf$gNpwxgFI`B@=ELe97z;N zxL#*mgG(K5beFm0Ryl=?7LG2p(Qleo8O^*S1bf5n#(H;gUIfC*bD04Y(!x1meH>PW zFU*lOK-}zZbVb#(nZo|kjK}VBm?TiDZvuz5+HB!YlsSQ>eQ0@{yP^2mO&@ayREF4P ze{0txG{)@g`FN~qg=)t$M>|E#ar)_%N78&Z8aZeP&ln78WNcK2YLQI}1QXhe^z+78gyYOpo^T}vRZp9`#GSob$M^;qK_3Xd;y)_P zvUV|XoQOXRU_?}UNWb=mT_qZrdQ05wxX=Q=*qP|eC5J?eu<@H_JyU$f(p23{J^2?i ztJX@LoQs*{&(*Qifr%vEpo^!MMbq@)#OzUd$)Yvk{8+IIU-f6p@ z-gh86=--(0|CA>FoqGS}4hp>zF4e^_n>wGY&T`c-kRT_m`~-2+I3-0ZkBUxb^+Y1b z9K${9HKG_xd#oO(~nncwyHvRHy$_E3GOP#nTfjm>Xy8=7VM844DSrv+>-p(!5bdG2ygd(Qw$+H3>jc_& zhATD9`4*2jR{)J{u}X8VL0lO1(H>ebno~nHi2Y z;@Wsa=RKXxHU@1@A^GG0yZMvrqHYZGkA}T*e|S~p#h|EsOHw2+1p|&;TassezH0D7 z&dbz;Ve&>1Tflr~5U03O)gpNm!fvD}*=ee&`%!PR9%iFObm8lys~YatR%evw@qfhH z<^8*+rlVXLn3Dfgw(g;KRKGe!>M|gXdeWAj!tp^sv{mvnjmEC1(}W4STX%^cu5EsxsUVWx&FC{XvS(O;ZW=0 zP*;=n%TsA-#=oywE5D!lIq#qJ_cR;peQm$5?e|LlJD7I)zM;Qw=z-`dzZ@7w2Wcfj1n#@WVZ_$}P)pA4d7 zFcD!X|JvaGlOKf|gS~&dLVQGYXk7f6==1;DM)h-cE4IR?A9FD|J(6n5y_!Zrw(e)d@e2`<{ZS<)^4B0ZrjJnb^m)YzrPo=+h^}! WvD+<3X{sp(K^^isSowAE5B~w^zNfVS diff --git a/src/Core/src/Handlers/ScrollView/ScrollViewHandler.iOS.cs b/src/Core/src/Handlers/ScrollView/ScrollViewHandler.iOS.cs index c8e7d6620fba..36debcf218b8 100644 --- a/src/Core/src/Handlers/ScrollView/ScrollViewHandler.iOS.cs +++ b/src/Core/src/Handlers/ScrollView/ScrollViewHandler.iOS.cs @@ -83,14 +83,7 @@ public static void MapOrientation(IScrollViewHandler handler, IScrollView scroll return; } - if (scrollView.Orientation == ScrollOrientation.Neither) - { - platformView.ScrollEnabled = false; - } - else - { - platformView.ScrollEnabled = true; - } + platformView.UpdateIsEnabled(scrollView); platformView.InvalidateMeasure(scrollView); } From 62b699e8a3175138994c33ddb19d092e7ee8ad75 Mon Sep 17 00:00:00 2001 From: SuthiYuvaraj <92777079+SuthiYuvaraj@users.noreply.github.com> Date: Wed, 9 Apr 2025 01:14:29 +0530 Subject: [PATCH 27/34] Revert "Fix HideSoftInputOnTapped Not Working Net9 (#28534)" (#28802) This reverts commit f3ec03b253f0b5cd8428bfa7e84bcb23ed2eb483. --- ...SoftInputOnTappedChangedManager.Android.cs | 2 +- ...oftInputOnTappedChangedManager.Platform.cs | 2 +- .../HideSoftInputOnTappedChangedManager.cs | 2 +- .../TestCases.HostApp/Issues/Issue26792.cs | 40 ------------------- .../Tests/Issues/Issue26792.cs | 29 -------------- 5 files changed, 3 insertions(+), 72 deletions(-) delete mode 100644 src/Controls/tests/TestCases.HostApp/Issues/Issue26792.cs delete mode 100644 src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26792.cs diff --git a/src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.Android.cs b/src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.Android.cs index 3501898dcfcf..3dc75e168a60 100644 --- a/src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.Android.cs +++ b/src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.Android.cs @@ -20,7 +20,7 @@ void OnWindowDispatchedTouch(object? sender, MotionEvent? e) foreach (var page in _contentPages) { - if ((page.HasNavigatedTo || page.Parent is Window) && + if (page.HasNavigatedTo && page.HideSoftInputOnTapped && page.Handler is IPlatformViewHandler pvh && pvh.MauiContext?.Context is not null) diff --git a/src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.Platform.cs b/src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.Platform.cs index 45b49052c65b..b5ed8c838a64 100644 --- a/src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.Platform.cs +++ b/src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.Platform.cs @@ -14,7 +14,7 @@ partial class HideSoftInputOnTappedChangedManager internal void UpdatePage(ContentPage page) { - if (page.HideSoftInputOnTapped && (page.HasNavigatedTo || page.Parent is Window)) + if (page.HideSoftInputOnTapped && page.HasNavigatedTo) { if (!_contentPages.Contains(page)) { diff --git a/src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.cs b/src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.cs index 17f1c41e75d7..1f369165f5f8 100644 --- a/src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.cs +++ b/src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.cs @@ -13,7 +13,7 @@ bool FeatureEnabled { foreach (var page in _contentPages) { - if (page.HideSoftInputOnTapped && (page.HasNavigatedTo || page.Parent is Window)) + if (page.HideSoftInputOnTapped && page.HasNavigatedTo) return true; } return false; diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue26792.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue26792.cs deleted file mode 100644 index cb4045de9468..000000000000 --- a/src/Controls/tests/TestCases.HostApp/Issues/Issue26792.cs +++ /dev/null @@ -1,40 +0,0 @@ -namespace Maui.Controls.Sample.Issues; - -[Issue(IssueTracker.Github, 26792, "HideSoftInputOnTapped Not Working", PlatformAffected.Android)] -public class Issue26792 : ContentPage -{ - - VerticalStackLayout stackLayout; - Button _button; - - Entry _entry; - public Issue26792() - { - this.HideSoftInputOnTapped = true; - stackLayout = new VerticalStackLayout - { - HorizontalOptions = LayoutOptions.Center, - VerticalOptions = LayoutOptions.Center, - AutomationId = "Issue26792StackLayout", - }; - _button = new Button - { - Text = "Click Me", - AutomationId = "Issue26792Button", - HorizontalOptions = LayoutOptions.Center, - VerticalOptions = LayoutOptions.Center, - }; - _entry = new Entry - { - Placeholder = "Enter text", - AutomationId = "Issue26792Entry", - HorizontalOptions = LayoutOptions.Center, - VerticalOptions = LayoutOptions.Center, - }; - - stackLayout.Children.Add(_button); - stackLayout.Children.Add(_entry); - Content = stackLayout; - } -} - diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26792.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26792.cs deleted file mode 100644 index 88bd8968731c..000000000000 --- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26792.cs +++ /dev/null @@ -1,29 +0,0 @@ -#if TEST_FAILS_ON_CATALYST && TEST_FAILS_ON_WINDOWS //As SoftKeyboard is not supported -using NUnit.Framework; -using UITest.Appium; -using UITest.Core; - -namespace Microsoft.Maui.TestCases.Tests.Issues; - -public class Issue26792 : _IssuesUITest -{ - public Issue26792(TestDevice testDevice) : base(testDevice) - { - } - - public override string Issue => "HideSoftInputOnTapped Not Working"; - - [Test] - [Category(UITestCategories.Page)] - public void SoftInputShouldHiddenOnTap() - { - App.WaitForElement("Issue26792Entry"); - App.Tap("Issue26792Entry"); - App.WaitForElement("Issue26792Button"); - App.Tap("Issue26792Button"); - App.WaitForElement("Issue26792Entry"); - Assert.That(App.IsKeyboardShown(), Is.False); - - } -} -#endif From 7e09fc725455871cb1c8b304bf9aa3b70da5db81 Mon Sep 17 00:00:00 2001 From: Vignesh-SF3580 <102575140+Vignesh-SF3580@users.noreply.github.com> Date: Thu, 10 Apr 2025 19:43:04 +0530 Subject: [PATCH 28/34] Fixed testcase failures in PR28867. (#28889) --- .../src/Handlers/ScrollView/ScrollViewHandler.Windows.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Windows.cs b/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Windows.cs index 1a6752f2e4a0..1bfe2081418e 100644 --- a/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Windows.cs +++ b/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Windows.cs @@ -67,7 +67,11 @@ public static void MapVerticalScrollBarVisibility(IScrollViewHandler handler, IS public static void MapOrientation(IScrollViewHandler handler, IScrollView scrollView) { - handler.PlatformView?.UpdateScrollBarVisibility(scrollView.Orientation, scrollView.HorizontalScrollBarVisibility); + var scrollBarVisibility = scrollView.Orientation == ScrollOrientation.Horizontal + ? scrollView.HorizontalScrollBarVisibility + : scrollView.VerticalScrollBarVisibility; + + handler.PlatformView?.UpdateScrollBarVisibility(scrollView.Orientation, scrollBarVisibility); } public static void MapRequestScrollTo(IScrollViewHandler handler, IScrollView scrollView, object? args) From 767307c592550e4699c9fb94c46a18277d7734ab Mon Sep 17 00:00:00 2001 From: LogishaSelvarajSF4525 Date: Mon, 14 Apr 2025 18:59:01 +0530 Subject: [PATCH 29/34] [Testing] Feature Matrix UITest Cases for CollectionView Header/Footer Feature (#28938) * Added feature tests for Header/Footer * added test cases * update the test cases * update the changes * modified * updated the test cases * update the changes * update the changes * updated the UI and Test cases * Updated test cases * add fails attributes * updated * modified changes * updated changes * renamed --- .../CoreViews/CorePageView.cs | 1 + .../CollectionViewControlPage.xaml | 28 + .../CollectionViewControlPage.xaml.cs | 26 + .../CollectionViewOptionsPage.xaml | 275 +++ .../CollectionViewOptionsPage.xaml.cs | 278 +++ .../CollectionView/CollectionViewViewModel.cs | 293 +++ .../CollectionView/HeaderFooterMainPage.xaml | 15 + .../HeaderFooterMainPage.xaml.cs | 26 + ...CollectionView_HeaderFooterFeatureTests.cs | 1762 +++++++++++++++++ 9 files changed, 2704 insertions(+) create mode 100644 src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewControlPage.xaml create mode 100644 src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewControlPage.xaml.cs create mode 100644 src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewOptionsPage.xaml create mode 100644 src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewOptionsPage.xaml.cs create mode 100644 src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewViewModel.cs create mode 100644 src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/HeaderFooterMainPage.xaml create mode 100644 src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/HeaderFooterMainPage.xaml.cs create mode 100644 src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_HeaderFooterFeatureTests.cs diff --git a/src/Controls/tests/TestCases.HostApp/CoreViews/CorePageView.cs b/src/Controls/tests/TestCases.HostApp/CoreViews/CorePageView.cs index 9f2fc6c54f1a..61d2bfa29c0c 100644 --- a/src/Controls/tests/TestCases.HostApp/CoreViews/CorePageView.cs +++ b/src/Controls/tests/TestCases.HostApp/CoreViews/CorePageView.cs @@ -77,6 +77,7 @@ public override string ToString() new GalleryPageFactory(() => new TimePickerCoreGalleryPage(), "Time Picker Gallery"), new GalleryPageFactory(() => new WebViewCoreGalleryPage(), "WebView Gallery"), new GalleryPageFactory(() => new SliderControlPage(), "Slider Feature Matrix"), + new GalleryPageFactory(() => new HeaderFooterMainPage(), "CollectionView Feature Matrix"), }; public CorePageView(Page rootPage) diff --git a/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewControlPage.xaml b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewControlPage.xaml new file mode 100644 index 000000000000..5c49a597e156 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewControlPage.xaml @@ -0,0 +1,28 @@ + + + + + + + + \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewControlPage.xaml.cs b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewControlPage.xaml.cs new file mode 100644 index 000000000000..27e08b4408c5 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewControlPage.xaml.cs @@ -0,0 +1,26 @@ +using System; +using Microsoft.Maui.Controls; +using System.Collections.ObjectModel; + +namespace Maui.Controls.Sample +{ + public partial class CollectionViewControlPage : ContentPage + { + private CollectionViewViewModel _viewModel; + + public CollectionViewControlPage() + { + InitializeComponent(); + _viewModel = new CollectionViewViewModel(); + _viewModel.ItemsSourceType = ItemsSourceType.ObservableCollection5T; + BindingContext = _viewModel; + } + + private async void NavigateToOptionsPage_Clicked(object sender, EventArgs e) + { + BindingContext = _viewModel = new CollectionViewViewModel(); + _viewModel.ItemsSourceType = ItemsSourceType.ObservableCollection5T; + await Navigation.PushAsync(new CollectionViewOptionsPage(_viewModel)); + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewOptionsPage.xaml b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewOptionsPage.xaml new file mode 100644 index 000000000000..7460999f5a1e --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewOptionsPage.xaml @@ -0,0 +1,275 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewOptionsPage.xaml.cs b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewOptionsPage.xaml.cs new file mode 100644 index 000000000000..ccf26c04cc54 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewOptionsPage.xaml.cs @@ -0,0 +1,278 @@ +using System; +using Microsoft.Maui.Controls; +using System.Collections.ObjectModel; +using Maui.Controls.Sample.CollectionViewGalleries; + +namespace Maui.Controls.Sample +{ + public partial class CollectionViewOptionsPage : ContentPage + { + private CollectionViewViewModel _viewModel; + + public CollectionViewOptionsPage(CollectionViewViewModel viewModel) + { + InitializeComponent(); + _viewModel = viewModel; + BindingContext = _viewModel; + } + + private void ApplyButton_Clicked(object sender, EventArgs e) + { + Navigation.PopAsync(); + } + + private void OnEmptyViewChanged(object sender, CheckedChangedEventArgs e) + { + if (EmptyViewNone.IsChecked) + { + _viewModel.EmptyView = null; + } + else if (EmptyViewString.IsChecked) + { + _viewModel.EmptyView = "No Items Available(String)"; + } + } + + private void OnHeaderChanged(object sender, CheckedChangedEventArgs e) + { + if (HeaderNone.IsChecked) + { + _viewModel.Header = null; + } + else if (HeaderString.IsChecked) + { + _viewModel.Header = "CollectionView Header(String)"; + } + else if (HeaderGrid.IsChecked) + { + Grid grid = new Grid + { + BackgroundColor = Colors.LightGray, + Padding = new Thickness(10) + }; + grid.Children.Add(new Label + { + Text = "CollectionView Header(Grid View)", + FontSize = 18, + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + TextColor = Colors.Blue, + AutomationId = "HeaderViewLabel" + }); + _viewModel.Header = grid; + } + } + + private void OnFooterChanged(object sender, CheckedChangedEventArgs e) + { + if (FooterNone.IsChecked) + { + _viewModel.Footer = null; + } + else if (FooterString.IsChecked) + { + _viewModel.Footer = "CollectionView Footer(String)"; + } + else if (FooterGrid.IsChecked) + { + Grid grid = new Grid + { + BackgroundColor = Colors.LightGray, + Padding = new Thickness(10) + }; + grid.Children.Add(new Label + { + Text = "CollectionView Footer(Grid View)", + FontSize = 18, + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + TextColor = Colors.Red, + AutomationId = "FooterViewLabel" + }); + _viewModel.Footer = grid; + } + } + + private void OnHeaderTemplateChanged(object sender, CheckedChangedEventArgs e) + { + if (HeaderTemplateNone.IsChecked) + { + _viewModel.HeaderTemplate = null; + } + else if (HeaderTemplateGrid.IsChecked) + { + _viewModel.HeaderTemplate = new DataTemplate(() => + { + Grid grid = new Grid + { + BackgroundColor = Colors.LightGray, + Padding = new Thickness(10) + }; + grid.Children.Add(new Label + { + Text = "Header Template(Grid View)", + FontSize = 18, + FontAttributes = FontAttributes.Bold, + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + TextColor = Colors.Blue, + AutomationId = "HeaderTemplateLabel" + }); + return grid; + }); + } + } + + private void OnFooterTemplateChanged(object sender, CheckedChangedEventArgs e) + { + if (FooterTemplateNone.IsChecked) + { + _viewModel.FooterTemplate = null; + } + else if (FooterTemplateGrid.IsChecked) + { + _viewModel.FooterTemplate = new DataTemplate(() => + { + Grid grid = new Grid + { + BackgroundColor = Colors.LightGray, + Padding = new Thickness(10) + }; + grid.Children.Add(new Label + { + Text = "Footer Template(Grid View)", + FontSize = 18, + FontAttributes = FontAttributes.Bold, + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + TextColor = Colors.Green, + AutomationId = "FooterTemplateLabel" + }); + return grid; + }); + } + } + + private void OnGroupHeaderTemplateChanged(object sender, CheckedChangedEventArgs e) + { + if (GroupHeaderTemplateNone.IsChecked) + { + _viewModel.GroupHeaderTemplate = null; + } + else if (GroupHeaderTemplateGrid.IsChecked) + { + _viewModel.GroupHeaderTemplate = new DataTemplate(() => + { + Grid grid = new Grid + { + BackgroundColor = Colors.LightGray, + Padding = new Thickness(10) + }; + grid.Children.Add(new Label + { + Text = "Group Header Template(Grid View)", + FontSize = 18, + FontAttributes = FontAttributes.Bold, + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + TextColor = Colors.Green, + AutomationId = "GroupHeaderTemplateLabel" + }); + return grid; + }); + } + } + private void OnGroupFooterTemplateChanged(object sender, CheckedChangedEventArgs e) + { + if (GroupFooterTemplateNone.IsChecked) + { + _viewModel.GroupFooterTemplate = null; + } + else if (GroupFooterTemplateGrid.IsChecked) + { + _viewModel.GroupFooterTemplate = new DataTemplate(() => + { + Grid grid = new Grid + { + BackgroundColor = Colors.LightGray, + Padding = new Thickness(10) + }; + grid.Children.Add(new Label + { + Text = "Group Footer Template(Grid View)", + FontSize = 18, + FontAttributes = FontAttributes.Bold, + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + TextColor = Colors.Red, + AutomationId = "GroupFooterTemplateLabel" + }); + return grid; + }); + } + } + private void OnIsGroupedChanged(object sender, CheckedChangedEventArgs e) + { + if (IsGroupedFalse.IsChecked) + { + _viewModel.IsGrouped = false; + } + else if (IsGroupedTrue.IsChecked) + { + _viewModel.IsGrouped = true; + } + } + + private void OnItemTemplateChanged(object sender, CheckedChangedEventArgs e) + { + if (ItemTemplateNone.IsChecked) + { + _viewModel.ItemTemplate = null; + } + else if (ItemTemplateBasic.IsChecked) + { + _viewModel.ItemTemplate = new DataTemplate(() => + { + var label = new Label(); + label.SetBinding(Label.TextProperty, new Binding("Caption")); + + return label; + }); + } + } + + private void OnItemsLayoutChanged(object sender, CheckedChangedEventArgs e) + { + if (ItemsLayoutVerticalList.IsChecked) + { + _viewModel.ItemsLayout = new LinearItemsLayout(ItemsLayoutOrientation.Vertical); + } + else if (ItemsLayoutHorizontalList.IsChecked) + { + _viewModel.ItemsLayout = new LinearItemsLayout(ItemsLayoutOrientation.Horizontal); + } + else if (ItemsLayoutVerticalGrid.IsChecked) + { + _viewModel.ItemsLayout = new GridItemsLayout(2, ItemsLayoutOrientation.Vertical); // 2 columns + } + else if (ItemsLayoutHorizontalGrid.IsChecked) + { + _viewModel.ItemsLayout = new GridItemsLayout(2, ItemsLayoutOrientation.Horizontal); // 2 rows + } + } + + private void OnItemsSourceChanged(object sender, CheckedChangedEventArgs e) + { + if (!(sender is RadioButton radioButton) || !e.Value) + return; + if (radioButton == ItemsSourceObservableCollection25) + _viewModel.ItemsSourceType = ItemsSourceType.ObservableCollection25T; + else if (radioButton == ItemsSourceObservableCollection5) + _viewModel.ItemsSourceType = ItemsSourceType.ObservableCollection5T; + else if (radioButton == ItemsSourceGroupedList) + _viewModel.ItemsSourceType = ItemsSourceType.GroupedListT; + else if (radioButton == ItemsSourceNone) + _viewModel.ItemsSourceType = ItemsSourceType.None; + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewViewModel.cs b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewViewModel.cs new file mode 100644 index 000000000000..76d61f1ed6f3 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/CollectionViewViewModel.cs @@ -0,0 +1,293 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; +using System.Runtime.CompilerServices; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Graphics; +using Maui.Controls.Sample.CollectionViewGalleries; + +namespace Maui.Controls.Sample +{ + public class Grouping : ObservableCollection + { + public TKey Key { get; } + + public Grouping(TKey key, IEnumerable items) : base(items) + { + Key = key; + } + } + + public enum ItemsSourceType + { + None, + ObservableCollection25T, + ObservableCollection5T, + GroupedListT, + EmptyGroupedListT, + EmptyObservableCollectionT + } + public class CollectionViewViewModel : INotifyPropertyChanged + { + private object _emptyView; + private object _header; + private object _footer; + private DataTemplate _emptyViewTemplate; + private DataTemplate _headerTemplate; + private DataTemplate _footerTemplate; + private DataTemplate _groupHeaderTemplate; + private DataTemplate _groupFooterTemplate; + private DataTemplate _itemTemplate; + private IItemsLayout _itemsLayout = new LinearItemsLayout(ItemsLayoutOrientation.Vertical); + private ItemsSourceType _itemsSourceType = ItemsSourceType.None; + private bool _isGrouped = false; + private ObservableCollection _observableCollection25; + private ObservableCollection _observableCollection5; + private ObservableCollection _emptyObservableCollection; + private List> _groupedList; + private List> _emptyGroupedList; + public event PropertyChangedEventHandler PropertyChanged; + + public CollectionViewViewModel() + { + LoadItems(); + ItemTemplate = new DataTemplate(() => + { + var stackLayout = new StackLayout + { + Padding = new Thickness(10), + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center + }; + + var label = new Label + { + VerticalOptions = LayoutOptions.Center, + HorizontalOptions = LayoutOptions.Center + }; + label.SetBinding(Label.TextProperty, "Caption"); + stackLayout.Children.Add(label); + return stackLayout; + }); + + GroupHeaderTemplate = new DataTemplate(() => + { + var stackLayout = new StackLayout + { + BackgroundColor = Colors.LightGray + }; + var label = new Label + { + FontAttributes = FontAttributes.Bold, + FontSize = 18 + }; + label.SetBinding(Label.TextProperty, "Key"); + stackLayout.Children.Add(label); + return stackLayout; + }); + } + + public object EmptyView + { + get => _emptyView; + set { _emptyView = value; OnPropertyChanged(); } + } + + public object Header + { + get => _header; + set { _header = value; OnPropertyChanged(); } + } + + public object Footer + { + get => _footer; + set { _footer = value; OnPropertyChanged(); } + } + + public DataTemplate EmptyViewTemplate + { + get => _emptyViewTemplate; + set { _emptyViewTemplate = value; OnPropertyChanged(); } + } + + public DataTemplate HeaderTemplate + { + get => _headerTemplate; + set { _headerTemplate = value; OnPropertyChanged(); } + } + + public DataTemplate FooterTemplate + { + get => _footerTemplate; + set { _footerTemplate = value; OnPropertyChanged(); } + } + + public DataTemplate GroupHeaderTemplate + { + get => _groupHeaderTemplate; + set { _groupHeaderTemplate = value; OnPropertyChanged(); } + } + + public DataTemplate GroupFooterTemplate + { + get => _groupFooterTemplate; + set { _groupFooterTemplate = value; OnPropertyChanged(); } + } + + public DataTemplate ItemTemplate + { + get => _itemTemplate; + set { _itemTemplate = value; OnPropertyChanged(); } + } + + public IItemsLayout ItemsLayout + { + get => _itemsLayout; + set + { + if (_itemsLayout != value) + { + _itemsLayout = value; + OnPropertyChanged(); + } + } + } + + public ItemsSourceType ItemsSourceType + { + get => _itemsSourceType; + set + { + if (_itemsSourceType != value) + { + _itemsSourceType = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(ItemsSource)); + } + } + } + + public bool IsGrouped + { + get => _isGrouped; + set + { + if (_isGrouped != value) + { + _isGrouped = value; + OnPropertyChanged(); + } + } + } + + public object ItemsSource + { + get + { + return ItemsSourceType switch + { + ItemsSourceType.ObservableCollection25T => _observableCollection25, + ItemsSourceType.ObservableCollection5T => _observableCollection5, + ItemsSourceType.GroupedListT => _groupedList, + ItemsSourceType.EmptyGroupedListT => _emptyGroupedList, + ItemsSourceType.EmptyObservableCollectionT => _emptyObservableCollection, + ItemsSourceType.None => null, + _ => null + }; + } + } + + + private void LoadItems() + { + _observableCollection25 = new ObservableCollection(); + _observableCollection5 = new ObservableCollection(); + AddItems(_observableCollection5, 5, "Fruits"); + AddItems(_observableCollection25, 10, "Fruits"); + AddItems(_observableCollection25, 10, "Vegetables"); + + _emptyObservableCollection = new ObservableCollection(); + + _groupedList = new List> + { + new Grouping("Fruits", new List()), + new Grouping("Vegetables", new List()) + }; + + AddItems(_groupedList[0], 4, "Fruits"); + AddItems(_groupedList[1], 4, "Vegetables"); + + _emptyGroupedList = new List>(); + } + + + private void AddItems(IList list, int count, string category) + { + string[] fruits = + { + "Apple", "Banana", "Orange", "Grapes", "Mango", + "Pineapple", "Strawberry", "Blueberry", "Peach", "Cherry", + "Watermelon", "Papaya", "Kiwi", "Pear", "Plum", + "Avocado", "Fig", "Guava", "Lychee", "Pomegranate", + "Lime", "Lemon", "Coconut", "Apricot", "Blackberry" + }; + + string[] vegetables = + { + "Carrot", "Broccoli", "Spinach", "Potato", "Tomato", + "Cucumber", "Lettuce", "Onion", "Garlic", "Pepper", + "Zucchini", "Pumpkin", "Radish", "Beetroot", "Cabbage", + "Sweet Potato", "Turnip", "Cauliflower", "Celery", "Asparagus", + "Eggplant", "Chili", "Corn", "Peas", "Mushroom" + }; + + string[] items = category == "Fruits" ? fruits : vegetables; + + for (int n = 0; n < count; n++) + { + list.Add(new CollectionViewTestItem(items[n % items.Length], n)); // Pass the index + } + } + + protected void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + if (propertyName == nameof(IsGrouped)) + { + OnPropertyChanged(nameof(ItemsSource)); + } + + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + public class CustomDataTemplateSelector : DataTemplateSelector + { + public DataTemplate Template1 { get; set; } + public DataTemplate Template2 { get; set; } + + protected override DataTemplate OnSelectTemplate(object item, BindableObject container) + { + if (item is CollectionViewTestItem testItem) + { + return testItem.Index % 2 == 0 ? Template1 : Template2; + } + + return Template1; + } + } + + public class CollectionViewTestItem + { + public string Caption { get; set; } + public int Index { get; set; } + + public CollectionViewTestItem(string caption, int index) + { + Caption = caption; + Index = index; + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/HeaderFooterMainPage.xaml b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/HeaderFooterMainPage.xaml new file mode 100644 index 000000000000..c98e25007ce5 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/FeatureMatrix/CollectionView/HeaderFooterMainPage.xaml @@ -0,0 +1,15 @@ + + + +