void End(bool success) { uiProvider.RemoveService(typeof(IConnection)); completion?.OnNext(success); completion?.OnCompleted(); transition.OnCompleted(); }
CloneRequest ShowCloneDialog(IUIProvider uiProvider, IGitRepositoriesExt gitRepositories, ISimpleRepositoryModel repository = null) { string basePath = null; uiProvider.AddService(this, gitRepositories); var load = uiProvider.SetupUI(repository == null ? UIControllerFlow.Clone : UIControllerFlow.StartPageClone, null //TODO: set the connection corresponding to the repository if the repository is not null ); load.Subscribe(x => { if ((repository == null && x.Data.ViewType == Exports.UIViewType.Clone) || // fire the normal clone dialog (repository != null && x.Data.ViewType == Exports.UIViewType.StartPageClone) // fire the clone dialog for re-acquiring a repo ) { var vm = x.View.ViewModel as IBaseCloneViewModel; if (repository != null) { vm.SelectedRepository = repository; } x.View.Done.Subscribe(_ => { basePath = vm.BaseRepositoryPath; if (repository == null) { repository = vm.SelectedRepository; } }); } }); uiProvider.RunUI(); uiProvider.RemoveService(typeof(IGitRepositoriesExt), this); return(new CloneRequest(basePath, repository)); }
public UIController(IUIProvider uiProvider, IRepositoryHosts hosts, IExportFactoryProvider factory, IConnectionManager connectionManager, Lazy<ITwoFactorChallengeHandler> lazyTwoFactorChallengeHandler) { this.factory = factory; this.uiProvider = uiProvider; this.hosts = hosts; this.connectionManager = connectionManager; this.lazyTwoFactorChallengeHandler = lazyTwoFactorChallengeHandler; #if DEBUG if (Application.Current != null && !Splat.ModeDetector.InUnitTestRunner()) { var waitDispatcher = RxApp.MainThreadScheduler as WaitForDispatcherScheduler; if (waitDispatcher != null) { Debug.Assert(DispatcherScheduler.Current.Dispatcher == Application.Current.Dispatcher, "DispatcherScheduler is set correctly"); } else { Debug.Assert(((DispatcherScheduler)RxApp.MainThreadScheduler).Dispatcher == Application.Current.Dispatcher, "The MainThreadScheduler is using the wrong dispatcher"); } } #endif machine = new StateMachine<UIViewType, Trigger>(UIViewType.None); machine.Configure(UIViewType.Login) .OnEntry(() => { RunView(UIViewType.Login); }) .Permit(Trigger.Next, UIViewType.TwoFactor) // Added the following line to make it easy to login to both GitHub and GitHub Enterprise // in DesignTimeStyleHelper in order to test Publish. .Permit(Trigger.Cancel, UIViewType.End) .PermitIf(Trigger.Finish, UIViewType.End, () => currentFlow == UIControllerFlow.Authentication) .PermitIf(Trigger.Finish, UIViewType.Create, () => currentFlow == UIControllerFlow.Create) .PermitIf(Trigger.Finish, UIViewType.Clone, () => currentFlow == UIControllerFlow.Clone) .PermitIf(Trigger.Finish, UIViewType.Publish, () => currentFlow == UIControllerFlow.Publish); machine.Configure(UIViewType.TwoFactor) .SubstateOf(UIViewType.Login) .OnEntry(() => { RunView(UIViewType.TwoFactor); }) .Permit(Trigger.Cancel, UIViewType.End) .PermitIf(Trigger.Next, UIViewType.End, () => currentFlow == UIControllerFlow.Authentication) .PermitIf(Trigger.Next, UIViewType.Create, () => currentFlow == UIControllerFlow.Create) .PermitIf(Trigger.Next, UIViewType.Clone, () => currentFlow == UIControllerFlow.Clone) .PermitIf(Trigger.Next, UIViewType.Publish, () => currentFlow == UIControllerFlow.Publish); machine.Configure(UIViewType.Create) .OnEntry(() => { RunView(UIViewType.Create); }) .Permit(Trigger.Cancel, UIViewType.End) .Permit(Trigger.Next, UIViewType.End); machine.Configure(UIViewType.Clone) .OnEntry(() => { RunView(UIViewType.Clone); }) .Permit(Trigger.Cancel, UIViewType.End) .Permit(Trigger.Next, UIViewType.End); machine.Configure(UIViewType.Publish) .OnEntry(() => { RunView(UIViewType.Publish); }) .Permit(Trigger.Cancel, UIViewType.End) .Permit(Trigger.Next, UIViewType.End); machine.Configure(UIViewType.End) .OnEntry(() => { uiProvider.RemoveService(typeof(IConnection)); transition.OnCompleted(); }) .Permit(Trigger.Next, UIViewType.Finished); // it might be useful later to check which triggered // made us enter here (Cancel or Next) and set a final // result accordingly, which is why UIViewType.End only // allows a Next trigger machine.Configure(UIViewType.Finished); }
public UIController(IUIProvider uiProvider, IRepositoryHosts hosts, IExportFactoryProvider factory, IConnectionManager connectionManager, Lazy <ITwoFactorChallengeHandler> lazyTwoFactorChallengeHandler) { this.factory = factory; this.uiProvider = uiProvider; this.hosts = hosts; this.connectionManager = connectionManager; this.lazyTwoFactorChallengeHandler = lazyTwoFactorChallengeHandler; #if DEBUG if (Application.Current != null && !Splat.ModeDetector.InUnitTestRunner()) { var waitDispatcher = RxApp.MainThreadScheduler as WaitForDispatcherScheduler; if (waitDispatcher != null) { Debug.Assert(DispatcherScheduler.Current.Dispatcher == Application.Current.Dispatcher, "DispatcherScheduler is set correctly"); } else { Debug.Assert(((DispatcherScheduler)RxApp.MainThreadScheduler).Dispatcher == Application.Current.Dispatcher, "The MainThreadScheduler is using the wrong dispatcher"); } } #endif machine = new StateMachine <UIViewType, Trigger>(UIViewType.None); machine.Configure(UIViewType.Login) .OnEntry(() => { RunView(UIViewType.Login); }) .Permit(Trigger.Next, UIViewType.TwoFactor) // Added the following line to make it easy to login to both GitHub and GitHub Enterprise // in DesignTimeStyleHelper in order to test Publish. .Permit(Trigger.Cancel, UIViewType.End) .PermitIf(Trigger.Finish, UIViewType.End, () => currentFlow == UIControllerFlow.Authentication) .PermitIf(Trigger.Finish, UIViewType.Create, () => currentFlow == UIControllerFlow.Create) .PermitIf(Trigger.Finish, UIViewType.Clone, () => currentFlow == UIControllerFlow.Clone) .PermitIf(Trigger.Finish, UIViewType.Publish, () => currentFlow == UIControllerFlow.Publish); machine.Configure(UIViewType.TwoFactor) .SubstateOf(UIViewType.Login) .OnEntry(() => { RunView(UIViewType.TwoFactor); }) .Permit(Trigger.Cancel, UIViewType.End) .PermitIf(Trigger.Next, UIViewType.End, () => currentFlow == UIControllerFlow.Authentication) .PermitIf(Trigger.Next, UIViewType.Create, () => currentFlow == UIControllerFlow.Create) .PermitIf(Trigger.Next, UIViewType.Clone, () => currentFlow == UIControllerFlow.Clone) .PermitIf(Trigger.Next, UIViewType.Publish, () => currentFlow == UIControllerFlow.Publish); machine.Configure(UIViewType.Create) .OnEntry(() => { RunView(UIViewType.Create); }) .Permit(Trigger.Cancel, UIViewType.End) .Permit(Trigger.Next, UIViewType.End); machine.Configure(UIViewType.Clone) .OnEntry(() => { RunView(UIViewType.Clone); }) .Permit(Trigger.Cancel, UIViewType.End) .Permit(Trigger.Next, UIViewType.End); machine.Configure(UIViewType.Publish) .OnEntry(() => { RunView(UIViewType.Publish); }) .Permit(Trigger.Cancel, UIViewType.End) .Permit(Trigger.Next, UIViewType.End); machine.Configure(UIViewType.End) .OnEntry(() => { uiProvider.RemoveService(typeof(IConnection)); transition.OnCompleted(); }) .Permit(Trigger.Next, UIViewType.Finished); // it might be useful later to check which triggered // made us enter here (Cancel or Next) and set a final // result accordingly, which is why UIViewType.End only // allows a Next trigger machine.Configure(UIViewType.Finished); }
/// <summary> /// Configures the UI that gets loaded when entering a certain state and which state /// to go to for each trigger. Which state to go to depends on which ui flow state machine /// is currently active - when a trigger happens, the PermitDynamic conditions will /// lookup the currently active state machine from the list of available ones in `machines`, /// fire the requested trigger on it, and return the state that it went to, which causes /// `uiStateMachine` to load a new UI (or exit) /// There is a bit of redundant information regarding valid state transitions between this /// state machine and the individual state machines for each ui flow. This is unavoidable /// because permited transition triggers have to be explicit, so care should be taken to /// make sure permitted triggers per view here match the permitted triggers in the individual /// state machines. /// </summary> void ConfigureUIHandlingStates() { uiStateMachine.Configure(UIViewType.None) .OnEntry(tr => stopping = false) .PermitDynamic(Trigger.Next, () => { var loggedIn = connection != null && hosts.LookupHost(connection.HostAddress).IsLoggedIn; activeFlow = loggedIn ? mainFlow : UIControllerFlow.Authentication; return(Go(Trigger.Next)); }) .PermitDynamic(Trigger.Finish, () => Go(Trigger.Finish)); uiStateMachine.Configure(UIViewType.Clone) .OnEntry(tr => RunView(UIViewType.Clone, CalculateDirection(tr))) .PermitDynamic(Trigger.Next, () => Go(Trigger.Next)) .PermitDynamic(Trigger.Cancel, () => Go(Trigger.Cancel)) .PermitDynamic(Trigger.Finish, () => Go(Trigger.Finish)); uiStateMachine.Configure(UIViewType.Create) .OnEntry(tr => RunView(UIViewType.Create, CalculateDirection(tr))) .PermitDynamic(Trigger.Next, () => Go(Trigger.Next)) .PermitDynamic(Trigger.Cancel, () => Go(Trigger.Cancel)) .PermitDynamic(Trigger.Finish, () => Go(Trigger.Finish)); uiStateMachine.Configure(UIViewType.Publish) .OnEntry(tr => RunView(UIViewType.Publish, CalculateDirection(tr))) .PermitDynamic(Trigger.Next, () => Go(Trigger.Next)) .PermitDynamic(Trigger.Cancel, () => Go(Trigger.Cancel)) .PermitDynamic(Trigger.Finish, () => Go(Trigger.Finish)); uiStateMachine.Configure(UIViewType.PRList) .OnEntry(tr => RunView(UIViewType.PRList, CalculateDirection(tr))) .PermitDynamic(Trigger.Next, () => Go(Trigger.Next)) .PermitDynamic(Trigger.PRDetail, () => Go(Trigger.PRDetail)) .PermitDynamic(Trigger.PRCreation, () => Go(Trigger.PRCreation)) .PermitDynamic(Trigger.Cancel, () => Go(Trigger.Cancel)) .PermitDynamic(Trigger.Finish, () => Go(Trigger.Finish)); triggers.Add(Trigger.PRDetail, uiStateMachine.SetTriggerParameters <ViewWithData>(Trigger.PRDetail)); uiStateMachine.Configure(UIViewType.PRDetail) .OnEntryFrom(triggers[Trigger.PRDetail], (arg, tr) => RunView(UIViewType.PRDetail, CalculateDirection(tr), arg)) .PermitDynamic(Trigger.Next, () => Go(Trigger.Next)) .PermitDynamic(Trigger.Cancel, () => Go(Trigger.Cancel)) .PermitDynamic(Trigger.Finish, () => Go(Trigger.Finish)); uiStateMachine.Configure(UIViewType.PRCreation) .OnEntry(tr => RunView(UIViewType.PRCreation, CalculateDirection(tr))) .PermitDynamic(Trigger.Next, () => Go(Trigger.Next)) .PermitDynamic(Trigger.Cancel, () => Go(Trigger.Cancel)) .PermitDynamic(Trigger.Finish, () => Go(Trigger.Finish)); uiStateMachine.Configure(UIViewType.Login) .OnEntry(tr => RunView(UIViewType.Login, CalculateDirection(tr))) .PermitDynamic(Trigger.Next, () => Go(Trigger.Next)) .PermitDynamic(Trigger.Cancel, () => Go(Trigger.Cancel)) .PermitDynamic(Trigger.Finish, () => Go(Trigger.Finish)); uiStateMachine.Configure(UIViewType.TwoFactor) .OnEntry(tr => RunView(UIViewType.TwoFactor, CalculateDirection(tr))) .PermitDynamic(Trigger.Next, () => Go(Trigger.Next)) .PermitDynamic(Trigger.Cancel, () => Go(Trigger.Cancel)) .PermitDynamic(Trigger.Finish, () => Go(Trigger.Finish)); uiStateMachine.Configure(UIViewType.End) .OnEntryFrom(Trigger.Cancel, () => End(false)) .OnEntryFrom(Trigger.Next, () => End(true)) .OnEntryFrom(Trigger.Finish, () => End(true)) // clear all the views and viewmodels created by a subflow .OnExit(() => { // it's important to have the stopping flag set before we do this if (activeFlow == mainFlow) { completion?.OnNext(Success.Value); completion?.OnCompleted(); } DisposeFlow(activeFlow); if (activeFlow == mainFlow) { uiProvider.RemoveService(typeof(IConnection), this); transition.OnCompleted(); Reset(); } else { activeFlow = stopping || LoggedIn ? mainFlow : UIControllerFlow.Authentication; } }) .PermitDynamic(Trigger.Next, () => { // sets the state to None for the current flow var state = Go(Trigger.Next); if (activeFlow != mainFlow) { if (stopping) { // triggering the End state again so that it can clear up the main flow and really end state = Go(Trigger.Finish, mainFlow); } else { // sets the state to the first UI of the main flow or the auth flow, depending on whether you're logged in state = Go(Trigger.Next, LoggedIn ? mainFlow : UIControllerFlow.Authentication); } } return(state); }) .Permit(Trigger.Finish, UIViewType.None); }
public void RemoveService(Type t, object owner) => theRealProvider.RemoveService(t, owner);