Ejemplo n.º 1
0
        /// <summary>
        /// Calls <see cref="StackNavigatorExtensions.Navigate{TViewModel}(IStackNavigator, CancellationToken, Func{TViewModel}, bool)"/> on this <see cref="ISectionsNavigator"/>'s active stack navigator.
        /// </summary>
        /// <param name="sectionsNavigator">The sections navigator.</param>
        /// <param name="ct">The cancellation token.</param>
        /// <param name="viewModelProvider">The method to invoke to instanciate the ViewModel.</param>
        /// <param name="suppressTransition">Whether to suppress the navigation transition.</param>
        public static async Task <TViewModel> Navigate <TViewModel>(this ISectionsNavigator sectionsNavigator, CancellationToken ct, Func <TViewModel> viewModelProvider, bool suppressTransition = false)
            where TViewModel : INavigableViewModel
        {
            var navigator = GetActiveStackNavigator(sectionsNavigator);

            return(await navigator.Navigate(ct, viewModelProvider, suppressTransition));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Opens a new modal.
        /// </summary>
        /// <typeparam name="TViewModel">The type of the view model.</typeparam>
        /// <param name="sectionsNavigator">The sections navigator.</param>
        /// <param name="ct"></param>
        /// <param name="viewModelProvider">The method invoked to instanciate the new ViewModel.</param>
        /// <param name="priority">The modal's priority.</param>
        /// <param name="name">The modal's name.</param>
        /// <returns>The newly created ViewModel instance.</returns>
        public static async Task <TViewModel> OpenModal <TViewModel>(this ISectionsNavigator sectionsNavigator, CancellationToken ct, Func <TViewModel> viewModelProvider, int?priority = null, string name = null)
            where TViewModel : INavigableViewModel
        {
            var modalNavigator = await sectionsNavigator.OpenModal(ct, SectionsNavigatorRequest.GetOpenModalRequest(StackNavigatorRequest.GetNavigateRequest(viewModelProvider, suppressTransition: true), name, priority));

            // Note that modalNavigator can be null if the OpenModal gets cancelled.
            return((TViewModel)modalNavigator?.GetActiveViewModel());
        }
 /// <summary>
 /// Gets an observable of the last page type from currently active section.
 /// The observable pushes a value whenever a navigation request is processed with the type of the last page ViewModel.
 /// </summary>
 /// <returns>An observable of types.</returns>
 public static IObservable <Type> ObserveActiveSectionLastPageType(this ISectionsNavigator sectionsNavigator)
 {
     return(sectionsNavigator
            .ObserveStateChanged()
            .Where(args => args.EventArgs.CurrentState.LastRequestState == NavigatorRequestState.Processed)
            .Select(args =>
     {
         var state = args.EventArgs.CurrentState;
         return state.ActiveSection?.State.Stack.LastOrDefault()?.ViewModel.GetType();
     })
            .StartWith(sectionsNavigator.State.ActiveSection?.State.Stack.LastOrDefault()?.ViewModel.GetType()));
 }
Ejemplo n.º 4
0
 /// <summary>
 /// Executes back action depending on top-most frame state.
 /// </summary>
 /// <remarks>
 /// Priorities:
 /// <list type="number">
 /// <item>Navigates back within the modal, if possible.</item>
 /// <item>Closes the modal, if possible.</item>
 /// <item>Navigates back within a section.</item>
 /// </list>
 /// This is useful when dealing with hardware back buttons.
 /// </remarks>
 /// <param name="sectionsNavigator">The sections navigator.</param>
 /// <param name="ct">The cancellation token.</param>
 public static async Task NavigateBackOrCloseModal(this ISectionsNavigator sectionsNavigator, CancellationToken ct)
 {
     if (sectionsNavigator.State.ActiveModal?.CanNavigateBack() ?? false)
     {
         await sectionsNavigator.State.ActiveModal.NavigateBack(ct);
     }
     else if (sectionsNavigator.State.ActiveModal != null)
     {
         await sectionsNavigator.CloseModal(ct);
     }
     else if (sectionsNavigator.State.ActiveSection?.CanNavigateBack() ?? false)
     {
         await sectionsNavigator.State.ActiveSection.NavigateBack(ct);
     }
     else
     {
         throw new InvalidOperationException($"Failed to NavigateBack or CloseModal. The active section '{sectionsNavigator.State.ActiveSection?.Name ?? "null"}' can't currently navigate back and there are no modals to close.");
     }
 }
Ejemplo n.º 5
0
 /// <summary>
 /// Creates a new instance of <see cref="SectionsNavigatorToStackNavigatorAdapter"/> from the specified adaptee.
 /// </summary>
 /// <param name="sectionsNavigator">The sections navigator to adapt into a <see cref="IStackNavigator"/>.</param>
 public SectionsNavigatorToStackNavigatorAdapter(ISectionsNavigator sectionsNavigator)
 {
     _sectionsNavigator = sectionsNavigator;
 }
Ejemplo n.º 6
0
 /// <summary>
 /// Gets an observable sequence that produces values whenever <see cref="ISectionsNavigator.StateChanged"/> is raised, pushing only the <see cref="SectionsNavigatorEventArgs.CurrentState"/> value.
 /// </summary>
 /// <param name="navigator">The sections navigator.</param>
 /// <returns>An observable sequence of <see cref="SectionsNavigatorState"/>.</returns>
 public static IObservable <SectionsNavigatorState> ObserveCurrentState(this ISectionsNavigator navigator)
 {
     return(navigator
            .ObserveStateChanged()
            .Select(pattern => pattern.EventArgs.CurrentState));
 }
Ejemplo n.º 7
0
 /// <summary>
 /// Gets an observable sequence that produces values whenever <see cref="ISectionsNavigator.StateChanged"/> is raised.
 /// </summary>
 /// <param name="navigator">The sections navigator.</param>
 /// <returns>An observable sequence of <see cref="EventPattern{SectionsNavigatorEventArgs}"/>.</returns>
 public static IObservable <EventPattern <SectionsNavigatorEventArgs> > ObserveStateChanged(this ISectionsNavigator navigator)
 {
     return(Observable
            .FromEventPattern <SectionsNavigatorStateChangedEventHandler, SectionsNavigatorEventArgs>(
                handler => navigator.StateChanged += handler,
                handler => navigator.StateChanged -= handler
                ));
 }
Ejemplo n.º 8
0
 /// <summary>
 /// Closes the top-most modal.
 /// </summary>
 /// <param name="sectionsNavigator">The sections navigator.</param>
 /// <param name="ct">The cancellation token.</param>
 public static async Task CloseModal(this ISectionsNavigator sectionsNavigator, CancellationToken ct)
 {
     await sectionsNavigator.CloseModal(ct, SectionsNavigatorRequest.GetCloseModalRequest(modalPriority: null));
 }
Ejemplo n.º 9
0
        /// <summary>
        /// Sets the active section using the provided section name and navigates.
        /// </summary>
        /// <typeparam name="TViewModel">The type of the view model.</typeparam>
        /// <param name="sectionsNavigator">The sections navigator.</param>
        /// <param name="ct">The cancellation token.</param>
        /// <param name="sectionName">The name of the section to set as active.</param>
        /// <param name="viewModelProvider">The method to make the view model instance. It will be invoked only if necessary.</param>
        /// <param name="returnToRoot">When this is true, the navigator will navigate back to the view model matching the type <typeparamref name="TViewModel"/>.</param>
        /// <returns>The stack navigator of the active section.</returns>
        public static async Task <ISectionStackNavigator> SetActiveSection <TViewModel>(this ISectionsNavigator sectionsNavigator,
                                                                                        CancellationToken ct,
                                                                                        string sectionName,
                                                                                        Func <TViewModel> viewModelProvider,
                                                                                        bool returnToRoot = false)
            where TViewModel : INavigableViewModel
        {
            if (ct.IsCancellationRequested)
            {
                typeof(SectionsNavigatorExtensions).Log().LogWarning($"Canceled 'SetActiveSection' operation to '{typeof(TViewModel).Name}' because of cancellation token.");

                return(null);
            }

            // No cancellation beyond this point.
            ct = CancellationToken.None;

            var sectionNavigator = sectionsNavigator.State.Sections[sectionName];

            if (sectionNavigator.State.Stack.LastOrDefault() == null)
            {
                // Create the default page if there's nothing in the section.
                await sectionNavigator.Navigate(ct, StackNavigatorRequest.GetNavigateRequest(viewModelProvider, suppressTransition: true));
            }
            else if (returnToRoot && sectionNavigator.State.Stack.Last().ViewModel.GetType() != typeof(TViewModel))
            {
                if (sectionNavigator.State.Stack.Any(e => e.ViewModel.GetType() == typeof(TViewModel)))
                {
                    // If the stack contains the root page of the section, remove all other entries and navigate back to it.
                    var indexesToRemove = sectionNavigator.State.Stack
                                          .Select((entry, index) => (entry, index))
                                          .Where(t => t.entry.ViewModel.GetType() != typeof(TViewModel) && t.index < sectionNavigator.State.Stack.Count - 1)
                                          .Select(t => t.index)
                                          .ToList();

                    await sectionNavigator.RemoveEntries(ct, indexesToRemove);

                    await sectionNavigator.NavigateBack(ct);
                }
                else
                {
                    // If the section root page isn't in the stack, clear everything and navigate to it.
                    await sectionNavigator.Navigate(ct, StackNavigatorRequest.GetNavigateRequest(viewModelProvider, suppressTransition: true, clearBackStack: true));
                }
            }

            return(await sectionsNavigator.SetActiveSection(ct, SectionsNavigatorRequest.GetSetActiveSectionRequest(sectionName)));
        }
Ejemplo n.º 10
0
 /// <summary>
 /// Sets the active section using the provided section name.
 /// </summary>
 /// <param name="sectionsNavigator">The sections navigator.</param>
 /// <param name="ct">The cancellation token.</param>
 /// <param name="sectionName">The name of the section to set as active.</param>
 /// <returns>The stack navigator of the active section.</returns>
 public static Task <ISectionStackNavigator> SetActiveSection(this ISectionsNavigator sectionsNavigator, CancellationToken ct, string sectionName)
 {
     return(sectionsNavigator.SetActiveSection(ct, SectionsNavigatorRequest.GetSetActiveSectionRequest(sectionName)));
 }
Ejemplo n.º 11
0
        /// <summary>
        /// Calls <see cref="StackNavigatorExtensions.GetActiveViewModel(IStackNavigator)"/> on this <see cref="ISectionsNavigator"/>'s active stack navigator.
        /// </summary>
        /// <param name="sectionsNavigator">The sections navigator.</param>
        public static INavigableViewModel GetActiveViewModel(this ISectionsNavigator sectionsNavigator)
        {
            var navigator = GetActiveStackNavigator(sectionsNavigator);

            return(navigator.GetActiveViewModel());
        }
Ejemplo n.º 12
0
 /// <summary>
 /// Calls <see cref="StackNavigatorExtensions.RemovePrevious(IStackNavigator, CancellationToken)"/> on this <see cref="ISectionsNavigator"/>'s active stack navigator.
 /// </summary>
 /// <param name="sectionsNavigator">The sections navigator.</param>
 /// <param name="ct">The cancellation token.</param>
 public static async Task RemovePrevious(this ISectionsNavigator sectionsNavigator, CancellationToken ct)
 {
     var navigator = GetActiveStackNavigator(sectionsNavigator);
     await navigator.RemovePrevious(ct);
 }
Ejemplo n.º 13
0
 /// <summary>
 /// Calls <see cref="IStackNavigator.NavigateBack(CancellationToken)"/> on this <see cref="ISectionsNavigator"/>'s active stack navigator.
 /// </summary>
 /// <param name="sectionsNavigator">The sections navigator.</param>
 /// <param name="ct">The cancellation token.</param>
 public static async Task NavigateBack(this ISectionsNavigator sectionsNavigator, CancellationToken ct)
 {
     var navigator = GetActiveStackNavigator(sectionsNavigator);
     await navigator.NavigateBack(ct);
 }
Ejemplo n.º 14
0
 /// <summary>
 /// Gets the active <see cref="IStackNavigator"/> of this <see cref="ISectionsNavigator"/>.
 /// </summary>
 /// <remarks>
 /// The result can be null if no navigator is active.
 /// </remarks>
 /// <param name="sectionsNavigator">The sections navigator.</param>
 public static IStackNavigator GetActiveStackNavigator(this ISectionsNavigator sectionsNavigator)
 {
     return(sectionsNavigator.State.GetActiveStackNavigator());
 }
Ejemplo n.º 15
0
 /// <summary>
 /// Gets whether the <see cref="ISectionsNavigator"/> can navigate back or close a modal.
 /// </summary>
 /// <remarks>
 /// This is useful when dealing with hardware back buttons.
 /// </remarks>
 /// <param name="sectionsNavigator">The sections navigator.</param>
 /// <returns>True if the navigator can navigate back or close a modal. False otherwise.</returns>
 public static bool CanNavigateBackOrCloseModal(this ISectionsNavigator sectionsNavigator)
 {
     return((sectionsNavigator.State.ActiveSection?.CanNavigateBack() ?? false) || sectionsNavigator.State.Modals.Any());
 }