Skip to content

Commit 4b3c01f

Browse files
committed
Merge branch 'main' into dev/gif-in-release
2 parents 595ff03 + e94b364 commit 4b3c01f

103 files changed

Lines changed: 1310 additions & 641 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/ReleasePlanning.md

Lines changed: 2 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,3 @@
1-
Throughout the year we add issues to the `Backlog` milestone as is pointed out in our [Triage Process](TriageProcess.md).
2-
We review all the issues in that milestone once a year, after the work on an upcoming major release is complete.
3-
Given the large number of issues, it takes multiple sessions for teams to review and identify candidates for consideration for the next major release.
4-
This document details the process we use for identifying candidate issues for the next release.
1+
# .NET MAUI Roadmap
52

6-
## Phases
7-
The process for identifying candidates for the next major release consists of multiple phases. In each phase, we filter issues out of the release by either moving them to the `Backlog`, or closing the issue.
8-
- Filtering & Individual prioritization
9-
- Rough costing
10-
- Team review & Priority adjustment
11-
- Capacity planning
12-
- Define the cut line
13-
14-
### Filtering
15-
At this stage all the issues are distributed to engineers by feature areas. Each engineer reviews all the issues within their feature area, and returns to the next meeting with individual priority labels assigned - fl-p1, fl-p2, fl-p3, where `fl` are their initials.
16-
17-
All the issues which the engineer believes are lower than `Priority-3` - remain in the backlog. We also agree to approximately balance the distribution of the 3 priority labels on the issues that will be brought back by each engineer, so that it forces real prioritization exercise.
18-
The issues which engineers think are good candidates and fit in the above listed requirements are moved to the `.NET V Planning` milestone, where `V` is the upcoming version number.
19-
20-
### Rough costing
21-
At this phase engineers apply rough cost estimates to the final list of issues that they have moved to the `.NET V Planning` milestone, by applying one of the `Cost: X` labels below, where `X` is the size:
22-
23-
| **Label** | **Description** |
24-
|--------------|---------------------------------------------------|
25-
| **Cost: S** | Work that requires one engineer up to 1 week |
26-
| **Cost: M** | Work that requires one engineer up to 2 weeks |
27-
| **Cost: L** | Work that requires one engineer up to 4 weeks |
28-
| **Cost: XL** | Work that requires one engineer more than 4 weeks |
29-
30-
This will be used later during the planning process.
31-
32-
For issues which don't have a clear description of the associated work, it's important to drop a comment summarizing the work involved. This will help at a later time, in case a question about the cost will be raised.
33-
34-
**Note**: while costing issues, it's important to reevaluate costs for those, which already have cost labels applied. Those are most probably from the past and may be outdated, not properly representing the cost any more.
35-
36-
### Team Review & Priority adjustment
37-
Now, that all the issues are in the `.NET V planning` milestone, the team reviews each issue one at a time starting from the highest priority ones (Priority: 1).
38-
We discuss the issues and agree on the priority at this point. Sometimes we make adjustments to the suggested individual priorities. After discussing each issue the `Priority: X` label is applied to each issue.
39-
Each `Priority: 1` issue is then moved to the project board, which will be used by each team for tracking the work for the upcoming release throughout the year. The issues start off in the `Triage` column. At this point we bring only the top priority issues to the board.
40-
41-
### Capacity Planning
42-
We usually reserve only 50% of the team capacity for this work. The reason is that we will be getting a lot of incoming feedback throughout the year and we need to allocate time for handling this feedback throughout the year.
43-
So we calculate the capacity of the team in weeks for the upcoming year and use half of the final number later in this process.
44-
45-
### Define the cut line
46-
At this point we have all the candidate issues that we think are worth considering for the upcoming release. This number is quite large, so the teams usually won't have enough capacity to handle all this.
47-
We start stack ranking issues so the most important work remains on the top of the list. We then draw the cut line and that defines the rough list of things the team will work on during the upcoming release.
3+
[Roadmap](https://github.com/dotnet/maui/wiki/Roadmap)

docs/ReleaseSchedule.md

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,3 @@
11
# .NET MAUI Release Schedule Information
22

3-
Versions of .NET MAUI are being released in sync with new .NET versions. More information on the .NET release policy can be found [here](https://dotnet.microsoft.com/platform/support/policy/dotnet-core).
4-
5-
## Past .NET MAUI Releases
6-
7-
Below you can find a list of all the previous releases of .NET MAUI, excluding pre-releases.
8-
For a full list, including release notes, please refer to our [Releases page](https://github.com/dotnet/maui/releases).
9-
10-
| Version | Release Date |
11-
|---------|--------------|
12-
| [6.0.536 (Service Release 4.1)](https://github.com/dotnet/maui/releases/tag/6.0.536) | 2022/09/14 |
13-
| [6.0.486 (Service Release 4)](https://github.com/dotnet/maui/releases/tag/6.0.486) | 2022/08/09 |
14-
| [6.0.424 (Service Release 3.1)](https://github.com/dotnet/maui/releases/tag/6.0.424) | 2022/08/01 |
15-
| [6.0.419 (Service Release 3)](https://github.com/dotnet/maui/releases/tag/6.0.419) | 2022/07/20 |
16-
| [6.0.408 (Service Release 2)](https://github.com/dotnet/maui/releases/tag/6.0.408) | 2022/07/12 |
17-
| [6.0.400](https://github.com/dotnet/maui/releases/tag/6.0.400) | 2022/06/14 |
18-
| [6.0.312](https://github.com/dotnet/maui/releases/tag/6.0.312) | 2022/05/23 |
3+
[Release Versions](https://github.com/dotnet/maui/wiki/Release-Versions)

eng/Versions.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project>
22
<PropertyGroup>
33
<!-- The .NET product branding version -->
4-
<ProductVersion>8.0.60</ProductVersion>
4+
<ProductVersion>8.0.70</ProductVersion>
55
<MajorVersion>8</MajorVersion>
66
<MinorVersion>0</MinorVersion>
77
<PatchVersion>60</PatchVersion>

eng/scripts/appium-install.ps1

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,15 @@ if (!(Test-Path $logsDir -PathType Container)) {
6767
$AppiumHome = $env:APPIUM_HOME
6868
Write-Output "APPIUM_HOME: $AppiumHome"
6969

70-
if (Test-Path $AppiumHome) {
71-
Write-Output "Removing existing APPIUM_HOME Cache..."
72-
Remove-Item -Path $AppiumHome -Recurse -Force
73-
}
70+
if ($AppiumHome) {
71+
if (Test-Path $AppiumHome) {
72+
Write-Output "Removing existing APPIUM_HOME Cache..."
73+
Remove-Item -Path $AppiumHome -Recurse -Force
74+
}
7475

75-
# Create the directory for appium home
76-
New-Item -ItemType Directory -Path $AppiumHome
76+
# Create the directory for appium home
77+
New-Item -ItemType Directory -Path $AppiumHome
78+
}
7779

7880
# Check for an existing appium install version
7981
$appiumCurrentVersion = ""

src/Controls/src/Core/Compatibility/iOS/Extensions/ToolbarItemExtensions.cs

Lines changed: 66 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#nullable disable
2+
using System;
23
using System.ComponentModel;
34
using CoreGraphics;
45
using ObjCRuntime;
@@ -26,20 +27,20 @@ public static UIBarButtonItem ToUIBarButtonItem(this ToolbarItem item, bool forc
2627
sealed class PrimaryToolbarItem : UIBarButtonItem
2728
{
2829
readonly bool _forceName;
29-
readonly ToolbarItem _item;
30+
readonly WeakReference<ToolbarItem> _item;
3031

3132
public PrimaryToolbarItem(ToolbarItem item, bool forceName)
3233
{
3334
_forceName = forceName;
34-
_item = item;
35+
_item = new(item);
3536

3637
if (item.IconImageSource != null && !item.IconImageSource.IsEmpty && !forceName)
37-
UpdateIconAndStyle();
38+
UpdateIconAndStyle(item);
3839
else
39-
UpdateTextAndStyle();
40-
UpdateIsEnabled();
40+
UpdateTextAndStyle(item);
41+
UpdateIsEnabled(item);
4142

42-
Clicked += (sender, e) => ((IMenuItemController)_item).Activate();
43+
Clicked += OnClicked;
4344
item.PropertyChanged += OnPropertyChanged;
4445

4546
if (item != null && !string.IsNullOrEmpty(item.AutomationId))
@@ -49,65 +50,76 @@ public PrimaryToolbarItem(ToolbarItem item, bool forceName)
4950
this.SetAccessibilityLabel(item);
5051
}
5152

53+
void OnClicked (object sender, EventArgs e)
54+
{
55+
if (_item.TryGetTarget(out var item))
56+
{
57+
((IMenuItemController)item).Activate();
58+
}
59+
}
60+
5261
protected override void Dispose(bool disposing)
5362
{
54-
if (disposing)
55-
_item.PropertyChanged -= OnPropertyChanged;
63+
if (disposing && _item.TryGetTarget(out var item))
64+
item.PropertyChanged -= OnPropertyChanged;
5665
base.Dispose(disposing);
5766
}
5867

5968
void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
6069
{
70+
if (!_item.TryGetTarget(out var item))
71+
return;
72+
6173
if (e.PropertyName == MenuItem.IsEnabledProperty.PropertyName)
62-
UpdateIsEnabled();
74+
UpdateIsEnabled(item);
6375
else if (e.PropertyName == MenuItem.TextProperty.PropertyName)
6476
{
65-
if (_item.IconImageSource == null || _item.IconImageSource.IsEmpty || _forceName)
66-
UpdateTextAndStyle();
77+
if (item.IconImageSource == null || item.IconImageSource.IsEmpty || _forceName)
78+
UpdateTextAndStyle(item);
6779
}
6880
else if (e.PropertyName == MenuItem.IconImageSourceProperty.PropertyName)
6981
{
7082
if (!_forceName)
7183
{
72-
if (_item.IconImageSource != null && !_item.IconImageSource.IsEmpty)
73-
UpdateIconAndStyle();
84+
if (item.IconImageSource != null && !item.IconImageSource.IsEmpty)
85+
UpdateIconAndStyle(item);
7486
else
75-
UpdateTextAndStyle();
87+
UpdateTextAndStyle(item);
7688
}
7789
}
7890
#pragma warning disable CS0618 // Type or member is obsolete
7991
else if (e.PropertyName == AutomationProperties.HelpTextProperty.PropertyName)
80-
this.SetAccessibilityHint(_item);
92+
this.SetAccessibilityHint(item);
8193
else if (e.PropertyName == AutomationProperties.NameProperty.PropertyName)
82-
this.SetAccessibilityLabel(_item);
94+
this.SetAccessibilityLabel(item);
8395
#pragma warning restore CS0618 // Type or member is obsolete
8496
}
8597

86-
void UpdateIconAndStyle()
98+
void UpdateIconAndStyle(ToolbarItem item)
8799
{
88-
if (_item?.IconImageSource == null)
100+
if (item?.IconImageSource == null)
89101
{
90102
Image = null;
91103
Style = UIBarButtonItemStyle.Plain;
92104
}
93105
else
94106
{
95-
_item.IconImageSource.LoadImage(_item.FindMauiContext(), result =>
107+
item.IconImageSource.LoadImage(item.FindMauiContext(), result =>
96108
{
97109
Image = result?.Value;
98110
Style = UIBarButtonItemStyle.Plain;
99111
});
100112
}
101113
}
102114

103-
void UpdateIsEnabled()
115+
void UpdateIsEnabled(ToolbarItem item)
104116
{
105-
Enabled = _item.IsEnabled;
117+
Enabled = item.IsEnabled;
106118
}
107119

108-
void UpdateTextAndStyle()
120+
void UpdateTextAndStyle(ToolbarItem item)
109121
{
110-
Title = _item.Text;
122+
Title = item.Text;
111123
#pragma warning disable CA1416, CA1422 // TODO: [UnsupportedOSPlatform("ios8.0")]
112124
Style = UIBarButtonItemStyle.Bordered;
113125
#pragma warning restore CA1416, CA1422
@@ -117,16 +129,16 @@ void UpdateTextAndStyle()
117129

118130
sealed class SecondaryToolbarItem : UIBarButtonItem
119131
{
120-
readonly ToolbarItem _item;
132+
readonly WeakReference<ToolbarItem> _item;
121133

122134
public SecondaryToolbarItem(ToolbarItem item) : base(new SecondaryToolbarItemContent())
123135
{
124-
_item = item;
125-
UpdateText();
126-
UpdateIcon();
127-
UpdateIsEnabled();
136+
_item = new(item);
137+
UpdateText(item);
138+
UpdateIcon(item);
139+
UpdateIsEnabled(item);
128140

129-
((SecondaryToolbarItemContent)CustomView).TouchUpInside += (sender, e) => ((IMenuItemController)_item).Activate();
141+
((SecondaryToolbarItemContent)CustomView).TouchUpInside += OnClicked;
130142
item.PropertyChanged += OnPropertyChanged;
131143

132144
if (item != null && !string.IsNullOrEmpty(item.AutomationId))
@@ -136,34 +148,45 @@ public SecondaryToolbarItem(ToolbarItem item) : base(new SecondaryToolbarItemCon
136148
this.SetAccessibilityLabel(item);
137149
}
138150

151+
void OnClicked (object sender, EventArgs e)
152+
{
153+
if (_item.TryGetTarget(out var item))
154+
{
155+
((IMenuItemController)item).Activate();
156+
}
157+
}
158+
139159
protected override void Dispose(bool disposing)
140160
{
141-
if (disposing)
142-
_item.PropertyChanged -= OnPropertyChanged;
161+
if (disposing && _item.TryGetTarget(out var item))
162+
item.PropertyChanged -= OnPropertyChanged;
143163
base.Dispose(disposing);
144164
}
145165

146166
void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
147167
{
168+
if (!_item.TryGetTarget(out var item))
169+
return;
170+
148171
if (e.PropertyName == MenuItem.TextProperty.PropertyName)
149-
UpdateText();
172+
UpdateText(item);
150173
else if (e.PropertyName == MenuItem.IconImageSourceProperty.PropertyName)
151-
UpdateIcon();
174+
UpdateIcon(item);
152175
else if (e.PropertyName == MenuItem.IsEnabledProperty.PropertyName)
153-
UpdateIsEnabled();
176+
UpdateIsEnabled(item);
154177
#pragma warning disable CS0618 // Type or member is obsolete
155178
else if (e.PropertyName == AutomationProperties.HelpTextProperty.PropertyName)
156-
this.SetAccessibilityHint(_item);
179+
this.SetAccessibilityHint(item);
157180
else if (e.PropertyName == AutomationProperties.NameProperty.PropertyName)
158181
#pragma warning restore CS0618 // Type or member is obsolete
159-
this.SetAccessibilityLabel(_item);
182+
this.SetAccessibilityLabel(item);
160183
}
161184

162-
void UpdateIcon()
185+
void UpdateIcon(ToolbarItem item)
163186
{
164-
if (_item.IconImageSource != null && !_item.IconImageSource.IsEmpty)
187+
if (item.IconImageSource != null && !item.IconImageSource.IsEmpty)
165188
{
166-
_item.IconImageSource.LoadImage(_item.FindMauiContext(), result =>
189+
item.IconImageSource.LoadImage(item.FindMauiContext(), result =>
167190
{
168191
((SecondaryToolbarItemContent)CustomView).Image = result?.Value;
169192
});
@@ -174,14 +197,14 @@ void UpdateIcon()
174197
}
175198
}
176199

177-
void UpdateIsEnabled()
200+
void UpdateIsEnabled(ToolbarItem item)
178201
{
179-
((UIControl)CustomView).Enabled = _item.IsEnabled;
202+
((UIControl)CustomView).Enabled = item.IsEnabled;
180203
}
181204

182-
void UpdateText()
205+
void UpdateText(ToolbarItem item)
183206
{
184-
((SecondaryToolbarItemContent)CustomView).Text = _item.Text;
207+
((SecondaryToolbarItemContent)CustomView).Text = item.Text;
185208
}
186209

187210
sealed class SecondaryToolbarItemContent : UIControl

src/Controls/src/Core/Handlers/Items/Android/Adapters/StructuredItemsViewAdapter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,12 @@ protected override void BindTemplatedItemViewHolder(TemplatedItemViewHolder temp
121121

122122
void UpdateHasHeader()
123123
{
124-
ItemsSource.HasHeader = ItemsView.Header != null;
124+
ItemsSource.HasHeader = (ItemsView.Header ?? ItemsView.HeaderTemplate) is not null;
125125
}
126126

127127
void UpdateHasFooter()
128128
{
129-
ItemsSource.HasFooter = ItemsView.Footer != null;
129+
ItemsSource.HasFooter = (ItemsView.Footer ?? ItemsView.FooterTemplate) is not null;
130130
}
131131

132132
bool IsHeader(int position)

src/Controls/src/Core/Handlers/Items/CarouselViewHandler.iOS.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,12 @@ public static void MapCurrentItem(CarouselViewHandler handler, CarouselView caro
5858

5959
public static void MapPosition(CarouselViewHandler handler, CarouselView carouselView)
6060
{
61-
(handler.Controller as CarouselViewController)?.UpdateFromPosition();
61+
// If the initial position hasn't been set, we have a UpdateInitialPosition call on CarouselViewController
62+
// that will handle this so we want to skip this mapper call. We need to wait for the CollectionView to be ready
63+
if(handler.Controller is CarouselViewController carouselViewController && carouselViewController.InitialPositionSet)
64+
{
65+
carouselViewController.UpdateFromPosition();
66+
}
6267
}
6368

6469
public static void MapLoop(CarouselViewHandler handler, CarouselView carouselView)

0 commit comments

Comments
 (0)