diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4529991..2f7bbcc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,8 +23,16 @@ jobs: run: dotnet restore - name: Build run: dotnet build --configuration Release --no-restore + - name: Pack + run: dotnet pack --configuration Release --no-restore + - name: Save Artifact + uses: actions/upload-artifact@v3 + with: + name: nupkg + path: ./Float.Core/obj/Release/ + retention-days: 5 - name: Test - run: dotnet test --configuration Release --no-build --verbosity normal --logger:"trx;" + run: dotnet test --configuration MAUI --no-restore -f net7.0 --no-build --verbosity normal --logger:"trx;" - name: Publish Test Results uses: EnricoMi/publish-unit-test-result-action@v2 if: always() diff --git a/Float.Core.Tests/Float.Core.Tests.csproj b/Float.Core.Tests/Float.Core.Tests.csproj index 9d16ce2..d4cc849 100644 --- a/Float.Core.Tests/Float.Core.Tests.csproj +++ b/Float.Core.Tests/Float.Core.Tests.csproj @@ -1,6 +1,6 @@ - netcoreapp3.1;net6.0;net7.0 + netcoreapp3.1;net7.0 false 9.0 true diff --git a/Float.Core.sln b/Float.Core.sln index 30db125..ed9e683 100644 --- a/Float.Core.sln +++ b/Float.Core.sln @@ -3,27 +3,42 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Float.Core", "Float.Core\Float.Core.csproj", "{0AF193E3-D9AF-4551-B853-177F15FDC639}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Float.Core.Tests", "Float.Core.Tests\Float.Core.Tests.csproj", "{CD4538B9-EBD5-4340-B44A-890DDCEFC31E}" +Project("{9344BDBB-3E7F-41FC-A0DD-8665D75EE146}") = "Float.Core.Tests", "Float.Core.Tests\Float.Core.Tests.csproj", "{0302630F-9229-48C3-BF66-0A8E7384A3DF}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU + MAUI|Any CPU = MAUI|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0AF193E3-D9AF-4551-B853-177F15FDC639}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0AF193E3-D9AF-4551-B853-177F15FDC639}.Debug|Any CPU.Build.0 = Debug|Any CPU {0AF193E3-D9AF-4551-B853-177F15FDC639}.Release|Any CPU.ActiveCfg = Release|Any CPU {0AF193E3-D9AF-4551-B853-177F15FDC639}.Release|Any CPU.Build.0 = Release|Any CPU - {CD4538B9-EBD5-4340-B44A-890DDCEFC31E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CD4538B9-EBD5-4340-B44A-890DDCEFC31E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CD4538B9-EBD5-4340-B44A-890DDCEFC31E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CD4538B9-EBD5-4340-B44A-890DDCEFC31E}.Release|Any CPU.Build.0 = Release|Any CPU + {0AF193E3-D9AF-4551-B853-177F15FDC639}.MAUI|Any CPU.ActiveCfg = MAUI|Any CPU + {0AF193E3-D9AF-4551-B853-177F15FDC639}.MAUI|Any CPU.Build.0 = MAUI|Any CPU + {0302630F-9229-48C3-BF66-0A8E7384A3DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0302630F-9229-48C3-BF66-0A8E7384A3DF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0302630F-9229-48C3-BF66-0A8E7384A3DF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0302630F-9229-48C3-BF66-0A8E7384A3DF}.Release|Any CPU.Build.0 = Release|Any CPU + {0302630F-9229-48C3-BF66-0A8E7384A3DF}.MAUI|Any CPU.ActiveCfg = MAUI|Any CPU EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution Policies = $0 $0.StandardHeader = $1 $1.IncludeInNewFiles = False $0.VersionControlPolicy = $2 + $0.DotNetNamingPolicy = $3 + $3.DirectoryNamespaceAssociation = PrefixedHierarchical + $0.TextStylePolicy = $4 + $4.inheritsSet = null + $4.scope = text/x-csharp + $0.CSharpFormattingPolicy = $5 + $5.scope = text/x-csharp + $0.TextStylePolicy = $6 + $6.FileWidth = 80 + $6.TabsToSpaces = True + $6.scope = text/plain EndGlobalSection EndGlobal diff --git a/Float.Core/Float.Core.csproj b/Float.Core/Float.Core.csproj index ec13c4a..4a8621b 100644 --- a/Float.Core/Float.Core.csproj +++ b/Float.Core/Float.Core.csproj @@ -1,6 +1,6 @@ - netstandard2;net6.0;net7.0 + netstandard2;net7.0 Float.Core Float Common utility code used by Float projects. @@ -14,6 +14,7 @@ 1.0.0 true + Release;MAUI;Debug @@ -31,6 +32,23 @@ MIT readme.md + + true + TRACE;RELEASE; + + + obj\MAUI + true + false + bin\MAUI + TRACE;DEBUG;MAUI; + 4 + bin\MAUI\Float.Core.xml + + + + TRACE;DEBUG; + diff --git a/Float.Core/UX/Coordinator.cs b/Float.Core/UX/Coordinator.cs index 552ab4e..a157755 100644 --- a/Float.Core/UX/Coordinator.cs +++ b/Float.Core/UX/Coordinator.cs @@ -59,6 +59,14 @@ public abstract class Coordinator : ICoordinator /// true if is finished; otherwise, false. protected bool IsFinished => isFinished; + /// + /// Gets or sets the event args that are pending a finish. + /// + /// + /// The event args that are pending a finish. + /// + protected EventArgs WaitingToFinishEventArgs { get; set; } + /// public virtual void Start(INavigationContext context) { @@ -98,6 +106,36 @@ public virtual void Start() isStarted = true; } + /// + public ICoordinator.CoordinatorRequestFinishStatus RequestFinish(EventArgs args) + { + return HandleFinishRequested(this, args); + } + + /// + /// Handles when a finish is requested. + /// + /// The coordinator that has requested this coordinator to finish. + /// The event args. + /// A value indicating whether this finished. + protected virtual ICoordinator.CoordinatorRequestFinishStatus HandleFinishRequested(ICoordinator coordinator, EventArgs eventArgs) + { + if (this == coordinator) + { + if (managedPage == null) + { + Finish(eventArgs); + return ICoordinator.CoordinatorRequestFinishStatus.FinishedImmediately; + } + + WaitingToFinishEventArgs = eventArgs; + NavigationContext.Reset(false); + return ICoordinator.CoordinatorRequestFinishStatus.PendingFinish; + } + + return ICoordinator.CoordinatorRequestFinishStatus.WillNotFinish; + } + /// /// Returning a page here will allow the coordinator to automatically /// manage itself based on the state of the UI. @@ -131,6 +169,7 @@ protected virtual void Finish(EventArgs args) } managedPage = null; + WaitingToFinishEventArgs = null; if (NavigationContext != null) { @@ -210,15 +249,26 @@ void HandleNavigation(object sender, NavigationEventArgs args) case NavigationEventArgs.NavigationType.Popped: if (args.Page == managedPage && !IsFinished) { - Finish(EventArgs.Empty); + if (WaitingToFinishEventArgs == null) + { + Finish(EventArgs.Empty); + return; + } + + Finish(WaitingToFinishEventArgs); } break; - case NavigationEventArgs.NavigationType.Reset: if (args.Page != managedPage && !IsFinished) { - Finish(EventArgs.Empty); + if (WaitingToFinishEventArgs == null) + { + Finish(EventArgs.Empty); + return; + } + + Finish(WaitingToFinishEventArgs); } break; diff --git a/Float.Core/UX/CoordinatorParent.cs b/Float.Core/UX/CoordinatorParent.cs index 0fa9386..b9955e1 100644 --- a/Float.Core/UX/CoordinatorParent.cs +++ b/Float.Core/UX/CoordinatorParent.cs @@ -117,6 +117,22 @@ public override string ToString() return $"[{GetType()}, Children: {string.Join(",", childCoordinators)}]"; } + /// + protected override ICoordinator.CoordinatorRequestFinishStatus HandleFinishRequested(ICoordinator coordinator, EventArgs eventArgs) + { + WaitingToFinishEventArgs = eventArgs; + + foreach (var eachChild in ChildCoordinators) + { + if (eachChild is Coordinator childCoordinator) + { + childCoordinator.RequestFinish(eventArgs); + } + } + + return base.HandleFinishRequested(coordinator, eventArgs); + } + /// protected override void Finish(EventArgs args) { @@ -149,6 +165,12 @@ protected virtual void HandleChildFinish(object sender, EventArgs args) { RemoveChild(child); } + + if (!HasChildren && WaitingToFinishEventArgs != null) + { + Finish(WaitingToFinishEventArgs); + WaitingToFinishEventArgs = null; + } } } } diff --git a/Float.Core/UX/ICoordinator.cs b/Float.Core/UX/ICoordinator.cs index c1cb38c..825e88f 100644 --- a/Float.Core/UX/ICoordinator.cs +++ b/Float.Core/UX/ICoordinator.cs @@ -18,10 +18,43 @@ public interface ICoordinator /// event EventHandler Finished; + /// + /// An enum for the possible results of a coordinator's RequestFinish. + /// + public enum CoordinatorRequestFinishStatus + { + /// + /// The coordinator RequestFinish finished immediately. + /// + FinishedImmediately, + + /// + /// The coordinator RequestFinish is pending a finish. + /// + PendingFinish, + + /// + /// The coordinator RequestFinish will not complete. + /// + WillNotFinish, + + /// + /// The coordinator RequestFinish's status is unknown. + /// + Unknown, + } + /// /// Implementing classes should use this to start this coordinator. /// /// The navigation context for this coordinator. void Start(INavigationContext navigationContext); + + /// + /// Requests that a coordinator will finish. + /// + /// The event args. + /// A task, with a boolean indicating whether this did finish. + CoordinatorRequestFinishStatus RequestFinish(EventArgs eventArgs); } }