Skip to content
36 changes: 36 additions & 0 deletions Float.Core/UX/Coordinator.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Threading.Tasks;
using Xamarin.Forms;
using static Float.Core.UX.ICoordinator;

namespace Float.Core.UX
{
Expand All @@ -26,6 +27,11 @@ public abstract class Coordinator : ICoordinator
/// </summary>
Page managedPage;

/// <summary>
/// The event args that are pending a finish.
/// </summary>
EventArgs waitingToFinishEventArgs;
Comment thread
EBusch marked this conversation as resolved.
Outdated
Comment thread
EBusch marked this conversation as resolved.
Outdated

/// <summary>
/// Occurs when this coordinator is started.
/// </summary>
Expand Down Expand Up @@ -93,6 +99,36 @@ public virtual void Start()
isStarted = true;
}

/// <inheritdoc/>
public CoordinatorRequestFinishStatus RequestFinish(EventArgs args)
Comment thread
EBusch marked this conversation as resolved.
Outdated
{
return HandleFinishRequested(this, args);
}

/// <summary>
/// Handles when a finish is requested.
/// </summary>
/// <param name="coordinator">The coordinator that has requested this coordinator to finish.</param>
/// <param name="eventArgs">The event args.</param>
/// <returns>A value indicating whether this finished.</returns>
public virtual CoordinatorRequestFinishStatus HandleFinishRequested(ICoordinator coordinator, EventArgs eventArgs)
Comment thread
EBusch marked this conversation as resolved.
Outdated
{
if (this == coordinator)
{
if (managedPage == null)
{
Finish(eventArgs);
return CoordinatorRequestFinishStatus.FinishedImmediately;
}

waitingToFinishEventArgs = eventArgs;
NavigationContext.Reset(false);
return CoordinatorRequestFinishStatus.PendingFinish;
}

return CoordinatorRequestFinishStatus.Unknown;
}

/// <summary>
/// Returning a page here will allow the coordinator to automatically
/// manage itself based on the state of the UI.
Expand Down
46 changes: 46 additions & 0 deletions Float.Core/UX/CoordinatorParent.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Float.Core.Extensions;
using static Float.Core.UX.ICoordinator;

namespace Float.Core.UX
{
Expand All @@ -15,6 +16,11 @@ public abstract class CoordinatorParent : Coordinator, ICoordinatorParent
/// </summary>
readonly List<ICoordinator> childCoordinators = new ();

/// <summary>
/// The event args that have been used as we are waiting to finish all the children before closing the parent.
/// </summary>
EventArgs waitingToFinishEventArgs = null;

Comment thread
EBusch marked this conversation as resolved.
Outdated
/// <summary>
/// Gets a value indicating whether this <see cref="CoordinatorParent"/> has children.
/// </summary>
Expand Down Expand Up @@ -117,6 +123,40 @@ public override string ToString()
return $"[{GetType()}, Children: {string.Join(",", childCoordinators)}]";
}

/// <summary>
/// Handles the finish request.
/// </summary>
/// <param name="coordinator">The calling coordinator.</param>
/// <param name="eventArgs">The event args.</param>
/// <returns>A value indicating whether this finished.</returns>
Comment thread
EBusch marked this conversation as resolved.
Outdated
public override CoordinatorRequestFinishStatus HandleFinishRequested(ICoordinator coordinator, EventArgs eventArgs)
{
waitingToFinishEventArgs = eventArgs;

CoordinatorRequestFinishStatus? status = null;

foreach (var eachChild in ChildCoordinators)
{
if (eachChild is Coordinator childCoordinator)
{
var freshStatus = childCoordinator.HandleFinishRequested(childCoordinator, eventArgs);

if (status == null)
{
status = freshStatus;
}

// If every child finishes with the same status we can return that, otherwise unknown seems to be the best option.
if (freshStatus != status)
{
status = CoordinatorRequestFinishStatus.Unknown;
}
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@EBusch We're probably missing a call to the base implementation here. When you add that, you may have an issue with Finish getting called twice:

Coordinator.HandleNavigation may call it and so will CoordinatorParent.HandleChildFinish -- it is not currently clear to me the best way to address that.

return status ?? CoordinatorRequestFinishStatus.Unknown;
}

/// <inheritdoc />
protected override void Finish(EventArgs args)
{
Expand Down Expand Up @@ -149,6 +189,12 @@ protected virtual void HandleChildFinish(object sender, EventArgs args)
{
RemoveChild(child);
}

if (!HasChildren && waitingToFinishEventArgs != null)
{
Finish(waitingToFinishEventArgs);
waitingToFinishEventArgs = null;
}
}
}
}
33 changes: 33 additions & 0 deletions Float.Core/UX/ICoordinator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,43 @@ public interface ICoordinator
/// </summary>
event EventHandler<EventArgs> Finished;

/// <summary>
/// An enum for the possible results of a coordinator's RequestFinish.
/// </summary>
public enum CoordinatorRequestFinishStatus
{
/// <summary>
/// The coordinator RequestFinish finished immediately.
/// </summary>
FinishedImmediately,

/// <summary>
/// The coordinator RequestFinish is pending a finish.
/// </summary>
PendingFinish,

/// <summary>
/// The coordinator RequestFinish will not complete.
/// </summary>
WillNotFinish,

/// <summary>
/// The coordinator RequestFinish's status is unknown.
/// </summary>
Unknown,
}

/// <summary>
/// Implementing classes should use this to start this coordinator.
/// </summary>
/// <param name="navigationContext">The navigation context for this coordinator.</param>
void Start(INavigationContext navigationContext);

/// <summary>
/// Requests that a coordinator will finish.
/// </summary>
/// <param name="eventArgs">The event args.</param>
/// <returns>A task, with a boolean indicating whether this did finish.</returns>
Comment thread
EBusch marked this conversation as resolved.
CoordinatorRequestFinishStatus RequestFinish(EventArgs eventArgs);
}
}