Skip to content

Commit

Permalink
Merge pull request #36 from nalu-development/small-improvements
Browse files Browse the repository at this point in the history
Delay navigation by 60ms to let user animation run on the screen when pressing buttons / doing actions
  • Loading branch information
albyrock87 authored May 30, 2024
2 parents 6842f56 + cf6f6a4 commit 0b293d0
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 70 deletions.
7 changes: 7 additions & 0 deletions Source/Nalu.Maui.Navigation/Internals/NavigationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ internal class NavigationService : INavigationService, IDisposable
private readonly SemaphoreSlim _semaphore = new(1, 1);
private readonly AsyncLocal<StrongBox<bool>> _isNavigating = new();
private readonly LeakDetector? _leakDetector;
private readonly TimeProvider _timeProvider;
private IShellProxy? _shellProxy;

public IShellProxy ShellProxy => _shellProxy ?? throw new InvalidOperationException("You must use NaluShell to navigate with INavigationService.");
Expand All @@ -20,6 +21,7 @@ public NavigationService(INavigationConfiguration configuration, IServiceProvide
{
Configuration = configuration;
_serviceProvider = serviceProvider;
_timeProvider = serviceProvider.GetService<TimeProvider>() ?? TimeProvider.System;

var trackLeaks
= (Configuration.LeakDetectorState == NavigationLeakDetectorState.EnabledWithDebugger && Debugger.IsAttached) ||
Expand Down Expand Up @@ -69,6 +71,11 @@ public async Task<bool> GoToAsync(INavigationInfo navigation)

return await ExecuteNavigationAsync(async () =>
{
if (navigation.Behavior?.HasFlag(NavigationBehavior.Immediate) != true)
{
await Task.Delay(TimeSpan.FromMilliseconds(60), _timeProvider).ConfigureAwait(true);
}
shellProxy.BeginNavigation();
try
{
Expand Down
8 changes: 8 additions & 0 deletions Source/Nalu.Maui.Navigation/NavigationBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,12 @@ public enum NavigationBehavior
/// When popping a page, the <see cref="ILeavingGuard"/>s will be ignored.
/// </summary>
IgnoreGuards = 0x04,

/// <summary>
/// Immediately navigates to the target page without waiting 60 milliseconds.
/// </summary>
/// <remarks>
/// Default behavior is to wait 60 milliseconds before navigating to the target page to let touch be displayed.
/// </remarks>
Immediate = 0x08,
}
140 changes: 70 additions & 70 deletions Source/Nalu.Maui.Navigation/ShellInfo/ShellProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,32 +52,32 @@ public async Task CommitNavigationAsync(Action? completeAction = null)
return;
}

var contentChanged = _contentChanged;
_navigationTarget = null;
_contentChanged = false;
_navigationCurrentSection = null;

try
{
_shell.SetIsNavigating(true);

var contentChanged = _contentChanged;
_navigationTarget = null;
_contentChanged = false;
_navigationCurrentSection = null;

await _shell.GoToAsync(targetState, true).ConfigureAwait(true);
await Task.Yield();

if (contentChanged)
{
// Wait for the animation to complete
// I know this is a hack, but I don't see any other way to do this
// given `shell.GoToAsync` does not wait for the animation to complete
await Task.Delay(600).ConfigureAwait(true);
}

completeAction?.Invoke();
}
finally
{
_shell.SetIsNavigating(false);
}

await Task.Yield();

if (contentChanged)
{
// Wait for the animation to complete
// I know this is a hack, but I don't see any other way to do this
// given `shell.GoToAsync` does not wait for the animation to complete
await Task.Delay(500).ConfigureAwait(true);
}

completeAction?.Invoke();
}

public IShellContentProxy GetContent(string segmentName) => _contentsBySegmentName[segmentName];
Expand All @@ -98,87 +98,87 @@ public IShellContentProxy FindContent(params string[] names)
throw new KeyNotFoundException($"Could not find content with segment name '{name}'");
}

public Color GetToolbarIconColor(Page page) => Shell.GetTitleColor(page.IsSet(Shell.TitleColorProperty) ? page : _shell);
public Color GetToolbarIconColor(Page page) =>
Shell.GetTitleColor(page.IsSet(Shell.TitleColorProperty) ? page : _shell);

public async Task PushAsync(string segmentName, Page page)
{
try
{
_shell.SetIsNavigating(true);
var baseRoute = _navigationTarget ?? _shell.CurrentState.Location.OriginalString;
var finalRoute = $"{baseRoute}/{segmentName}";

var baseRoute = _navigationTarget ?? _shell.CurrentState.Location.OriginalString;
var finalRoute = $"{baseRoute}/{segmentName}";
var pageTypeRouteFactory = _routeFactory.GetRouteFactory(page.GetType());
pageTypeRouteFactory.Push(page);

var pageTypeRouteFactory = _routeFactory.GetRouteFactory(page.GetType());
pageTypeRouteFactory.Push(page);

if (!_registeredSegments.Contains(segmentName))
{
Routing.RegisterRoute(segmentName, pageTypeRouteFactory);
_registeredSegments.Add(segmentName);
}
if (!_registeredSegments.Contains(segmentName))
{
Routing.RegisterRoute(segmentName, pageTypeRouteFactory);
_registeredSegments.Add(segmentName);
}

if (_navigationTarget != null)
if (_navigationTarget != null)
{
_navigationTarget = finalRoute;
}
else
{
try
{
_navigationTarget = finalRoute;
_shell.SetIsNavigating(true);
await _shell.GoToAsync(finalRoute).ConfigureAwait(true);
}
else
finally
{
await _shell.GoToAsync(finalRoute).ConfigureAwait(true);
_shell.SetIsNavigating(false);
}
}
finally
{
_shell.SetIsNavigating(false);
}
}

public async Task PopAsync(IShellSectionProxy? section = null)
{
try
{
_shell.SetIsNavigating(true);
section ??= CurrentItem.CurrentSection;
section ??= CurrentItem.CurrentSection;

if (section == _navigationCurrentSection && _navigationTarget != null)
if (section == _navigationCurrentSection && _navigationTarget != null)
{
var previousSegmentEnd = _navigationTarget.LastIndexOf('/');
_navigationTarget = _navigationTarget[..previousSegmentEnd];
}
else
{
try
{
var previousSegmentEnd = _navigationTarget.LastIndexOf('/');
_navigationTarget = _navigationTarget[..previousSegmentEnd];
_shell.SetIsNavigating(true);
await section.PopAsync().ConfigureAwait(true);
}
else
finally
{
await section.PopAsync().ConfigureAwait(true);
_shell.SetIsNavigating(false);
}
}
finally
{
_shell.SetIsNavigating(false);
}
}

public async Task SelectContentAsync(string segmentName)
{
try
var contentProxy = (ShellContentProxy)GetContent(segmentName);
if (CurrentItem.CurrentSection.CurrentContent == contentProxy)
{
_shell.SetIsNavigating(true);
var contentProxy = (ShellContentProxy)GetContent(segmentName);
if (CurrentItem.CurrentSection.CurrentContent == contentProxy)
{
return;
}
return;
}

_contentChanged = true;
var content = contentProxy.Content;
var section = (ShellSection)content.Parent;
var item = (ShellItem)section.Parent;
_contentChanged = true;
var content = contentProxy.Content;
var section = (ShellSection)content.Parent;
var item = (ShellItem)section.Parent;

if (_navigationTarget is not null)
{
_navigationTarget = contentProxy.Parent.GetNavigationStack(contentProxy).LastOrDefault()?.Route
?? $"//{item.Route}/{section.Route}/{content.Route}";
return;
}
if (_navigationTarget is not null)
{
_navigationTarget = contentProxy.Parent.GetNavigationStack(contentProxy).LastOrDefault()?.Route
?? $"//{item.Route}/{section.Route}/{content.Route}";
return;
}

try
{
_shell.SetIsNavigating(true);
if (section.CurrentItem != content)
{
section.CurrentItem = content;
Expand All @@ -194,7 +194,7 @@ public async Task SelectContentAsync(string segmentName)
_shell.CurrentItem = item;
}

await Task.Delay(250).ConfigureAwait(true);
await Task.Delay(500).ConfigureAwait(true);
}
finally
{
Expand Down

0 comments on commit 0b293d0

Please sign in to comment.