Skip to content

Instantly share code, notes, and snippets.

@PureWeen
Last active May 6, 2020 21:23
Show Gist options
  • Save PureWeen/59ad6f2f625ef8af1bbc3b6ea291e18c to your computer and use it in GitHub Desktop.
Save PureWeen/59ad6f2f625ef8af1bbc3b6ea291e18c to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Linq;
using Xamarin.Forms;
using TinyNavigationHelper.Abstraction;
namespace TinyNavigationHelper.Forms
{
public class FormsNavigationHelper : INavigationHelper
{
private readonly Application _app = Application.Current;
protected Dictionary<string, Type> Views = new Dictionary<string, Type>();
private NavigationPage? _modalNavigationPage;
public IViewCreator<Page> ViewCreator { get; set; }
public FormsNavigationHelper()
{
ViewCreator = new DefaultViewCreator();
Abstraction.NavigationHelper.Current = this;
}
public void RegisterView<T>(string key) where T : Page
{
var type = typeof(T);
InternalRegisterView(type, key);
}
public void RegisterView(string key, Type type)
{
InternalRegisterView(type, key);
}
protected virtual void InternalRegisterView(Type type, string key)
{
if (Views.ContainsKey(key.ToLower()))
{
Views[key.ToLower()] = type;
}
else
{
Views.Add(key.ToLower(), type);
}
}
/// <summary>
/// Registers the views in assembly that inherit from Page
/// </summary>
/// <param name="assembly">The assembly to inspect</param>
public void RegisterViewsInAssembly(Assembly assembly)
{
foreach (var type in assembly.DefinedTypes.Where(e => e.IsSubclassOf(typeof(Page))))
{
InternalRegisterView(type.AsType(), type.Name);
}
}
/// <summary>
/// Navigates to async.
/// </summary>
/// <returns>The to async.</returns>
/// <param name="page">Page.</param>
/// <remarks>Not exposed by the interface but added as an extension</remarks>
public async Task NavigateToAsync(Page page)
{
await NavigateToAsync(page, false);
}
private async Task NavigateToAsync(Page page, bool resetStack)
{
if (_modalNavigationPage == null)
{
if (_app.MainPage is TabbedPage tabbedpage)
{
var selected = tabbedpage.CurrentPage;
if (resetStack)
{
var pages = selected.Navigation.NavigationStack.Count();
await selected.Navigation.PushAsync(page);
for (var i = pages - 1; i >= 0; i--)
{
var p = selected.Navigation.NavigationStack[i];
selected.Navigation.RemovePage(p);
}
return;
}
if (selected.Navigation != null)
{
await selected.Navigation.PushAsync(page);
return;
}
}
else if (_app.MainPage is MasterDetailPage masterDetailPage)
{
if (resetStack)
{
masterDetailPage.Detail = new NavigationPage(page);
return;
}
if (masterDetailPage.Detail is TabbedPage tabbedPage)
{
if (tabbedPage.CurrentPage.Navigation != null)
{
await tabbedPage.CurrentPage.Navigation.PushAsync(page);
return;
}
}
if (masterDetailPage?.Detail.Navigation != null)
{
await masterDetailPage.Detail.Navigation.PushAsync(page);
return;
}
}
if (resetStack)
{
_app.MainPage = new NavigationPage(page);
return;
}
await _app.MainPage.Navigation.PushAsync(page);
}
else
{
await _modalNavigationPage.PushAsync(page);
}
}
public virtual async Task NavigateToAsync(string key, object parameter)
{
await NavigateTo(key, parameter);
}
public virtual async Task NavigateToAsync(string key)
{
await NavigateTo(key, null);
}
private async Task NavigateTo(string key, object? parameter)
{
if (Views.ContainsKey(key.ToLower()))
{
var type = Views[key.ToLower()];
Page? page = null;
if (parameter == null)
{
page = ViewCreator.Create(type);
}
else
{
page = ViewCreator.Create(type, parameter);
}
await NavigateToAsync(page);
}
else
{
throw new ViewCreationException($"The view '{key}, you're trying to navigate to has not been registered");
}
}
public async Task OpenModalAsync(Page page, bool withNavigation = false)
{
if (withNavigation)
{
_modalNavigationPage = new NavigationPage(page);
await _app.MainPage.Navigation.PushModalAsync(_modalNavigationPage);
}
else
{
await _app.MainPage.Navigation.PushModalAsync(page);
}
}
public async Task OpenModalAsync(string key, object parameter, bool withNavigation = false)
{
await OpenModal(key, parameter, withNavigation);
}
public async Task OpenModalAsync(string key, bool withNavigation = false)
{
await OpenModal(key, null, withNavigation);
}
private async Task OpenModal(string key, object? parameter, bool withNavigation = false)
{
if (Views.ContainsKey(key.ToLower()))
{
var type = Views[key.ToLower()];
Page? page = null;
if (parameter == null)
{
page = ViewCreator.Create(type);
}
else
{
page = ViewCreator.Create(type, parameter);
}
await OpenModalAsync(page, withNavigation);
}
else
{
throw new ViewCreationException($"The view '{key}, you're trying to navigate to has not been registered");
}
}
public async Task CloseModalAsync()
{
await _app.MainPage.Navigation.PopModalAsync();
_modalNavigationPage = null;
}
public async Task BackAsync()
{
if (_app.MainPage is TabbedPage tabbedpage)
{
var selected = (Page)tabbedpage.CurrentPage;
if (selected.Navigation != null)
{
await selected.Navigation.PopAsync();
return;
}
}
else if (_app.MainPage is MasterDetailPage masterDetailPage)
{
if (masterDetailPage.Detail is TabbedPage tabbedPage)
{
if (tabbedPage.CurrentPage.Navigation != null)
{
await tabbedPage.CurrentPage.Navigation.PopAsync();
return;
}
}
if (masterDetailPage.Detail.Navigation != null)
{
await masterDetailPage.Detail.Navigation.PopAsync();
return;
}
}
await _app.MainPage.Navigation.PopAsync();
}
public void SetRootView(string key, object parameter, bool withNavigation = true)
{
SetRoot(key, parameter, withNavigation);
}
public void SetRootView(string key, bool withNavigation = true)
{
SetRoot(key, null, withNavigation);
}
private void SetRoot(string key, object? parameter, bool withNavigation)
{
if (Views.ContainsKey(key.ToLower()))
{
var type = Views[key.ToLower()];
Page? page = null;
if (parameter == null)
{
page = ViewCreator.Create(type);
}
else
{
page = ViewCreator.Create(type, parameter);
}
if (withNavigation)
{
_app.MainPage = new NavigationPage(page);
}
else
{
_app.MainPage = page;
}
}
else
{
throw new ViewCreationException($"The view '{key}, you're trying to navigate to has not been registered");
}
}
public async Task ResetStackWith(string key)
{
await ResetStack(key, null);
}
public async Task ResetStackWith(string key, object parameter)
{
await ResetStack(key, parameter);
}
private async Task ResetStack(string key, object? parameter)
{
if (Views.ContainsKey(key.ToLower()))
{
var type = Views[key.ToLower()];
Page? page = null;
if (parameter == null)
{
page = ViewCreator.Create(type);
}
else
{
page = ViewCreator.Create(type, parameter);
}
await NavigateToAsync(page, true);
}
else
{
throw new ViewCreationException($"The view '{key}, you're trying to navigate to has not been registered");
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace TinyNavigationHelper.Forms
{
public class ShellNavigationHelper : FormsNavigationHelper
{
private Dictionary<string, string> queries = new Dictionary<string, string>();
public ShellNavigationHelper()
{
Abstraction.NavigationHelper.Current = this;
}
public void RegisterRoute(string route, Type type)
{
Routing.RegisterRoute(route, type);
}
protected override void InternalRegisterView(Type type, string key)
{
base.InternalRegisterView(type, key);
if(type.GenericTypeArguments.Length > 0)
{
RegisterRoute(type.GenericTypeArguments[0].Name, type);
}
if (type.BaseType.GenericTypeArguments.Length > 0)
{
RegisterRoute(type.BaseType.GenericTypeArguments[0].Name, type);
}
RegisterRoute(key, type);
}
internal Dictionary<string, string> GetQueryParameters(string tinyId)
{
var values = queries[tinyId].Split('&');
var parameters = new Dictionary<string, string>();
foreach (var val in values)
{
var split = val.Split('=');
parameters.Add(split.First(), split.Last());
}
return parameters;
}
public async override Task NavigateToAsync(string key)
{
try
{
if (Views.ContainsKey(key.ToLower()))
{
await base.NavigateToAsync(key);
return;
}
if (key.Contains("?"))
{
var route = key.Split('?');
var tinyId = Guid.NewGuid().ToString();
key = $"{key}&tinyid={tinyId}";
queries.Add(tinyId, route.Last());
}
await Shell.Current.GoToAsync(key);
}
catch (Exception ex)
{
await base.NavigateToAsync(key);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment