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);
            });
        }
Beispiel #2
0
        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);
                }
            });
        }
Beispiel #5
0
        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);
        }
Beispiel #7
0
        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();
        }
Beispiel #9
0
        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);
        }
Beispiel #13
0
        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)));
        }
Beispiel #16
0
        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)));
        }
Beispiel #17
0
        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);
        }
Beispiel #18
0
        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);
            });
        }
Beispiel #19
0
        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)));
        }
Beispiel #22
0
        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));
        }
Beispiel #24
0
        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);
        }
Beispiel #27
0
        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);
        }