public void parse_returns_an_appropriate_exercise_programs_instance(string input, string[] expectedProgramNames)
        {
            var result = ExercisePrograms.Parse(
                input,
                new AudioServiceMock(MockBehavior.Loose),
                new DelayServiceMock(MockBehavior.Loose),
                new SpeechServiceMock(MockBehavior.Loose));

            Assert.NotNull(result);
            Assert.True(result.Programs.Select(x => x.Name).SequenceEqual(expectedProgramNames));
        }
        public ExerciseProgramsViewModel(
            IAudioService audioService,
            IDelayService delayService,
            IExerciseDocumentService exerciseDocumentService,
            ILoggerService loggerService,
            ISchedulerService schedulerService,
            ISpeechService speechService,
            IStateService stateService,
            IScreen hostScreen,
            ExerciseProgramViewModelFactory exerciseProgramViewModelFactory)
        {
            audioService.AssertNotNull(nameof(audioService));
            delayService.AssertNotNull(nameof(delayService));
            exerciseDocumentService.AssertNotNull(nameof(exerciseDocumentService));
            loggerService.AssertNotNull(nameof(loggerService));
            schedulerService.AssertNotNull(nameof(schedulerService));
            speechService.AssertNotNull(nameof(speechService));
            stateService.AssertNotNull(nameof(stateService));
            hostScreen.AssertNotNull(nameof(hostScreen));
            exerciseProgramViewModelFactory.AssertNotNull(nameof(exerciseProgramViewModelFactory));

            this.exerciseDocumentService = exerciseDocumentService;
            this.stateService            = stateService;
            this.logger      = loggerService.GetLogger(this.GetType());
            this.hostScreen  = hostScreen;
            this.disposables = new CompositeDisposable();

            var documentsFromCache = this
                                     .stateService
                                     .GetAsync <string>(exerciseProgramsCacheKey)
                                     .Where(x => x != null)
                                     .Select(x => new DocumentSourceWith <string>(DocumentSource.Cache, x));

            var documentsFromService = this
                                       .exerciseDocumentService
                                       .ExerciseDocument
                                       .Where(x => x != null)
                                       .Select(x => new DocumentSourceWith <string>(DocumentSource.Service, x));

            var documents = documentsFromCache
                            .Catch((Exception ex) => Observable.Empty <DocumentSourceWith <string> >())
                            .Concat(documentsFromService)
                            .Do(x => this.logger.Debug("Received document from {0}.", x.Source))
                            .Publish();

            var safeDocuments = documents
                                .Catch((Exception ex) => Observable.Empty <DocumentSourceWith <string> >());

            var results = documents
                          .ObserveOn(schedulerService.TaskPoolScheduler)
                          .Select(
                x =>
            {
                IResult <ExercisePrograms> parsedExercisePrograms;

                using (this.logger.Perf("Parsing exercise programs from {0}.", x.Source))
                {
                    parsedExercisePrograms = ExercisePrograms.TryParse(x.Item, audioService, delayService, loggerService, speechService);
                }

                return(new DocumentSourceWith <IResult <ExercisePrograms> >(x.Source, parsedExercisePrograms));
            })
                          .Publish();

            var safeResults = results
                              .Catch((Exception ex) => Observable.Empty <DocumentSourceWith <IResult <ExercisePrograms> > >());

            safeResults
            .Select(x => x.Item.WasSuccessful ? null : x.Item.ToString())
            .ObserveOn(schedulerService.MainScheduler)
            .Subscribe(x => this.ParseErrorMessage = x)
            .AddTo(this.disposables);

            results
            .Select(x => !x.Item.WasSuccessful ? ExerciseProgramsViewModelStatus.ParseFailed : x.Source == DocumentSource.Cache ? ExerciseProgramsViewModelStatus.LoadedFromCache : ExerciseProgramsViewModelStatus.LoadedFromService)
            .Catch((Exception ex) => Observable.Return(ExerciseProgramsViewModelStatus.LoadFailed))
            .ObserveOn(schedulerService.MainScheduler)
            .Subscribe(x => this.Status = x)
            .AddTo(this.disposables);

            safeResults
            .Select(x => x.Item.WasSuccessful ? x.Item.Value : null)
            .ObserveOn(schedulerService.MainScheduler)
            .Subscribe(x => this.Model = x)
            .AddTo(this.disposables);

            this.WhenAnyValue(x => x.Model)
            .Select(x => x == null ? null : x.Programs.CreateDerivedCollection(y => exerciseProgramViewModelFactory(y)))
            .ObserveOn(schedulerService.MainScheduler)
            .Subscribe(x => this.Programs = x)
            .AddTo(this.disposables);

            safeDocuments
            .Where(x => x.Source == DocumentSource.Service)
            .SelectMany(x => this.stateService.SetAsync(exerciseProgramsCacheKey, x.Item))
            .Subscribe()
            .AddTo(this.disposables);

            results
            .Connect()
            .AddTo(this.disposables);

            documents
            .Connect()
            .AddTo(this.disposables);

            this
            .WhenAnyValue(x => x.SelectedProgram)
            .Where(x => x != null)
            .Subscribe(x => this.hostScreen.Router.Navigate.Execute(x))
            .AddTo(this.disposables);

            this
            .hostScreen
            .Router
            .CurrentViewModel
            .OfType <ExerciseProgramsViewModel>()
            .Subscribe(x => x.SelectedProgram = null)
            .AddTo(this.disposables);
        }
Beispiel #3
0
 public void parse_throws_if_speech_service_is_null()
 {
     Assert.Throws <ArgumentNullException>(() => ExercisePrograms.Parse("input", new AudioServiceMock(), new DelayServiceMock(), new LoggerServiceMock(), null));
 }
Beispiel #4
0
 public void try_parse_throws_if_input_is_null()
 {
     Assert.Throws <ArgumentNullException>(() => ExercisePrograms.TryParse(null, new AudioServiceMock(), new DelayServiceMock(), new LoggerServiceMock(), new SpeechServiceMock()));
 }
Beispiel #5
0
        public ExerciseProgramsViewModel(
            IAudioService audioService,
            IDelayService delayService,
            IExerciseDocumentService exerciseDocumentService,
            IScheduler mainScheduler,
            IScheduler backgroundScheduler,
            ISpeechService speechService,
            IStateService stateService,
            IScreen hostScreen,
            ExerciseProgramViewModelFactory exerciseProgramViewModelFactory)
        {
            Ensure.ArgumentNotNull(audioService, nameof(audioService));
            Ensure.ArgumentNotNull(delayService, nameof(delayService));
            Ensure.ArgumentNotNull(exerciseDocumentService, nameof(exerciseDocumentService));
            Ensure.ArgumentNotNull(mainScheduler, nameof(mainScheduler));
            Ensure.ArgumentNotNull(backgroundScheduler, nameof(backgroundScheduler));
            Ensure.ArgumentNotNull(speechService, nameof(speechService));
            Ensure.ArgumentNotNull(stateService, nameof(stateService));
            Ensure.ArgumentNotNull(hostScreen, nameof(hostScreen));
            Ensure.ArgumentNotNull(exerciseProgramViewModelFactory, nameof(exerciseProgramViewModelFactory));

            this.logger = LoggerService.GetLogger(this.GetType());

            using (this.logger.Perf("Construction"))
            {
                this.activator = new ViewModelActivator();
                this.exerciseDocumentService = exerciseDocumentService;
                this.stateService            = stateService;
                this.hostScreen = hostScreen;

                this
                .WhenAnyValue(x => x.SelectedProgram)
                .Where(x => x != null)
                .SelectMany(x => this.hostScreen.Router.Navigate.Execute(x))
                .SubscribeSafe();

                var isActivated = this
                                  .GetIsActivated()
                                  .Publish()
                                  .RefCount();

                var documentsFromCache = this
                                         .stateService
                                         .Get <string>(exerciseProgramsCacheKey)
                                         .Where(x => x != null)
                                         .Select(x => new DocumentSourceWith <string>(DocumentSource.Cache, x));

                var documentsFromService = this
                                           .exerciseDocumentService
                                           .ExerciseDocument
                                           .Where(x => x != null)
                                           .Select(x => new DocumentSourceWith <string>(DocumentSource.Service, x));

                var documents = isActivated
                                .Select(
                    activated =>
                {
                    if (activated)
                    {
                        return(documentsFromCache
                               .Catch((Exception ex) => Observable <DocumentSourceWith <string> > .Empty)
                               .Concat(documentsFromService)
                               .Do(x => this.logger.Debug("Received document from {0}.", x.Source)));
                    }
                    else
                    {
                        return(Observable <DocumentSourceWith <string> > .Empty);
                    }
                })
                                .Switch()
                                .Publish();

                var results = documents
                              .ObserveOn(backgroundScheduler)
                              .Select(
                    x =>
                {
                    IResult <ExercisePrograms> parsedExercisePrograms;

                    using (this.logger.Perf("Parsing exercise programs from {0}.", x.Source))
                    {
                        parsedExercisePrograms = ExercisePrograms.TryParse(x.Item, audioService, delayService, speechService);
                    }

                    return(new DocumentSourceWith <IResult <ExercisePrograms> >(x.Source, parsedExercisePrograms));
                })
                              .Publish();

                var safeResults = results
                                  .Catch((Exception ex) => Observable <DocumentSourceWith <IResult <ExercisePrograms> > > .Empty);

                this.parseErrorMessage = safeResults
                                         .Select(x => x.Item.WasSuccessful ? null : x.Item.ToString())
                                         .ToProperty(this, x => x.ParseErrorMessage, scheduler: mainScheduler);

                this.status = results
                              .Select(x => !x.Item.WasSuccessful ? ExerciseProgramsViewModelStatus.ParseFailed : x.Source == DocumentSource.Cache ? ExerciseProgramsViewModelStatus.LoadedFromCache : ExerciseProgramsViewModelStatus.LoadedFromService)
                              .Catch((Exception ex) => Observable.Return(ExerciseProgramsViewModelStatus.LoadFailed))
                              .ObserveOn(mainScheduler)
                              .ToProperty(this, x => x.Status);

                this.model = safeResults
                             .Select(x => x.Item.WasSuccessful ? x.Item.Value : null)
                             .ToProperty(this, x => x.Model, scheduler: mainScheduler);

                this.programs = this
                                .WhenAnyValue(x => x.Model)
                                .Select(x => x == null ? null : x.Programs.Select(program => exerciseProgramViewModelFactory(program)).ToImmutableList())
                                .ObserveOn(mainScheduler)
                                .ToProperty(this, x => x.Programs);

                var safeDocuments = documents
                                    .Catch((Exception ex) => Observable <DocumentSourceWith <string> > .Empty);

                safeDocuments
                .Where(x => x.Source == DocumentSource.Service)
                .SelectMany(x => this.stateService.Set(exerciseProgramsCacheKey, x.Item))
                .SubscribeSafe();

                results
                .Connect();

                documents
                .Connect();

                this
                .WhenActivated(
                    disposables =>
                {
                    using (this.logger.Perf("Activation"))
                    {
                        this
                        .hostScreen
                        .Router
                        .CurrentViewModel
                        .OfType <ExerciseProgramsViewModel>()
                        .SubscribeSafe(x => x.SelectedProgram = null)
                        .AddTo(disposables);
                    }
                });
            }
        }