Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Google.Android.Material.BottomSheet;
using Google.Android.Material.Navigation;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Maui.Graphics;
using AColor = Android.Graphics.Color;
using AView = Android.Views.View;
Expand All @@ -38,7 +39,7 @@ void IAppearanceObserver.OnAppearanceChanged(ShellAppearance appearance)
{
_shellAppearance = appearance;

if (appearance != null)
if (appearance is not null)
SetAppearance(appearance);
else
ResetAppearance();
Expand All @@ -59,6 +60,9 @@ void IAppearanceObserver.OnAppearanceChanged(ShellAppearance appearance)
bool _appearanceSet;
public IShellItemController ShellItemController => ShellItem;
IMauiContext MauiContext => ShellContext.Shell.Handler.MauiContext;
IMenuItem _updateMenuItemTitle;
IMenuItem _updateMenuItemIcon;
ShellSection _updateMenuItemSource;

public ShellItemRenderer(IShellContext shellContext) : base(shellContext)
{
Expand All @@ -73,10 +77,10 @@ public override AView OnCreateView(LayoutInflater inflater, ViewGroup container,
_navigationArea = PlatformInterop.CreateNavigationBarArea(context, _outerLayout);
_bottomView = PlatformInterop.CreateNavigationBar(context, Resource.Attribute.bottomNavigationViewStyle, _outerLayout, this);

if (ShellItem == null)
if (ShellItem is null)
throw new InvalidOperationException("Active Shell Item not set. Have you added any Shell Items to your Shell?");

if (ShellItem.CurrentItem == null)
if (ShellItem.CurrentItem is null)
throw new InvalidOperationException($"Content not found for active {ShellItem}. Title: {ShellItem.Title}. Route: {ShellItem.Route}.");

HookEvents(ShellItem);
Expand All @@ -92,12 +96,12 @@ public override AView OnCreateView(LayoutInflater inflater, ViewGroup container,

void Destroy()
{
if (ShellItem != null)
if (ShellItem is not null)
UnhookEvents(ShellItem);

((IShellController)ShellContext?.Shell)?.RemoveAppearanceObserver(this);

if (_bottomSheetDialog != null)
if (_bottomSheetDialog is not null)
{
_bottomSheetDialog.DismissEvent -= OnMoreSheetDismissed;
_bottomSheetDialog?.Dispose();
Expand All @@ -108,7 +112,7 @@ void Destroy()
_appearanceTracker?.Dispose();
_outerLayout?.Dispose();

if (_bottomView != null)
if (_bottomView is not null)
{
_bottomView?.SetOnItemSelectedListener(null);
_bottomView?.Background?.Dispose();
Expand Down Expand Up @@ -143,9 +147,9 @@ public override void OnDestroy()

protected virtual void SetAppearance(ShellAppearance appearance)
{
if (_bottomView == null ||
if (_bottomView is null ||
_bottomView.Visibility == ViewStates.Gone ||
DisplayedPage == null)
DisplayedPage is null)
{
return;
}
Expand Down Expand Up @@ -229,7 +233,7 @@ void clickCallback(object s, EventArgs e)
(result) =>
{
image.SetImageDrawable(result?.Value);
if (result?.Value != null)
if (result?.Value is not null)
{
var color = Colors.Black.MultiplyAlpha(0.6f).ToPlatform();
result.Value.SetTint(color);
Expand Down Expand Up @@ -287,13 +291,13 @@ protected override void OnDisplayedPageChanged(Page newPage, Page oldPage)
{
base.OnDisplayedPageChanged(newPage, oldPage);

if (oldPage != null)
if (oldPage is not null)
oldPage.PropertyChanged -= OnDisplayedElementPropertyChanged;

if (newPage != null)
if (newPage is not null)
newPage.PropertyChanged += OnDisplayedElementPropertyChanged;

if (newPage != null && !_menuSetup)
if (newPage is not null && !_menuSetup)
{
SetupMenu();
}
Expand Down Expand Up @@ -358,7 +362,7 @@ protected virtual void OnMoreSheetDismissed(object sender, EventArgs e)
{
OnShellSectionChanged();

if (_bottomSheetDialog != null)
if (_bottomSheetDialog is not null)
{
_bottomSheetDialog.DismissEvent -= OnMoreSheetDismissed;
_bottomSheetDialog.Dispose();
Expand All @@ -377,24 +381,53 @@ protected override void OnShellSectionPropertyChanged(object sender, PropertyCha
{
base.OnShellSectionPropertyChanged(sender, e);

if (e.PropertyName == BaseShellItem.IsEnabledProperty.PropertyName)
if (e.IsOneOf(BaseShellItem.TitleProperty, BaseShellItem.IconProperty, BaseShellItem.IsEnabledProperty))
{
var content = (ShellSection)sender;
var index = ((IShellItemController)ShellItem).GetItems().IndexOf(content);
var shellSection = (ShellSection)sender;
var index = ((IShellItemController)ShellItem).GetItems().IndexOf(shellSection);

var itemCount = ((IShellItemController)ShellItem).GetItems().Count;
var maxItems = _bottomView.MaxItemCount;
IMenuItem menuItem = null;

if (itemCount > maxItems && index > maxItems - 2)
return;
if (!(itemCount > maxItems && index > maxItems - 2))
{
menuItem = _bottomView.Menu.FindItem(index);
}

var menuItem = _bottomView.Menu.FindItem(index);
UpdateShellSectionEnabled(content, menuItem);
}
else if (e.PropertyName == BaseShellItem.TitleProperty.PropertyName ||
e.PropertyName == BaseShellItem.IconProperty.PropertyName)
{
SetupMenu();
if (menuItem is not null)
{
if (e.Is(BaseShellItem.IsEnabledProperty))
{
UpdateShellSectionEnabled(shellSection, menuItem);
}
else if (e.Is(BaseShellItem.IconProperty))
{
_updateMenuItemIcon = menuItem;
}
else if (e.Is(BaseShellItem.TitleProperty))
{
_updateMenuItemTitle = menuItem;
}
}

// This is primarily used so that `SetupMenu` is still called when the
// title and icon property change calls happen. We don't want to break users
// that are dependent on that behavior
if (e.IsOneOf(BaseShellItem.IconProperty, BaseShellItem.TitleProperty))
{
try
{
_updateMenuItemSource = shellSection;
SetupMenu();
}
finally
{
_updateMenuItemIcon = null;
_updateMenuItemTitle = null;
_updateMenuItemSource = null;
}
}
}
}

Expand All @@ -406,7 +439,35 @@ protected virtual void OnTabReselected(ShellSection shellSection)

protected virtual void SetupMenu(IMenu menu, int maxBottomItems, ShellItem shellItem)
{
if (DisplayedPage == null)
if ((_updateMenuItemIcon is not null || _updateMenuItemTitle is not null) &&
_menuSetup &&
_updateMenuItemSource is not null &&
_bottomView.IsAlive() &&
_bottomView.IsAttachedToWindow)
{
if (_updateMenuItemIcon is not null)
{
var menuItem = _updateMenuItemIcon;
var shellSection = _updateMenuItemSource;
_updateMenuItemSource = null;
_updateMenuItemIcon = null;

UpdateShellSectionIcon(shellSection, menuItem);
return;
}
else if (_updateMenuItemTitle is not null)
{
var menuItem = _updateMenuItemTitle;
var shellSection = _updateMenuItemSource;
_updateMenuItemSource = null;
_updateMenuItemIcon = null;

UpdateShellSectionTitle(shellSection, menuItem);
return;
}
}

if (DisplayedPage is null)
return;

if (ShellItemController.ShowTabs)
Expand All @@ -427,6 +488,18 @@ protected virtual void SetupMenu(IMenu menu, int maxBottomItems, ShellItem shell
UpdateTabBarVisibility();
}

protected virtual void UpdateShellSectionIcon(ShellSection shellSection, IMenuItem menuItem)
{
BottomNavigationViewUtils.SetMenuItemIcon(menuItem, shellSection.Icon, MauiContext)
.FireAndForget(e => MauiContext?.CreateLogger<ShellItemRenderer>()?
.LogWarning(e, "Failed to Update Shell Section Icon"));
}

protected virtual void UpdateShellSectionTitle(ShellSection shellSection, IMenuItem menuItem)
{
BottomNavigationViewUtils.SetMenuItemTitle(menuItem, shellSection.Title);
}

protected virtual void UpdateShellSectionEnabled(ShellSection shellSection, IMenuItem menuItem)
{
bool tabEnabled = shellSection.IsEnabled;
Expand All @@ -453,12 +526,12 @@ void SetupMenu()

protected virtual void UpdateTabBarVisibility()
{
if (DisplayedPage == null)
if (DisplayedPage is null)
return;

_bottomView.Visibility = ShellItemController.ShowTabs ? ViewStates.Visible : ViewStates.Gone;

if (_shellAppearance != null && !_appearanceSet)
if (_shellAppearance is not null && !_appearanceSet)
{
SetAppearance(_shellAppearance);
}
Expand Down
69 changes: 51 additions & 18 deletions src/Controls/src/Core/Platform/Android/BottomNavigationViewUtils.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#nullable disable
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Android.Content;
using Android.Graphics.Drawables;
Expand Down Expand Up @@ -39,6 +40,29 @@ internal static void UpdateEnabled(bool tabEnabled, IMenuItem menuItem)
menuItem.SetEnabled(tabEnabled);
}

internal static Task SetupMenuItem(
(string title, ImageSource icon, bool tabEnabled) item,
IMenu menu,
int index,
int currentIndex,
BottomNavigationView bottomView,
IMauiContext mauiContext,
out IMenuItem menuItem)
{
Task returnValue;
using var title = new Java.Lang.String(item.title);
menuItem = menu.Add(0, index, 0, title);
returnValue = SetMenuItemIcon(menuItem, item.icon, mauiContext);
UpdateEnabled(item.tabEnabled, menuItem);
if (index == currentIndex)
{
menuItem.SetChecked(true);
bottomView.SelectedItemId = index;
}

return returnValue;
}

internal static async void SetupMenu(
IMenu menu,
int maxBottomItems,
Expand All @@ -48,29 +72,33 @@ internal static async void SetupMenu(
IMauiContext mauiContext)
{
Context context = mauiContext.Context;
menu.Clear();

while (items.Count < menu.Size())
{
menu.RemoveItem(menu.GetItem(menu.Size() - 1).ItemId);
}

int numberOfMenuItems = items.Count;
bool showMore = numberOfMenuItems > maxBottomItems;
int end = showMore ? maxBottomItems - 1 : numberOfMenuItems;


List<IMenuItem> menuItems = new List<IMenuItem>();
List<Task> loadTasks = new List<Task>();
for (int i = 0; i < end; i++)
{
var item = items[i];
using (var title = new Java.Lang.String(item.title))

IMenuItem menuItem;
if (i >= menu.Size())
loadTasks.Add(SetupMenuItem(item, menu, i, currentIndex, bottomView, mauiContext, out menuItem));
else
{
var menuItem = menu.Add(0, i, 0, title);
menuItems.Add(menuItem);
menuItem = menu.GetItem(i);
SetMenuItemTitle(menuItem, item.title);
loadTasks.Add(SetMenuItemIcon(menuItem, item.icon, mauiContext));
UpdateEnabled(item.tabEnabled, menuItem);
if (i == currentIndex)
{
menuItem.SetChecked(true);
bottomView.SelectedItemId = i;
}
}

menuItems.Add(menuItem);
}

if (showMore)
Expand All @@ -88,17 +116,20 @@ internal static async void SetupMenu(

if (loadTasks.Count > 0)
await Task.WhenAll(loadTasks);
}

foreach (var menuItem in menuItems)
menuItem.Dispose();
internal static void SetMenuItemTitle(IMenuItem menuItem, string title)
{
using var jTitle = new Java.Lang.String(title);
menuItem.SetTitle(jTitle);
}

static async Task SetMenuItemIcon(IMenuItem menuItem, ImageSource source, IMauiContext context)
internal static async Task SetMenuItemIcon(IMenuItem menuItem, ImageSource source, IMauiContext context)
{
if (!menuItem.IsAlive())
return;

if (source == null)
if (source is null)
return;

var services = context.Services;
Expand All @@ -109,8 +140,10 @@ static async Task SetMenuItemIcon(IMenuItem menuItem, ImageSource source, IMauiC
source,
context.Context);

if (menuItem.IsAlive() && result is not null)
menuItem.SetIcon(result.Value);
if (menuItem.IsAlive())
{
menuItem.SetIcon(result?.Value);
}
}

public static BottomSheetDialog CreateMoreBottomSheet(
Expand Down Expand Up @@ -212,7 +245,7 @@ public static void SetShiftMode(this BottomNavigationView bottomNavigationView,
try
{
var menuView = bottomNavigationView.GetChildAt(0) as BottomNavigationMenuView;
if (menuView == null)
if (menuView is null)
{
System.Diagnostics.Debug.WriteLine("Unable to find BottomNavigationMenuView");
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ override Microsoft.Maui.Controls.SearchBar.IsEnabledCore.get -> bool
*REMOVED*~static Microsoft.Maui.Controls.MessagingCenter.Subscribe<TSender>(object subscriber, string message, System.Action<TSender> callback, TSender source = null) -> void
*REMOVED*~static Microsoft.Maui.Controls.MessagingCenter.Unsubscribe<TSender, TArgs>(object subscriber, string message) -> void
*REMOVED*~static Microsoft.Maui.Controls.MessagingCenter.Unsubscribe<TSender>(object subscriber, string message) -> void
~virtual Microsoft.Maui.Controls.Platform.Compatibility.ShellItemRenderer.UpdateShellSectionIcon(Microsoft.Maui.Controls.ShellSection shellSection, Android.Views.IMenuItem menuItem) -> void
~virtual Microsoft.Maui.Controls.Platform.Compatibility.ShellItemRenderer.UpdateShellSectionTitle(Microsoft.Maui.Controls.ShellSection shellSection, Android.Views.IMenuItem menuItem) -> void
*REMOVED*~Microsoft.Maui.Controls.OpenGLView.On<T>() -> Microsoft.Maui.Controls.IPlatformElementConfiguration<T, Microsoft.Maui.Controls.OpenGLView>
*REMOVED*~Microsoft.Maui.Controls.OpenGLView.OnDisplay.get -> System.Action<Microsoft.Maui.Graphics.Rect>
*REMOVED*~Microsoft.Maui.Controls.OpenGLView.OnDisplay.set -> void
Expand All @@ -71,4 +73,4 @@ override Microsoft.Maui.Controls.SearchBar.IsEnabledCore.get -> bool
*REMOVED*Microsoft.Maui.Controls.Application.SavePropertiesAsync() -> System.Threading.Tasks.Task!
*REMOVED*Microsoft.Maui.Controls.Application.Properties.get -> System.Collections.Generic.IDictionary<string!, object!>!
Microsoft.Maui.Controls.IValueConverter.Convert(object? value, System.Type! targetType, object? parameter, System.Globalization.CultureInfo! culture) -> object?
Microsoft.Maui.Controls.IValueConverter.ConvertBack(object? value, System.Type! targetType, object? parameter, System.Globalization.CultureInfo! culture) -> object?
Microsoft.Maui.Controls.IValueConverter.ConvertBack(object? value, System.Type! targetType, object? parameter, System.Globalization.CultureInfo! culture) -> object?
Loading