1
votes

I am trying to implement a view/viewmodel that will be displayed while the application checks if the user is authenticated.

The code below ends up with multiple calls to the Router. Is there a problem with the test code in InternalIsAuthenticated? How can I implement this correct?

ViewModel:

public class LoadingViewModel : ReactiveObject, IRoutableViewModel
    {
        public string UrlPathSegment {
            get {
                return "Loading";
            }
        }

        public IScreen HostScreen { get; protected set; }

        public ReactiveCommand<bool> IsAuthenticatedCommand { get; protected set; }

        public LoadingViewModel (IScreen screen)
        {
            HostScreen = screen;
            IsAuthenticatedCommand = ReactiveCommand.CreateAsyncTask (async (_, ctx) => await InternalIsAuthenticated ());
            IsAuthenticatedCommand.Subscribe(next => {
                //called twice. ??
                HostScreen.Router.NavigateAndReset.Execute(new OnboardingViewModel(HostScreen));
            });
            IsAuthenticatedCommand.ThrownExceptions.Subscribe(ex => {
                Debug.WriteLine(ex.Message);
                UserError.Throw("oops");
            });

            //Error: nested push animation can result in corrupted navigation bar
            //Error: Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.
            //this.WhenAnyValue(x => x.UrlPathSegment)
            //  .Throttle(TimeSpan.FromSeconds(1), RxApp.MainThreadScheduler)
            //  .InvokeCommand(this, x => x.IsAuthenticatedCommand);

            //Error: nested push animation can result in corrupted navigation bar
            //Error: Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.
            this.IsAuthenticatedCommand.ExecuteAsyncTask ();

            //OnboardingView ends on top of LoadingView in the navigation stack.
            //HostScreen.Router.NavigateAndReset.Execute(new OnboardingViewModel(HostScreen));
        }

        private async Task<bool> InternalIsAuthenticated(){
            return await Task.Run(() => {return true;});
        }
    }

View:

public partial class LoadingView  : ContentPage, IViewFor<LoadingViewModel>
    {   
        public LoadingView ()
        {
            InitializeComponent ();
            this.WhenAnyValue (x => x.ViewModel).BindTo (this, x => x.BindingContext);
        }

        public LoadingViewModel ViewModel {
            get { return (LoadingViewModel)GetValue(ViewModelProperty); }
            set { SetValue(ViewModelProperty, value); }
        }
        public static readonly BindableProperty ViewModelProperty =
            BindableProperty.Create<LoadingView, LoadingViewModel>(x => x.ViewModel, default(LoadingViewModel), BindingMode.OneWay);

        object IViewFor.ViewModel {
            get { return ViewModel; }
            set { ViewModel = (LoadingViewModel)value; }
        }
    }
1

1 Answers

2
votes

If NavigateAndReset is getting called twice, maybe it's because you're creating two LoadingViewModels?