public void ShowView(ViewWithData data) { View.ViewModel?.Initialize(data); }
void LoadSingleView(UIViewType type, ViewWithData data) { Stop(); Control = uiProvider.GetView(type, data); }
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
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(); }
protected void NotifyOpen(ViewWithData id) { open.OnNext(id); open.OnCompleted(); }
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)); }
/// <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); } }
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); }
public void Initialize([AllowNull] ViewWithData data) { Title = "GitHub"; Reload(data).Forget(); }
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); }
public IView GetView(UIViewType which, ViewWithData data = null) => theRealProvider.GetView(which, data);
public IUIController Configure(UIControllerFlow flow, IConnection connection = null, ViewWithData data = null) => theRealProvider.Configure(flow, connection, data);
public void Initialize(ViewWithData data) { }