void LoadView(UIControllerFlow flow, IConnection connection = null, ViewWithData data = null, UIViewType type = UIViewType.None)
        {
            // if we're loading a single view or a different flow, we need to stop the current controller
            var restart = flow == UIControllerFlow.None || uiController?.SelectedFlow != flow;

            if (restart)
            {
                Stop();
            }

            // if there's no selected flow, then just load a view directly
            if (flow == UIControllerFlow.None)
            {
                var factory = ServiceProvider.GetExportedValue <IUIFactory>();
                var c       = factory.CreateViewAndViewModel(type);
                c.View.DataContext = c.ViewModel;
                Control            = c.View;
            }
            // it's a new flow!
            else if (restart)
            {
                StartFlow(flow, connection, data);
            }
            // navigate to a requested view within the currently running uiController
            else
            {
                uiController.Jump(data ?? navStack[currentNavItem]);
            }
        }
        async Task Reload([AllowNull] ViewWithData data = null, bool navigating = false)
        {
            navigatingViaArrows = navigating;

            if (!IsGitHubRepo.HasValue)
            {
                IsGitHubRepo = await IsAGitHubRepo();
            }

            if (!IsGitHubRepo.Value)
            {
                if (uiController != null)
                {
                    Stop();
                    //var factory = ServiceProvider.GetExportedValue<IUIFactory>();
                    //var c = factory.CreateViewAndViewModel(UIViewType.LoggedOut);
                    //Control = c.View;
                }
                return;
            }

            var connection = await connectionManager.LookupConnection(ActiveRepo);

            IsLoggedIn = await connection.IsLoggedIn(hosts);

            if (IsLoggedIn)
            {
                if (uiController == null || (data != null && data.ActiveFlow != uiController.CurrentFlow))
                {
                    StartFlow(data?.ActiveFlow ?? UIControllerFlow.PullRequests, connection, data);
                }
                else if (data != null || currentNavItem >= 0)
                {
                    uiController.Jump(data ?? navStack[currentNavItem]);
                }
            }
            else
            {
                var factory = ServiceProvider.GetExportedValue <IUIFactory>();
                var c       = factory.CreateViewAndViewModel(UIViewType.LoggedOut);
                Control = c.View;
            }
            return;
        }
        void StartFlow(UIControllerFlow controllerFlow, [AllowNull] IConnection conn, ViewWithData data = null)
        {
            Stop();

            if (conn == null)
            {
                return;
            }

            switch (controllerFlow)
            {
            case UIControllerFlow.PullRequests:
                Title = Resources.PullRequestsNavigationItemText;
                break;

            default:
                Title = "GitHub";
                break;
            }

            var uiProvider = ServiceProvider.GetExportedValue <IUIProvider>();
            var factory    = uiProvider.GetService <IExportFactoryProvider>();
            var uiflow     = factory.UIControllerFactory.CreateExport();

            disposables.Add(uiflow);
            uiController = uiflow.Value;
            var creation = uiController.SelectFlow(controllerFlow).Publish().RefCount();

            // if the flow is authentication, we need to show the login dialog. and we can't
            // block the main thread on the subscriber, it'll block other handlers, so we're doing
            // this on a separate thread and posting the dialog to the main thread
            creation
            .Where(c => uiController.CurrentFlow == UIControllerFlow.Authentication)
            .ObserveOn(RxApp.TaskpoolScheduler)
            .Subscribe(c =>
            {
                // nothing to do, we already have a dialog
                if (windowController != null)
                {
                    return;
                }
                syncContext.Post(_ =>
                {
                    windowController = new WindowController(creation,
                                                            __ => uiController.CurrentFlow == UIControllerFlow.Authentication,
                                                            ___ => uiController.CurrentFlow != UIControllerFlow.Authentication);
                    windowController.WindowStartupLocation = WindowStartupLocation.CenterOwner;
                    windowController.Load(c.View);
                    windowController.ShowModal();
                    windowController = null;
                }, null);
            });

            creation
            .Where(c => uiController.CurrentFlow != UIControllerFlow.Authentication)
            .Subscribe(c =>
            {
                if (!navigatingViaArrows)
                {
                    if (c.Direction == LoadDirection.Forward)
                    {
                        GoForward(c.Data);
                    }
                    else if (c.Direction == LoadDirection.Back)
                    {
                        GoBack();
                    }
                }
                UpdateToolbar();

                Control = c.View;
            });

            if (data != null)
            {
                uiController.Jump(data);
            }
            uiController.Start(conn);
        }
        void StartFlow(UIControllerFlow controllerFlow, [AllowNull]IConnection conn, ViewWithData data = null)
        {
            Stop();

            if (conn == null)
                return;

            var uiProvider = ServiceProvider.GetService<IUIProvider>();
            var factory = uiProvider.GetService<IExportFactoryProvider>();
            var uiflow = factory.UIControllerFactory.CreateExport();
            disposables.Add(uiflow);
            uiController = uiflow.Value;
            var creation = uiController.SelectFlow(controllerFlow).Publish().RefCount();

            // if the flow is authentication, we need to show the login dialog. and we can't
            // block the main thread on the subscriber, it'll block other handlers, so we're doing
            // this on a separate thread and posting the dialog to the main thread
            creation
                .Where(c => uiController.CurrentFlow == UIControllerFlow.Authentication)
                .ObserveOn(RxApp.TaskpoolScheduler)
                .Subscribe(c =>
                {
                    // nothing to do, we already have a dialog
                    if (windowController != null)
                        return;
                    syncContext.Post(_ =>
                    {
                        windowController = new WindowController(creation,
                            __ => uiController.CurrentFlow == UIControllerFlow.Authentication,
                            ___ => uiController.CurrentFlow != UIControllerFlow.Authentication);
                        windowController.WindowStartupLocation = WindowStartupLocation.CenterOwner;
                        windowController.Load(c.View);
                        windowController.ShowModal();
                        windowController = null;
                    }, null);
                });

            creation
                .Where(c => uiController.CurrentFlow != UIControllerFlow.Authentication)
                .Subscribe(c =>
                {
                    if (!navigatingViaArrows)
                    {
                        if (c.Direction == LoadDirection.Forward)
                            GoForward(c.Data);
                        else if (c.Direction == LoadDirection.Back)
                            GoBack();
                    }
                    UpdateToolbar();

                    Control = c.View;
                });

            if (data != null)
                uiController.Jump(data);
            uiController.Start(conn);
        }