File: Platform\Tizen\StackNavigationManager.cs
Web Access
Project: src\src\Core\src\Core.csproj (Microsoft.Maui)
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Tizen.NUI.BaseComponents;
using Tizen.UIExtensions.NUI;
using NLayoutGroup = Tizen.NUI.LayoutGroup;
using NLinearLayout = Tizen.NUI.LinearLayout;
#pragma warning disable CA1859 // Use concrete types when possible for improved performance
 
namespace Microsoft.Maui.Platform
{
	public interface IToolbarContainer
	{
		public void SetToolbar(MauiToolbar toolbar);
	}
 
	public class StackNavigationManager : View, IToolbarContainer
	{
		Dictionary<IView, NaviPage> _pageMap = new Dictionary<IView, NaviPage>();
		Dictionary<IView, IViewHandler?> _handlerMap = new Dictionary<IView, IViewHandler?>();
 
		MauiToolbar? _toolbar;
 
		List<IView> NavigationStack { get; set; } = new List<IView>();
 
		protected IMauiContext? MauiContext { get; set; }
 
		protected IStackNavigation? NavigationView { get; set; }
 
		protected NavigationStack PlatformNavigation { get; }
 
		public StackNavigationManager()
		{
			HeightSpecification = LayoutParamPolicies.MatchParent;
			WidthSpecification = LayoutParamPolicies.MatchParent;
 
			Layout = new NLinearLayout
			{
				LinearOrientation = NLinearLayout.Orientation.Vertical
			};
			PlatformNavigation = new NavigationStack();
 
			Add(PlatformNavigation);
		}
 
		public void SetToolbar(MauiToolbar toolbar)
		{
			if (_toolbar != null)
			{
				Remove(_toolbar);
				_toolbar.Dispose();
				_toolbar = null;
			}
 
			_toolbar = toolbar;
			Add(toolbar);
			(toolbar.Layout as NLayoutGroup)?.ChangeLayoutSiblingOrder(0);
		}
 
		public virtual void Connect(IView navigationView)
		{
			NavigationView = (IStackNavigation)navigationView;
			MauiContext = navigationView.Handler?.MauiContext;
		}
 
		public virtual void Disconnect()
		{
			NavigationView = null;
			MauiContext = null;
		}
 
		public virtual async void RequestNavigation(NavigationRequest e)
		{
			var newPageStack = new List<IView>(e.NavigationStack);
			var previousNavigationStack = NavigationStack;
			var previousNavigationStackCount = previousNavigationStack.Count;
			bool initialNavigation = previousNavigationStackCount == 0;
 
			if (initialNavigation)
			{
				await InitializeStack((IReadOnlyList<IView>)newPageStack, e.Animated);
				NavigationStack = newPageStack;
				NavigationFinished(NavigationStack);
				return;
			}
 
			if (newPageStack.Count > 0 && previousNavigationStackCount > 0 &&
				newPageStack[newPageStack.Count - 1] == previousNavigationStack[previousNavigationStackCount - 1])
			{
				SyncBackStackToNavigationStack(newPageStack);
				NavigationStack = newPageStack;
				NavigationFinished(NavigationStack);
				return;
			}
 
			if (newPageStack.Count > previousNavigationStackCount)
			{
				//Push to sync
				await PushToSync(newPageStack, e.Animated);
				NavigationStack = newPageStack;
				NavigationFinished(NavigationStack);
			}
			else
			{
				// top to sync
				await PopToSync(newPageStack, e.Animated);
				NavigationStack = newPageStack;
				NavigationFinished(NavigationStack);
			}
		}
 
		protected virtual async Task InitializeStack(IReadOnlyList<IView> newStack, bool animated)
		{
			var navigationStack = newStack;
			if (navigationStack.Count == 0)
				return;
 
			var top = navigationStack[navigationStack.Count - 1];
			foreach (var page in navigationStack)
			{
				await PlatformNavigation.Push(GetNavigationItem(page), page == top && animated);
			}
		}
 
		void SyncBackStackToNavigationStack(List<IView> newStack)
		{
			if (newStack.Count > NavigationStack.Count)
			{
				for (int i = 0; i < newStack.Count; i++)
				{
					if (NavigationStack.IndexOf(newStack[i]) == -1)
					{
						PlatformNavigation.Insert(GetNavigationItem(NavigationStack[i]), GetNavigationItem(newStack[i]));
					}
				}
			}
			else
			{
				foreach (var page in NavigationStack)
				{
					if (newStack.IndexOf(page) == -1)
					{
						PlatformNavigation.Pop(GetNavigationItem(page));
						_pageMap.Remove(page);
						if (_handlerMap.TryGetValue(page, out var handler))
						{
							(handler as IPlatformViewHandler)?.Dispose();
							_handlerMap.Remove(page);
						}
					}
				}
			}
		}
 
		async Task PushToSync(List<IView> newStack, bool animated)
		{
			int start = NavigationStack.Count;
			for (int i = start; i < newStack.Count; i++)
			{
				var isTop = i + 1 == newStack.Count;
				await PlatformNavigation.Push(GetNavigationItem(newStack[i]), isTop && animated);
			}
		}
 
		async Task PopToSync(List<IView> newStack, bool animated)
		{
			int start = newStack.Count;
			for (int i = start; i < NavigationStack.Count; i++)
			{
				var isLast = i + 1 == NavigationStack.Count;
				var page = NavigationStack[i];
 
				if (isLast)
				{
					await PlatformNavigation.Pop(animated);
				}
				else
				{
					PlatformNavigation.Pop(GetNavigationItem(NavigationStack[i]));
				}
				_pageMap.Remove(page);
				if (_handlerMap.TryGetValue(page, out var handler))
				{
					(handler as IPlatformViewHandler)?.Dispose();
					_handlerMap.Remove(page);
				}
			}
		}
 
		void NavigationFinished(List<IView> stack)
		{
			NavigationView?.NavigationFinished(stack);
		}
 
		NaviPage GetNavigationItem(IView page)
		{
			if (_pageMap.ContainsKey(page))
			{
				return _pageMap[page];
			}
 
			var content = page.ToPlatform(MauiContext!);
			content.WidthSpecification = LayoutParamPolicies.MatchParent;
			content.HeightSpecification = LayoutParamPolicies.MatchParent;
 
			var naviPage = new NaviPage
			{
				Content = content,
				WidthSpecification = LayoutParamPolicies.MatchParent,
				HeightSpecification = LayoutParamPolicies.MatchParent,
			};
			_pageMap[page] = naviPage;
			_handlerMap[page] = page.Handler;
			return naviPage;
		}
	}
}
#pragma warning restore CA1859 // Use concrete types when possible for improved performance