public void SpinnerShouldSpinWhileAppIsSearching() { (new TestScheduler()).With(sched => { // Here, we're going to create a dummy Observable that mocks // a web service call - mocking things that happen over time is // often tricky, but not with Rx! var searchObservable = Observable.Return(createSampleResults()) .Delay(TimeSpan.FromMilliseconds(5000), RxApp.TaskpoolScheduler); var command = new ReactiveAsyncCommand(); command.RegisterAsyncObservable(x => searchObservable); var fixture = new AppViewModel(command, searchObservable); // The spinner should be hidden on startup Assert.AreNotEqual(Visibility.Visible, fixture.SpinnerVisibility); // Invoke the command fixture.ExecuteSearch.Execute("Robot"); // Once we run the command, we should be showing the spinner sched.RunToMilliseconds(100); Assert.AreEqual(Visibility.Visible, fixture.SpinnerVisibility); // Fast forward to 6sec, the spinner should now be gone sched.RunToMilliseconds(6 * 1000); Assert.AreNotEqual(Visibility.Visible, fixture.SpinnerVisibility); }); }
public SearchViewModel(IScreen hostScreen, ILoginMethods loginMethods) { HostScreen = hostScreen; SearchResults = new ReactiveCollection<ISongTileViewModel>(); var playApi = loginMethods.CurrentAuthenticatedClient; if (playApi == null) { hostScreen.Router.Navigate.Execute(RxApp.GetService<IWelcomeViewModel>()); return; } var canSearch = this.WhenAny(x => x.SearchQuery, x => !String.IsNullOrWhiteSpace(x.Value)); PerformSearch = new ReactiveAsyncCommand(canSearch); this.ObservableForProperty(x => x.SearchQuery) .Throttle(TimeSpan.FromMilliseconds(700), RxApp.DeferredScheduler) .InvokeCommand(PerformSearch); var searchResults = PerformSearch.RegisterAsyncObservable(_ => playApi.Search(SearchQuery)); SearchResults = searchResults .Do(_ => SearchResults.Clear()) .SelectMany(list => list.ToObservable()) .LoggedCatch(this, Observable.Empty<Song>()) .CreateCollection(x => (ISongTileViewModel) new SongTileViewModel(x, playApi)); PerformSearch.ItemsInflight.StartWith(0) .Select(x => x > 0 ? Visibility.Visible : Visibility.Collapsed) .ToProperty(this, x => x.SearchBusySpinner); PerformSearch.ThrownExceptions.Subscribe(_ => { }); GoBack = new ReactiveCommand(); GoBack.InvokeCommand(hostScreen.Router.NavigateBack); }
public InsertGistViewModel() { //var client = new GitHubClient() { Username = "******", Password = "******" }; var privateImage = new BitmapImage(new Uri(@"pack://*****:*****@"pack://application:,,,/data/public.png")); _PublicPrivateIcon = this.WhenAny(x => x.IsPrivateGist, x => x.Value) .Select(x => x ? privateImage : publicImage) .ToProperty(this, x => x.PublicPrivateIcon); CreateGist = new ReactiveAsyncCommand(); CreateGist.RegisterAsyncObservable(_ => client.CreateGist(SelectionText, !IsPrivateGist)) .Select(x => x.html_url) .BindTo(this, x => x.LastGistUrl); CopyToClipboard = new ReactiveCommand( this.WhenAny(x => x.LastGistUrl, x => !String.IsNullOrWhiteSpace(x.Value))); CopyToClipboard.Subscribe(_ => Clipboard.SetText(LastGistUrl)); this.WhenAny(x => x.SelectionText, x => x.Value) .Where(_ => LastGistUrl != null) .Subscribe(_ => LastGistUrl = null); }
public void ChangingSearchTermShouldResultInSearchResults() { (new TestScheduler()).With(sched => { // Create a dummy Observable representing the actual query var searchObservable = Observable.Return(createSampleResults()) .Delay(TimeSpan.FromMilliseconds(5 * 1000), RxApp.TaskpoolScheduler); // Create a dummy command to pass to the ViewModel that returns // our Observable var command = new ReactiveAsyncCommand(); command.RegisterAsyncObservable(x => searchObservable); var fixture = new AppViewModel(command, searchObservable); Assert.IsTrue(fixture.SearchResults.Count == 0); fixture.SearchTerm = "Foo"; // At 2 seconds in, we shouldn't have results yet sched.RunToMilliseconds(2 * 1000); Assert.IsTrue(fixture.SearchResults.Count == 0); // At 10 seconds, we should have the sample results var sampleData = createSampleResults(); sched.RunToMilliseconds(10 * 1000); Assert.AreEqual(sampleData.Count, fixture.SearchResults.Count); // Make sure the two sequences are identical foreach (var item in sampleData.Zip(fixture.SearchResults, (expected, actual) => new { expected, actual })) { Assert.AreEqual(item.expected.Title, item.actual.Title); Assert.AreEqual(item.expected.Description, item.actual.Description); Assert.AreEqual(item.expected.Url, item.actual.Url); } }); }
public void MultipleSubscribersShouldntDecrementRefcountBelowZero() { (new TestScheduler()).With(sched => { var fixture = new ReactiveAsyncCommand(); var results = new List <int>(); bool[] subscribers = new[] { false, false, false, false, false }; var output = fixture.RegisterAsyncObservable(_ => Observable.Return(5).Delay(TimeSpan.FromMilliseconds(5000), sched)); output.Subscribe(x => results.Add(x)); Enumerable.Range(0, 5).Run(x => output.Subscribe(_ => subscribers[x] = true)); Assert.True(fixture.CanExecute(null)); fixture.Execute(null); sched.AdvanceToMs(2000); Assert.False(fixture.CanExecute(null)); sched.AdvanceToMs(6000); Assert.True(fixture.CanExecute(null)); Assert.True(results.Count == 1); Assert.True(results[0] == 5); Assert.True(subscribers.All(x => x)); }); }
public InsertGistViewModel() { //var client = new GitHubClient() { Username = "******", Password = "******" }; var privateImage = new BitmapImage(new Uri(@"pack://*****:*****@"pack://application:,,,/data/public.png")); _PublicPrivateIcon = this.WhenAny(x => x.IsPrivateGist, x => x.Value) .Select(x => x ? privateImage : publicImage) .ToProperty(this, x => x.PublicPrivateIcon); CreateGist = new ReactiveAsyncCommand(); CreateGist.RegisterAsyncObservable(_ => client.CreateGist(SelectionText, !IsPrivateGist)) .Select(x => x.html_url) .BindTo(this, x => x.LastGistUrl); CopyToClipboard = new ReactiveCommand( this.WhenAny(x => x.LastGistUrl, x => !String.IsNullOrWhiteSpace(x.Value))); CopyToClipboard.Subscribe(_ => Clipboard.SetText(LastGistUrl)); this.WhenAny(x => x.SelectionText, x => x.Value) .Where(_ => LastGistUrl != null) .Subscribe(_ => LastGistUrl = null); }
public void RAOShouldActuallyRunOnTheTaskpool() { var deferred = RxApp.DeferredScheduler; var taskpool = RxApp.TaskpoolScheduler; try { var testDeferred = new CountingTestScheduler(Scheduler.Immediate); var testTaskpool = new CountingTestScheduler(Scheduler.NewThread); RxApp.DeferredScheduler = testDeferred; RxApp.TaskpoolScheduler = testTaskpool; var fixture = new ReactiveAsyncCommand(); var result = fixture.RegisterAsyncObservable(x => Observable.Return((int)x * 5).Delay(TimeSpan.FromSeconds(1), RxApp.TaskpoolScheduler)); fixture.Execute(1); Assert.Equal(5, result.First()); Assert.True(testDeferred.ScheduledItems.Count >= 1); Assert.True(testTaskpool.ScheduledItems.Count >= 1); } finally { RxApp.DeferredScheduler = deferred; RxApp.TaskpoolScheduler = taskpool; } }
public MainWindowViewModel() { var noneInFlight = new BehaviorSubject<bool>(false); var updateManager = default(UpdateManager); this.WhenAny(x => x.UpdatePath, x => x.Value) .Where(x => !String.IsNullOrWhiteSpace(x)) .Throttle(TimeSpan.FromMilliseconds(700), RxApp.DeferredScheduler) .Subscribe(x => { if (updateManager != null) updateManager.Dispose(); updateManager = new UpdateManager(UpdatePath, "SampleUpdatingApp", FrameworkVersion.Net40); }); CheckForUpdate = new ReactiveAsyncCommand(noneInFlight); CheckForUpdate.RegisterAsyncObservable(_ => updateManager.CheckForUpdate()) .Subscribe(x => { UpdateInfo = x; DownloadedUpdateInfo = null; }); DownloadReleases = new ReactiveAsyncCommand(noneInFlight.Where(_ => UpdateInfo != null)); DownloadReleases.RegisterAsyncObservable(_ => updateManager.DownloadReleases(UpdateInfo.ReleasesToApply)) .Subscribe(_ => DownloadedUpdateInfo = UpdateInfo); ApplyReleases = new ReactiveAsyncCommand(noneInFlight.Where(_ => DownloadedUpdateInfo != null)); ApplyReleases.RegisterAsyncObservable(_ => updateManager.ApplyReleases(DownloadedUpdateInfo)); Observable.CombineLatest( CheckForUpdate.ItemsInflight.StartWith(0), DownloadReleases.ItemsInflight.StartWith(0), ApplyReleases.ItemsInflight.StartWith(0), this.WhenAny(x => x.UpdatePath, _ => 0), (a, b, c, _) => a + b + c ).Select(x => x == 0 && UpdatePath != null).Multicast(noneInFlight).Connect(); }
public void ChangingSearchTermShouldResultInSearchResults() { (new TestScheduler()).With(sched => { // Create a dummy Observable representing the actual query var searchObservable = Observable.Return(createSampleResults()) .Delay(TimeSpan.FromMilliseconds(5 * 1000), RxApp.TaskpoolScheduler); // Create a dummy command to pass to the ViewModel that returns // our Observable var command = new ReactiveAsyncCommand(); command.RegisterAsyncObservable(x => searchObservable); var fixture = new AppViewModel(command, searchObservable); Assert.IsTrue(fixture.SearchResults.Count == 0); fixture.SearchTerm = "Foo"; // At 2 seconds in, we shouldn't have results yet sched.RunToMilliseconds(2 * 1000); Assert.IsTrue(fixture.SearchResults.Count == 0); // At 10 seconds, we should have the sample results var sampleData = createSampleResults(); sched.RunToMilliseconds(10 * 1000); Assert.AreEqual(sampleData.Count, fixture.SearchResults.Count); // Make sure the two sequences are identical foreach(var item in sampleData.Zip(fixture.SearchResults, (expected, actual) => new { expected, actual })) { Assert.AreEqual(item.expected.Title, item.actual.Title); Assert.AreEqual(item.expected.Description, item.actual.Description); Assert.AreEqual(item.expected.Url, item.actual.Url); } }); }
public MainWindowViewModel() { var noneInFlight = new BehaviorSubject <bool>(false); var updateManager = default(UpdateManager); this.WhenAny(x => x.UpdatePath, x => x.Value) .Where(x => !String.IsNullOrWhiteSpace(x)) .Throttle(TimeSpan.FromMilliseconds(700), RxApp.DeferredScheduler) .Subscribe(x => { if (updateManager != null) { updateManager.Dispose(); } updateManager = new UpdateManager(UpdatePath, "SampleUpdatingApp", FrameworkVersion.Net40); }); CheckForUpdate = new ReactiveAsyncCommand(noneInFlight); CheckForUpdate.RegisterAsyncObservable(_ => updateManager.CheckForUpdate()) .Subscribe(x => { UpdateInfo = x; DownloadedUpdateInfo = null; }); DownloadReleases = new ReactiveAsyncCommand(noneInFlight.Where(_ => UpdateInfo != null)); DownloadReleases.RegisterAsyncObservable(_ => updateManager.DownloadReleases(UpdateInfo.ReleasesToApply)) .Subscribe(_ => DownloadedUpdateInfo = UpdateInfo); ApplyReleases = new ReactiveAsyncCommand(noneInFlight.Where(_ => DownloadedUpdateInfo != null)); ApplyReleases.RegisterAsyncObservable(_ => updateManager.ApplyReleases(DownloadedUpdateInfo)); Observable.CombineLatest( CheckForUpdate.ItemsInflight.StartWith(0), DownloadReleases.ItemsInflight.StartWith(0), ApplyReleases.ItemsInflight.StartWith(0), this.WhenAny(x => x.UpdatePath, _ => 0), (a, b, c, _) => a + b + c ).Select(x => x == 0 && UpdatePath != null).Multicast(noneInFlight).Connect(); }
public MainWindowViewModel() { DoIt = new ReactiveAsyncCommand(); DoIt.RegisterAsyncObservable(_ => Observable.Timer(TimeSpan.FromSeconds(5.0), RxApp.TaskpoolScheduler)) .Subscribe(_ => { Console.WriteLine("Boom"); }); }
public DownloadVM( IDiversityServiceClient Service, IConnectivityService Connectivity, IFieldDataService Storage, IKeyMappingService Mappings, EventHierarchyLoader HierarchyLoader, [Dispatcher] IScheduler Dispatcher ) { this.Service = Service; this.Connectivity = Connectivity; this.Storage = Storage; this.Mappings = Mappings; this.HierarchyLoader = HierarchyLoader; QueryResult = new ReactiveCollection<Event>(); _IsOnlineAvailable = Connectivity.Status().Select(s => s == ConnectionStatus.Wifi).Do(_ => { this.GetType(); }, ex => { }, () => { }) .ToProperty(this, x => x.IsOnlineAvailable); SearchEvents = new ReactiveAsyncCommand(this.WhenAny(x => x.IsOnlineAvailable, x => x.Value)); SearchEvents.ShowInFlightNotification(Notifications, DiversityResources.Download_SearchingEvents); SearchEvents.ThrownExceptions .ShowServiceErrorNotifications(Notifications) .ShowErrorNotifications(Notifications) .Subscribe(); SearchEvents .RegisterAsyncObservable(query => Service.GetEventsByLocality(query as string ?? string.Empty) .TakeUntil(this.OnDeactivation()) ) .Do(_ => QueryResult.Clear()) .Subscribe(QueryResult.AddRange); CancelDownload = new ReactiveCommand(); DownloadElement = new ReactiveAsyncCommand(this.WhenAny(x => x.IsOnlineAvailable, x => x.Value)); DownloadElement.ThrownExceptions .ShowServiceErrorNotifications(Notifications) .ShowErrorNotifications(Notifications) .Subscribe(); DownloadElement .RegisterAsyncObservable(ev => IfNotDownloadedYet(ev as Event) .Select(HierarchyLoader.downloadAndStoreDependencies) .SelectMany(dl => dl.TakeUntil(CancelDownload)) .Scan(0, (acc, _) => ++acc) .Do(_ElementsDownloadedSubject.OnNext) ); _IsDownloading = DownloadElement.ItemsInflight .Select(x => x > 0) .ToProperty(this, x => x.IsDownloading); this.OnDeactivation() .Subscribe(_ => Messenger.SendMessage(EventMessage.Default, MessageContracts.INIT)); _ElementsDownloadedSubject = new Subject<int>(); _ElementsDownloaded = _ElementsDownloadedSubject.ToProperty(this, x => x.ElementsDownloaded, 0, Dispatcher); }
public void CanExecuteShouldChangeOnInflightOp() { (new TestScheduler()).With(sched => { var canExecute = sched.CreateHotObservable( sched.OnNextAt(0, true), sched.OnNextAt(250, false), sched.OnNextAt(500, true), sched.OnNextAt(750, false), sched.OnNextAt(1000, true), sched.OnNextAt(1100, false) ); var fixture = new ReactiveAsyncCommand(canExecute); int calculatedResult = -1; bool latestCanExecute = false; fixture.RegisterAsyncObservable(x => Observable.Return((int)x * 5).Delay(TimeSpan.FromMilliseconds(900), RxApp.DeferredScheduler)) .Subscribe(x => calculatedResult = x); fixture.CanExecuteObservable.Subscribe(x => latestCanExecute = x); // CanExecute should be true, both input observable is true // and we don't have anything inflight sched.AdvanceToMs(10); Assert.True(fixture.CanExecute(1)); Assert.True(latestCanExecute); // Invoke a command 10ms in fixture.Execute(1); // At 300ms, input is false sched.AdvanceToMs(300); Assert.False(fixture.CanExecute(1)); Assert.False(latestCanExecute); // At 600ms, input is true, but the command is still running sched.AdvanceToMs(600); Assert.False(fixture.CanExecute(1)); Assert.False(latestCanExecute); // After we've completed, we should still be false, since from // 750ms-1000ms the input observable is false sched.AdvanceToMs(900); Assert.False(fixture.CanExecute(1)); Assert.False(latestCanExecute); Assert.Equal(-1, calculatedResult); sched.AdvanceToMs(1010); Assert.True(fixture.CanExecute(1)); Assert.True(latestCanExecute); Assert.Equal(calculatedResult, 5); sched.AdvanceToMs(1200); Assert.False(fixture.CanExecute(1)); Assert.False(latestCanExecute); }); }
public void CanExecuteShouldChangeOnInflightOp() { (new TestScheduler()).With(sched => { var canExecute = sched.CreateHotObservable( sched.OnNextAt(0, true), sched.OnNextAt(250, false), sched.OnNextAt(500, true), sched.OnNextAt(750, false), sched.OnNextAt(1000, true), sched.OnNextAt(1100, false) ); var fixture = new ReactiveAsyncCommand(canExecute); int calculatedResult = -1; bool latestCanExecute = false; fixture.RegisterAsyncObservable(x => Observable.Return((int)x * 5).Delay(TimeSpan.FromMilliseconds(900), RxApp.DeferredScheduler)) .Subscribe(x => calculatedResult = x); fixture.CanExecuteObservable.Subscribe(x => latestCanExecute = x); // CanExecute should be true, both input observable is true // and we don't have anything inflight sched.AdvanceToMs(10); Assert.True(fixture.CanExecute(1)); Assert.True(latestCanExecute); // Invoke a command 10ms in fixture.Execute(1); // At 300ms, input is false sched.AdvanceToMs(300); Assert.False(fixture.CanExecute(1)); Assert.False(latestCanExecute); // At 600ms, input is true, but the command is still running sched.AdvanceToMs(600); Assert.False(fixture.CanExecute(1)); Assert.False(latestCanExecute); // After we've completed, we should still be false, since from // 750ms-1000ms the input observable is false sched.AdvanceToMs(900); Assert.False(fixture.CanExecute(1)); Assert.False(latestCanExecute); Assert.Equal(-1, calculatedResult); sched.AdvanceToMs(1010); Assert.True(fixture.CanExecute(1)); Assert.True(latestCanExecute); Assert.Equal(calculatedResult, 5); sched.AdvanceToMs(1200); Assert.False(fixture.CanExecute(1)); Assert.False(latestCanExecute); }); }
public LoginViewModel(IScreen hostScreen, [Named("confirmUserPass")] [Optional] Func<IObservable<Unit>> confirmUserPassMock = null) { HostScreen = hostScreen; var canConfirm = this.WhenAny(x => x.User, x => x.Password, (u, p) => !String.IsNullOrWhiteSpace(u.Value) && !String.IsNullOrWhiteSpace(p.Value)); Confirm = new ReactiveAsyncCommand(canConfirm); var confirmFunc = confirmUserPassMock ?? TestUserNameAndPassword; var result = Confirm.RegisterAsyncObservable(_ => confirmFunc()); MessageBus.Current.RegisterMessageSource(result.Select(res => new Tuple<string, string>(User, Password)), "login"); Confirm.ThrownExceptions.Subscribe(x => UserError.Throw(new UserError("Couldn't Log In", x.Message, new[] {RecoveryCommand.Ok}, null, x))); }
public LoginViewModel(IScreen hostScreen, [Named("confirmUserPass")][Optional] Func <IObservable <Unit> > confirmUserPassMock = null) { HostScreen = hostScreen; var canConfirm = this.WhenAny(x => x.User, x => x.Password, (u, p) => !String.IsNullOrWhiteSpace(u.Value) && !String.IsNullOrWhiteSpace(p.Value)); Confirm = new ReactiveAsyncCommand(canConfirm); var confirmFunc = confirmUserPassMock ?? TestUserNameAndPassword; var result = Confirm.RegisterAsyncObservable(_ => confirmFunc()); MessageBus.Current.RegisterMessageSource(result.Select(res => new Tuple <string, string>(User, Password)), "login"); Confirm.ThrownExceptions.Subscribe(x => UserError.Throw(new UserError("Couldn't Log In", x.Message, new[] { RecoveryCommand.Ok }, null, x))); }
public TranslatorViewModel() { TranslateText = new ReactiveAsyncCommand(); this.ObservableForProperty(x => x.EnglishText) .Throttle(TimeSpan.FromMilliseconds(1200)) .Subscribe(x => TranslateText.Execute(x.Value)); var client = new LanguageServiceClient() as LanguageService; var translation_func = Observable.FromAsyncPattern <string, string>( client.BeginTranslateToGerman, client.EndTranslateToGerman); var results = TranslateText.RegisterAsyncObservable(x => translation_func((string)x)); _TranslatedText = this.ObservableToProperty(results, x => x.TranslatedText); }
public void MultipleResultsFromObservableShouldntDecrementRefcountBelowZero() { (new TestScheduler()).With(sched => { int latestInFlight = 0; var fixture = new ReactiveAsyncCommand(null, 1, sched); var results = fixture .RegisterAsyncObservable(_ => new[] { 1, 2, 3 }.ToObservable()) .CreateCollection(); fixture.ItemsInflight.Subscribe(x => latestInFlight = x); fixture.Execute(1); sched.Start(); Assert.Equal(3, results.Count); Assert.Equal(0, latestInFlight); }); }
public SearchViewModel(IScreen hostScreen, ILoginMethods loginMethods, [Named("UserAccount")] IBlobCache userCache) { HostScreen = hostScreen; SearchResults = new ReactiveCollection <ISongTileViewModel>(); var playApi = loginMethods.CurrentAuthenticatedClient; if (playApi == null) { hostScreen.Router.Navigate.Execute(RxApp.GetService <IWelcomeViewModel>()); return; } var canSearch = this.WhenAny(x => x.SearchQuery, x => !String.IsNullOrWhiteSpace(x.Value)); PerformSearch = new ReactiveAsyncCommand(canSearch); this.ObservableForProperty(x => x.SearchQuery) .Throttle(TimeSpan.FromMilliseconds(700), RxApp.DeferredScheduler) .InvokeCommand(PerformSearch); var searchResults = PerformSearch.RegisterAsyncObservable(_ => userCache.GetOrFetchObject( "search__" + SearchQuery, () => playApi.Search(SearchQuery), RxApp.TaskpoolScheduler.Now + TimeSpan.FromMinutes(1.0))); SearchResults = searchResults .Do(_ => SearchResults.Clear()) .SelectMany(list => list.ToObservable()) .LoggedCatch(this, Observable.Empty <Song>()) .CreateCollection(x => (ISongTileViewModel) new SongTileViewModel(x, playApi)); PerformSearch.ItemsInflight.StartWith(0) .Select(x => x > 0 ? Visibility.Visible : Visibility.Hidden) .ToProperty(this, x => x.SearchBusySpinner); PerformSearch.ThrownExceptions.Subscribe(_ => { }); GoBack = new ReactiveCommand(); GoBack.InvokeCommand(hostScreen.Router.NavigateBack); }
public SongTileViewModel(Song model, IPlayApi playApi) { Model = model; playApi.FetchImageForAlbum(model) .LoggedCatch(this, Observable.Return(default(BitmapImage))) .ToProperty(this, x => x.AlbumArt); QueueSong = new ReactiveAsyncCommand(); QueueAlbum = new ReactiveAsyncCommand(); QueueSong.RegisterAsyncObservable(_ => playApi.QueueSong(Model)) .Subscribe( x => this.Log().Info("Queued {0}", Model.name), ex => this.Log().WarnException("Failed to queue", ex)); QueueAlbum.RegisterAsyncObservable(_ => playApi.AllSongsOnAlbum(Model.artist, Model.album)) .SelectMany(x => x.ToObservable()) .Select(x => reallyTryToQueueSong(playApi, x)).Concat() .Subscribe( x => this.Log().Info("Queued song"), ex => this.Log().WarnException("Failed to queue album", ex)); QueueAlbum.ThrownExceptions.Subscribe(x => { }); IsStarred = model.starred; ToggleStarred = new ReactiveAsyncCommand(); ToggleStarred.RegisterAsyncObservable(_ => IsStarred ? playApi.Unstar(Model) : playApi.Star(Model)) .Select(_ => true).LoggedCatch(this, Observable.Return(false)) .Subscribe(result => { if (result) { IsStarred = !IsStarred; } }, ex => this.Log().WarnException("Couldn't star/unstar song", ex)); ToggleStarred.ThrownExceptions.Subscribe(x => { }); }
public DropRepoViewModel(IScreen hostScreen, IAppState appState, IRepoAnalysisProvider analyzeFunc) { HostScreen = hostScreen; AnalyzeRepo = new ReactiveAsyncCommand(); CoreUtility.ExtractLibGit2(); var scanResult = AnalyzeRepo.RegisterAsyncObservable(x => analyzeFunc.AnalyzeRepo((string)x)); scanResult.Select(x => x.Item1).ToProperty(this, x => x.CurrentRepoPath); scanResult .Select(x => x.Item2.Select(y => (IBranchInformationViewModel) new BranchInformationViewModel(y.Key, y.Value))) .Select(x => new ReactiveCollection <IBranchInformationViewModel>(x)) .ToProperty(this, x => x.BranchInformation); this.WhenAny(x => x.BranchInformation, x => x.Value != null ? Visibility.Visible : Visibility.Hidden) .ToProperty(this, x => x.RepairButtonVisibility); RepairButton = new ReactiveCommand(); RepairButton.Subscribe(_ => { appState.BranchInformation = BranchInformation.Where(x => x.BranchName != Constants.WorkingDirectory).ToArray(); appState.WorkingDirectoryInformation = BranchInformation.First(x => x.BranchName == Constants.WorkingDirectory).Model; appState.CurrentRepo = CurrentRepoPath; HostScreen.Router.Navigate.Execute(RxApp.GetService <IRepairViewModel>()); }); var viewStates = Observable.Merge( AnalyzeRepo.ItemsInflight.Where(x => x > 0).Select(_ => "Analyzing"), scanResult.Select(_ => "RepoAdded")); MessageBus.Current.RegisterMessageSource(viewStates, "DropRepoViewState"); this.WhenNavigatedTo(() => MessageBus.Current.Listen <string>("DropFolder").Subscribe(path => AnalyzeRepo.Execute(path))); }
public void RegisterAsyncFunctionSmokeTest() { (new TestScheduler()).With(sched => { var fixture = new ReactiveAsyncCommand(null, 1); ReactiveCollection <int> results; results = fixture.RegisterAsyncObservable(_ => Observable.Return(5).Delay(TimeSpan.FromSeconds(5), sched)).CreateCollection(); var inflightResults = fixture.ItemsInflight.CreateCollection(); sched.AdvanceToMs(10); Assert.True(fixture.CanExecute(null)); fixture.Execute(null); sched.AdvanceToMs(1005); Assert.False(fixture.CanExecute(null)); sched.AdvanceToMs(5100); Assert.True(fixture.CanExecute(null)); new[] { 0, 1, 0 }.AssertAreEqual(inflightResults); new[] { 5 }.AssertAreEqual(results); }); }
public void MultipleSubscribersShouldntDecrementRefcountBelowZero() { var sched = new TestScheduler(); var fixture = new ReactiveAsyncCommand(null, 1, sched); var results = new List<int>(); bool[] subscribers = new[] { false, false, false, false, false }; var output = fixture.RegisterAsyncObservable(_ => Observable.Return(5).Delay(TimeSpan.FromMilliseconds(5000), sched)); output.Subscribe(x => results.Add(x)); Enumerable.Range(0, 5).Run(x => output.Subscribe(_ => subscribers[x] = true)); Assert.IsTrue(fixture.CanExecute(null)); fixture.Execute(null); sched.RunToMilliseconds(2000); Assert.IsFalse(fixture.CanExecute(null)); sched.RunToMilliseconds(6000); Assert.IsTrue(fixture.CanExecute(null)); Assert.IsTrue(results.Count == 1); Assert.IsTrue(results[0] == 5); Assert.IsTrue(subscribers.All(x => x == true)); }
public SongTileViewModel(Song model, IPlayApi playApi) { Model = model; playApi.FetchImageForAlbum(model) .LoggedCatch(this, Observable.Return(default(BitmapImage))) .ToProperty(this, x => x.AlbumArt); QueueSong = new ReactiveAsyncCommand(); QueueAlbum = new ReactiveAsyncCommand(); QueueSong.RegisterAsyncObservable(_ => playApi.QueueSong(Model)) .Subscribe( x => this.Log().Info("Queued {0}", Model.name), ex => this.Log().WarnException("Failed to queue", ex)); QueueAlbum.RegisterAsyncObservable(_ => playApi.AllSongsOnAlbum(Model.artist, Model.album)) .SelectMany(x => x.ToObservable()) .Select(x => reallyTryToQueueSong(playApi, x)).Concat() .Subscribe( x => this.Log().Info("Queued song"), ex => this.Log().WarnException("Failed to queue album", ex)); QueueAlbum.ThrownExceptions.Subscribe(x => { }); IsStarred = model.starred; ToggleStarred = new ReactiveAsyncCommand(); ToggleStarred.RegisterAsyncObservable(_ => IsStarred ? playApi.Unstar(Model) : playApi.Star(Model)) .Select(_ => true).LoggedCatch(this, Observable.Return(false)) .Subscribe(result => { if (result) IsStarred = !IsStarred; }, ex => this.Log().WarnException("Couldn't star/unstar song", ex)); ToggleStarred.ThrownExceptions.Subscribe(x => { }); }
public DropRepoViewModel(IScreen hostScreen, IAppState appState, IRepoAnalysisProvider analyzeFunc) { HostScreen = hostScreen; AnalyzeRepo = new ReactiveAsyncCommand(); CoreUtility.ExtractLibGit2(); var scanResult = AnalyzeRepo.RegisterAsyncObservable(x => analyzeFunc.AnalyzeRepo((string) x)); scanResult.Select(x => x.Item1).ToProperty(this, x => x.CurrentRepoPath); scanResult .Select(x => x.Item2.Select(y => (IBranchInformationViewModel)new BranchInformationViewModel(y.Key, y.Value))) .Select(x => new ReactiveCollection<IBranchInformationViewModel>(x)) .ToProperty(this, x => x.BranchInformation); this.WhenAny(x => x.BranchInformation, x => x.Value != null ? Visibility.Visible : Visibility.Hidden) .ToProperty(this, x => x.RepairButtonVisibility); RepairButton = new ReactiveCommand(); RepairButton.Subscribe(_ => { appState.BranchInformation = BranchInformation.Where(x => x.BranchName != Constants.WorkingDirectory).ToArray(); appState.WorkingDirectoryInformation = BranchInformation.First(x => x.BranchName == Constants.WorkingDirectory).Model; appState.CurrentRepo = CurrentRepoPath; HostScreen.Router.Navigate.Execute(RxApp.GetService<IRepairViewModel>()); }); var viewStates = Observable.Merge( AnalyzeRepo.ItemsInflight.Where(x => x > 0).Select(_ => "Analyzing"), scanResult.Select(_ => "RepoAdded")); MessageBus.Current.RegisterMessageSource(viewStates, "DropRepoViewState"); this.WhenNavigatedTo(() => MessageBus.Current.Listen<string>("DropFolder").Subscribe(path => AnalyzeRepo.Execute(path))); }
public TranslatorViewModel() { TranslateText = new ReactiveAsyncCommand(); this.ObservableForProperty(x => x.EnglishText) .Throttle(TimeSpan.FromMilliseconds(1200)) .Subscribe(x => TranslateText.Execute(x.Value)); var client = new LanguageServiceClient() as LanguageService; var translation_func = Observable.FromAsyncPattern<string, string>( client.BeginTranslateToGerman, client.EndTranslateToGerman); var results = TranslateText.RegisterAsyncObservable(x => translation_func((string)x)); _TranslatedText = this.ObservableToProperty(results, x => x.TranslatedText); }
public void SpinnerShouldSpinWhileAppIsSearching() { (new TestScheduler()).With(sched => { // Here, we're going to create a dummy Observable that mocks // a web service call - mocking things that happen over time is // often tricky, but not with Rx! var searchObservable = Observable.Return(createSampleResults()) .Delay(TimeSpan.FromMilliseconds(5000), RxApp.TaskpoolScheduler); var command = new ReactiveAsyncCommand(); command.RegisterAsyncObservable(x => searchObservable); var fixture = new AppViewModel(command, searchObservable); // The spinner should be hidden on startup Assert.AreNotEqual(Visibility.Visible, fixture.SpinnerVisibility); // Invoke the command fixture.ExecuteSearch.Execute("Robot"); // Once we run the command, we should be showing the spinner sched.RunToMilliseconds(100); Assert.AreEqual(Visibility.Visible, fixture.SpinnerVisibility); // Fast forward to 6sec, the spinner should now be gone sched.RunToMilliseconds(6 * 1000); Assert.AreNotEqual(Visibility.Visible, fixture.SpinnerVisibility); }); }
public void MultipleResultsFromObservableShouldntDecrementRefcountBelowZero() { (new TestScheduler()).With(sched => { int latestInFlight = 0; var fixture = new ReactiveAsyncCommand(null, 1, sched); var results = fixture .RegisterAsyncObservable(_ => new[] {1, 2, 3}.ToObservable()) .CreateCollection(); fixture.ItemsInflight.Subscribe(x => latestInFlight = x); fixture.Execute(1); sched.Start(); Assert.Equal(3, results.Count); Assert.Equal(0, latestInFlight); }); }
public void RAOShouldActuallyRunOnTheTaskpool() { var deferred = RxApp.DeferredScheduler; var taskpool = RxApp.TaskpoolScheduler; try { var testDeferred = new CountingTestScheduler(Scheduler.Immediate); var testTaskpool = new CountingTestScheduler(Scheduler.NewThread); RxApp.DeferredScheduler = testDeferred; RxApp.TaskpoolScheduler = testTaskpool; var fixture = new ReactiveAsyncCommand(); var result = fixture.RegisterAsyncObservable(x => Observable.Return((int)x * 5).Delay(TimeSpan.FromSeconds(1), RxApp.TaskpoolScheduler)); fixture.Execute(1); Assert.Equal(5, result.First()); Assert.True(testDeferred.ScheduledItems.Count >= 1); Assert.True(testTaskpool.ScheduledItems.Count >= 1); } finally { RxApp.DeferredScheduler = deferred; RxApp.TaskpoolScheduler = taskpool; } }
public void RegisterAsyncFunctionSmokeTest() { (new TestScheduler()).With(sched => { var fixture = new ReactiveAsyncCommand(null, 1); ReactiveCollection<int> results; results = fixture.RegisterAsyncObservable(_ => Observable.Return(5).Delay(TimeSpan.FromSeconds(5), sched)).CreateCollection(); var inflightResults = fixture.ItemsInflight.CreateCollection(); sched.AdvanceToMs(10); Assert.True(fixture.CanExecute(null)); fixture.Execute(null); sched.AdvanceToMs(1005); Assert.False(fixture.CanExecute(null)); sched.AdvanceToMs(5100); Assert.True(fixture.CanExecute(null)); new[] {0,1,0}.AssertAreEqual(inflightResults); new[] {5}.AssertAreEqual(results); }); }
public CommitHintViewModel(string filePath, IVisualStudioOps vsOps, UserSettings settings = null, IGitRepoOps gitRepoOps = null, IFilesystemWatchCache watchCache = null) { FilePath = filePath; watchCache = watchCache ?? _defaultWatchCache; _gitRepoOps = gitRepoOps ?? new GitRepoOps(); UserSettings = settings ?? new UserSettings(); this.Log().Info("Starting Commit Hint for {0}", filePath); this.WhenAny(x => x.FilePath, x => x.Value) .Where(x => !String.IsNullOrWhiteSpace(x)) .Select(_gitRepoOps.FindGitRepo) .ToProperty(this, x => x.RepoPath, out _RepoPath); this.WhenAny(x => x.RepoPath, x => x.Value) .Where(x => !String.IsNullOrWhiteSpace(x)) .Select(_gitRepoOps.ProtocolUrlForRepoPath) .ToProperty(this, x => x.ProtocolUrl, out _ProtocolUrl); Open = new ReactiveCommand(this.WhenAny(x => x.ProtocolUrl, x => !String.IsNullOrWhiteSpace(x.Value))); GoAway = new ReactiveCommand(); RefreshStatus = new ReactiveAsyncCommand(this.WhenAny(x => x.RepoPath, x => !String.IsNullOrWhiteSpace(x.Value))); RefreshLastCommitTime = new ReactiveAsyncCommand(this.WhenAny(x => x.RepoPath, x => !String.IsNullOrWhiteSpace(x.Value))); var repoWatchSub = this.WhenAny(x => x.RepoPath, x => x.Value) .Where(x => !String.IsNullOrWhiteSpace(x)) .Select(x => watchCache.Register(Path.Combine(x, ".git", "refs")).Select(_ => x)) .Switch() .InvokeCommand(RefreshLastCommitTime); RefreshLastCommitTime.RegisterAsyncObservable(_ => _gitRepoOps.LastCommitTime(RepoPath)) .StartWith(_gitRepoOps.ApplicationStartTime) .ToProperty(this, x => x.LastRepoCommitTime, out _LastRepoCommitTime); MessageBus.Current.Listen<Unit>("AnyDocumentChanged") .Timestamp(RxApp.MainThreadScheduler) .Select(x => x.Timestamp) .StartWith(_gitRepoOps.ApplicationStartTime) .ToProperty(this, x => x.LastTextActiveTime, out _LastTextActiveTime); var refreshDisp = this.WhenAny(x => x.LastTextActiveTime, x => Unit.Default) .Buffer(TimeSpan.FromSeconds(5), RxApp.TaskpoolScheduler) .ObserveOn(RxApp.MainThreadScheduler) .InvokeCommand(RefreshStatus); this.WhenAny(x => x.LastRepoCommitTime, x => x.LastTextActiveTime, x => x.MinutesTimeOverride, (commit, active, _) => active.Value - commit.Value) .Select(x => x.Ticks < 0 ? TimeSpan.Zero : x) .Select(x => MinutesTimeOverride != null ? TimeSpan.FromMinutes(MinutesTimeOverride.Value) : x) .Select(x => LastCommitTimeToOpacity(x)) .ToProperty(this, x => x.SuggestedOpacity, out _SuggestedOpacity, 1.0); var hintState = new Subject<CommitHintState>(); hintState.ToProperty(this, x => x.HintState, out _HintState); Open.Subscribe(_ => vsOps.SaveAll()); RefreshStatus.RegisterAsyncObservable(_ => _gitRepoOps.GetStatus(RepoPath)) .ToProperty(this, x => x.LatestRepoStatus, out _LatestRepoStatus); this.WhenAny(x => x.SuggestedOpacity, x => x.LatestRepoStatus, (opacity, status) => new { Opacity = opacity.Value, Status = status.Value }) .Select(x => { if (x.Status == null) return CommitHintState.Green; if (!x.Status.Added.Any() && !x.Status.Removed.Any() && !x.Status.Modified.Any() && !x.Status.Missing.Any()) return CommitHintState.Green; if (x.Opacity >= 0.95) return CommitHintState.Red; if (x.Opacity >= 0.6) return CommitHintState.Yellow; return CommitHintState.Green; }) .Subscribe(hintState); // NB: Because _LastRepoCommitTime at the end of the day creates a // FileSystemWatcher, we have to dispose it or else we'll get FSW // messages for evar. _inner = new CompositeDisposable(repoWatchSub, _LastRepoCommitTime, _LastTextActiveTime); }