Пример #1
0
 public void ShowView(ViewWithData data)
 {
     View.ViewModel?.Initialize(data);
 }
Пример #2
0
 void LoadSingleView(UIViewType type, ViewWithData data)
 {
     Stop();
     Control = uiProvider.GetView(type, data);
 }
Пример #3
0
        void RunView(UIViewType viewType, ViewWithData arg = null)
        {
            if (requestedTarget?.ViewType == viewType || (requestedTarget?.ViewType == UIViewType.None && requestedTarget?.MainFlow == CurrentFlow))
            {
                arg = requestedTarget;
            }

            if (arg == null)
            {
                arg = new ViewWithData {
                    ActiveFlow = activeFlow, MainFlow = selectedFlow, ViewType = viewType
                }
            }
            ;
            bool firstTime = CreateViewAndViewModel(viewType, arg);
            var  view      = GetObjectsForFlow(activeFlow)[viewType].View;

            transition.OnNext(new LoadData
            {
                Flow = activeFlow,
                View = view,
                Data = arg
            });

            // controller might have been stopped in the OnNext above
            if (IsStopped)
            {
                return;
            }

            // if it's not the first time we've shown this view, no need
            // to set it up
            if (!firstTime)
            {
                return;
            }

            SetupView(viewType, view.ViewModel);
        }

        void SetupView(UIViewType viewType, IViewModel viewModel)
        {
            var list      = GetObjectsForFlow(activeFlow);
            var pair      = list[viewType];
            var hasDone   = viewModel as IHasDone;
            var hasCancel = viewModel as IHasCancel;

            // 2FA is set up when login is set up, so nothing to do
            if (viewType == UIViewType.TwoFactor)
            {
                return;
            }

            // we're setting up the login dialog, we need to setup the 2fa as
            // well to continue the flow if it's needed, since the
            // authenticationresult callback won't happen until
            // everything is done
            if (viewType == UIViewType.Login)
            {
                var pair2fa = list[UIViewType.TwoFactor];
                pair2fa.AddHandler(((IDialogViewModel)pair2fa.ViewModel).WhenAny(x => x.IsShowing, x => x.Value)
                                   .Where(x => x)
                                   .ObserveOn(RxApp.MainThreadScheduler)
                                   .Subscribe(_ => Fire(Trigger.Next)));

                pair2fa.AddHandler(((IHasCancel)pair2fa.ViewModel).Cancel
                                   .ObserveOn(RxApp.MainThreadScheduler)
                                   .Subscribe(_ => Fire(uiStateMachine.CanFire(Trigger.Cancel) ? Trigger.Cancel : Trigger.Finish)));

                if (hasDone != null)
                {
                    pair.AddHandler(hasDone.Done
                                    .ObserveOn(RxApp.MainThreadScheduler)
                                    .Subscribe(_ => Fire(Trigger.Finish)));
                }
            }
            else if (hasDone != null)
            {
                pair.AddHandler(hasDone.Done
                                .ObserveOn(RxApp.MainThreadScheduler)
                                .Subscribe(_ => Fire(uiStateMachine.CanFire(Trigger.Next) ? Trigger.Next : Trigger.Finish)));
            }

            if (hasCancel != null)
            {
                pair.AddHandler(hasCancel.Cancel
                                .ObserveOn(RxApp.MainThreadScheduler)
                                .Subscribe(_ => Fire(uiStateMachine.CanFire(Trigger.Cancel) ? Trigger.Cancel : Trigger.Finish)));
            }
        }

        /// <summary>
        /// Creates View/ViewModel instances for the specified <paramref name="viewType"/> if they
        /// haven't been created yet in the current flow
        /// </summary>
        /// <param name="viewType"></param>
        /// <returns>true if the View/ViewModel didn't exist and had to be created</returns>
        bool CreateViewAndViewModel(UIViewType viewType, ViewWithData data = null)
        {
            var list = GetObjectsForFlow(activeFlow);

            if (viewType == UIViewType.Login)
            {
                if (!list.ContainsKey(viewType))
                {
                    var d = factory.CreateViewAndViewModel(UIViewType.TwoFactor);
                    list.Add(UIViewType.TwoFactor, d);
                }
            }

            // 2fa view/viewmodel is created when login is created 'cause login needs the 2fa viewmodel
            // so the only thing we want to do is connect the viewmodel to the view when it's showing
            else if (viewType == UIViewType.TwoFactor)
            {
                var d = list[viewType];
                if (d.View.ViewModel == null)
                {
                    d.ViewModel.Initialize(data);
                    d.View.DataContext = d.ViewModel;
                }
            }

            IUIPair pair      = null;
            var     firstTime = !list.TryGetValue(viewType, out pair);

            if (firstTime)
            {
                pair = factory.CreateViewAndViewModel(viewType);
            }

            pair.ViewModel.Initialize(data);

            if (firstTime)
            {
                pair.View.DataContext = pair.ViewModel;
                list.Add(viewType, pair);
            }

            return(firstTime);
        }

        /// <summary>
        /// Returns the view/viewmodel pair for a given flow
        /// </summary>
        Dictionary <UIViewType, IUIPair> GetObjectsForFlow(UIControllerFlow flow)
        {
            Dictionary <UIViewType, IUIPair> list;

            if (!uiObjects.TryGetValue(flow, out list))
            {
                list = new Dictionary <UIViewType, IUIPair>();
                uiObjects.Add(flow, list);
            }
            return(list);
        }

        void Fire(Trigger next, ViewWithData arg = null)
        {
            Debug.WriteLine("Firing {0} from {1} ({2})", next, uiStateMachine.State, GetHashCode());
            if (triggers.ContainsKey(next))
            {
                uiStateMachine.Fire(triggers[next], arg);
            }
            else
            {
                uiStateMachine.Fire(next);
            }
        }

        UIViewType Go(Trigger trigger)
        {
            return(Go(trigger, activeFlow));
        }

        UIViewType Go(Trigger trigger, UIControllerFlow flow)
        {
            var m = machines[flow];

            Debug.WriteLine("Firing {0} from {1} for flow {2} ({3})", trigger, m.State, flow, GetHashCode());
            m.Fire(trigger);
            return(m.State);
        }

        void Reset()
        {
            if (connectionAdded != null)
            {
                connectionManager.Connections.CollectionChanged -= connectionAdded;
            }
            connectionAdded = null;

            var tr  = transition;
            var cmp = completion;

            transition = null;
            completion = null;
            disposables.Clear();
            tr?.Dispose();
            cmp?.Dispose();
            stopping   = false;
            connection = null;
        }

        bool disposed; // To detect redundant calls
Пример #4
0
 public void Initialize(ViewWithData data)
 {
     // Nothing to do here: initialized in constructor.
 }
        void DoCreatePullRequest()
        {
            var d = new ViewWithData(UIControllerFlow.PullRequestCreation);

            navigate.OnNext(d);
        }
 public override void Initialize(ViewWithData data)
 {
     base.Initialize(data);
     Load().Forget();
 }
Пример #7
0
 protected void NotifyOpen(ViewWithData id)
 {
     open.OnNext(id);
     open.OnCompleted();
 }
Пример #8
0
 public virtual void Initialize([AllowNull] ViewWithData data)
 {
 }
 public override void Initialize([AllowNull] ViewWithData data)
 {
     System.Windows.MessageBox.Show(String.Format(CultureInfo.InvariantCulture, "{0}", data.Data));
 }
Пример #10
0
        /// <summary>
        /// This method is reentrant, so all await calls need to be done before
        /// any actions are performed on the data. More recent calls to this method
        /// will cause previous calls pending on await calls to exit early.
        /// </summary>
        /// <returns></returns>
        async Task Reload([AllowNull] ViewWithData data = null, bool navigating = false)
        {
            if (!initialized)
            {
                return;
            }

            latestReloadCallId++;
            var reloadCallId = latestReloadCallId;

            navigatingViaArrows = navigating;

            if (RepositoryOrigin == RepositoryOrigin.Unknown)
            {
                var origin = await GetRepositoryOrigin();

                if (reloadCallId != latestReloadCallId)
                {
                    return;
                }

                RepositoryOrigin = origin;
            }

            var connection = await connectionManager.LookupConnection(ActiveRepo);

            if (reloadCallId != latestReloadCallId)
            {
                return;
            }

            if (connection == null)
            {
                IsLoggedIn = false;
            }
            else
            {
                var isLoggedIn = await connection.IsLoggedIn(hosts);

                if (reloadCallId != latestReloadCallId)
                {
                    return;
                }

                IsLoggedIn = isLoggedIn;
            }

            if (RepositoryOrigin == UI.RepositoryOrigin.NonGitRepository)
            {
                LoadView(UIViewType.NotAGitRepository);
            }
            else if (RepositoryOrigin == UI.RepositoryOrigin.Other)
            {
                LoadView(UIViewType.NotAGitHubRepository);
            }
            else if (!IsLoggedIn)
            {
                LoadView(UIViewType.LoggedOut);
            }
            else
            {
                LoadView(data?.ActiveFlow ?? DefaultControllerFlow, connection, data);
            }
        }
Пример #11
0
        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);
        }
Пример #12
0
 public void Initialize([AllowNull] ViewWithData data)
 {
     Title = "GitHub";
     Reload(data).Forget();
 }
Пример #13
0
        public IUIController Configure(UIControllerFlow flow, IConnection connection = null, ViewWithData data = null)
        {
            var controller = new UIController(serviceProvider);

            disposables.Add(controller);
            var listener = controller.Configure(flow, connection, data).Publish().RefCount();

            listener.Subscribe(_ => { }, () =>
            {
                StopUI(controller);
            });

            // 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
            listener
            .Where(c => c.Flow == UIControllerFlow.Authentication)
            .ObserveOn(RxApp.TaskpoolScheduler)
            .Subscribe(c =>
            {
                // nothing to do, we already have a dialog
                if (windowController != null)
                {
                    return;
                }
                RunModalDialogForAuthentication(c.Flow, listener, c).Forget();
            });

            return(controller);
        }
Пример #14
0
 public IView GetView(UIViewType which, ViewWithData data = null) => theRealProvider.GetView(which, data);
Пример #15
0
 public IUIController Configure(UIControllerFlow flow, IConnection connection = null, ViewWithData data = null) => theRealProvider.Configure(flow, connection, data);
 public void Initialize(ViewWithData data)
 {
 }