Skip to content

Commit 39c8d64

Browse files
jfversluisCopilot
andcommitted
Support dot badge via empty string BadgeText
Change BadgeText semantics: null = no badge, empty string = dot indicator, non-empty string = text/count badge. Previously both null and empty string hid the badge. Platform implementations: - Android: ClearNumber() on BadgeDrawable for dot mode - iOS: Set BadgeValue to empty string (native dot support) - Windows: HasBadge checks 'is not null' instead of IsNullOrEmpty Added 3 unit tests for dot badge behavior. Updated sample page dot badge button to use empty string. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 2879d79 commit 39c8d64

6 files changed

Lines changed: 44 additions & 7 deletions

File tree

src/Controls/samples/Controls.Sample/Pages/Core/ShellGalleries/ShellBadgeGallery.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ public ShellBadgeGallery()
5555
new Label { Text = "Apply Badge to Tab", FontAttributes = FontAttributes.Bold },
5656
CreateApplyButton("Set Badge on Current Tab", OnSetBadgeCurrentTab),
5757
CreateApplyButton("Set Badge on All Tabs", OnSetBadgeAllTabs),
58+
CreateApplyButton("Set Dot Badge (empty string)", OnSetDotBadge),
5859
CreateApplyButton("Clear All Badges", OnClearAllBadges),
5960

6061
new BoxView { HeightRequest = 1, Color = Colors.LightGray },
@@ -179,8 +180,8 @@ void OnSetDotBadge(object? sender, EventArgs e)
179180
var section = GetCurrentShellSection();
180181
if (section is not null)
181182
{
182-
// A non-null but empty-looking badge on some platforms shows as a dot
183-
section.BadgeText = " ";
183+
// Empty string shows as a dot indicator on all platforms
184+
section.BadgeText = "";
184185
UpdateBadgeStatus();
185186
}
186187
}

src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellItemRenderer.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,7 @@ protected virtual void UpdateShellSectionBadge(ShellSection shellSection, int in
521521
var badgeText = shellSection.BadgeText;
522522
var menuItemId = index;
523523

524-
if (string.IsNullOrEmpty(badgeText))
524+
if (badgeText is null)
525525
{
526526
_bottomView.RemoveBadge(menuItemId);
527527
}
@@ -536,7 +536,10 @@ protected virtual void UpdateShellSectionBadge(ShellSection shellSection, int in
536536
}
537537

538538
var badge = _bottomView.GetOrCreateBadge(menuItemId);
539-
badge.Text = badgeText;
539+
if (badgeText.Length > 0)
540+
badge.Text = badgeText;
541+
else
542+
badge.ClearNumber(); // Empty string shows as dot indicator
540543

541544
if (badgeColor is not null)
542545
{

src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellItemRenderer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ void SetTabItemsEnabledState()
343343
static void UpdateTabBarItemBadge(UITabBarItem tabBarItem, ShellSection shellSection)
344344
{
345345
var badgeText = shellSection.BadgeText;
346-
tabBarItem.BadgeValue = string.IsNullOrEmpty(badgeText) ? null : badgeText;
346+
tabBarItem.BadgeValue = badgeText is null ? null : (badgeText.Length > 0 ? badgeText : "");
347347

348348
var badgeColor = shellSection.BadgeColor;
349349
if (badgeColor is not null)

src/Controls/src/Core/Shell/BaseShellItem.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ public bool FlyoutItemIsVisible
166166
/// </summary>
167167
/// <remarks>
168168
/// Setting this property to a non-null, non-empty value will display a badge on the tab item.
169-
/// Set to <see langword="null"/> or empty string to hide the badge.
169+
/// Set to an empty string to show a dot indicator (small badge with no text).
170+
/// Set to <see langword="null"/> to hide the badge.
170171
/// On Windows, only numeric values are displayed as numbers; non-numeric text (e.g., "New") shows as a dot indicator.
171172
/// </remarks>
172173
public string BadgeText

src/Controls/tests/Core.UnitTests/ShellBadgeTests.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,5 +251,37 @@ public void BadgeTextColorSupportsDataBinding()
251251
shellSection.BindingContext = new { TextColor = Colors.Cyan };
252252
Assert.Equal(Colors.Cyan, shellSection.BadgeTextColor);
253253
}
254+
255+
[Fact]
256+
public void SetBadgeTextEmptyStringForDotBadge()
257+
{
258+
var shellSection = new ShellSection();
259+
shellSection.BadgeText = "";
260+
Assert.Equal("", shellSection.BadgeText);
261+
}
262+
263+
[Fact]
264+
public void EmptyStringBadgeIsDistinctFromNull()
265+
{
266+
var shellSection = new ShellSection();
267+
shellSection.BadgeText = "";
268+
Assert.NotNull(shellSection.BadgeText);
269+
shellSection.BadgeText = null;
270+
Assert.Null(shellSection.BadgeText);
271+
}
272+
273+
[Fact]
274+
public void EmptyStringBadgeFiresPropertyChanged()
275+
{
276+
var shellSection = new ShellSection();
277+
bool fired = false;
278+
shellSection.PropertyChanged += (s, e) =>
279+
{
280+
if (e.PropertyName == nameof(BaseShellItem.BadgeText))
281+
fired = true;
282+
};
283+
shellSection.BadgeText = "";
284+
Assert.True(fired);
285+
}
254286
}
255287
}

src/Core/src/Platform/Windows/NavigationViewItemViewModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ public WBrush? BadgeForeground
274274
set { this.SetProperty(ref _badgeForeground, value, OnPropertyChanged); }
275275
}
276276

277-
public bool HasBadge => !string.IsNullOrEmpty(_badgeText);
277+
public bool HasBadge => _badgeText is not null;
278278

279279
public int BadgeValue => int.TryParse(_badgeText, out var v) && v >= 0 ? v : -1;
280280

0 commit comments

Comments
 (0)