Example #1
0
 /// <summary>
 /// A utility method that will pipe an Observable to an ICommand (i.e.
 /// it will first call its CanExecute with the provided value, then if
 /// the command can be executed, Execute() will be called)
 /// </summary>
 /// <param name="command">The command to be executed.</param>
 /// <returns>An object that when disposes, disconnects the Observable
 /// from the command.</returns>
 public static IDisposable InvokeCommand <T, TResult>(this IObservable <T> This, IReactiveCommand <TResult> command)
 {
     return(This.Throttle(x => command.CanExecuteObservable.StartWith(command.CanExecute(x)).Where(b => b))
            .Select(x => command.ExecuteAsync(x).Catch(Observable.Empty <TResult>()))
            .Switch()
            .Subscribe());
 }
Example #2
0
        private static async Task assertExceptionForwardedToThrownExceptions(IReactiveCommand <Unit> command, Exception exception)
        {
            var exceptions = command.ThrownExceptions.CreateCollection();

            await command.ExecuteAsync()
            .Catch(Observable.Empty <Unit>())
            .DefaultIfEmpty(Unit.Default);

            Assert.Equal(1, exceptions.Count);
            Assert.Contains(exception, exceptions);
        }
Example #3
0
        private static async Task assertThrowsOnExecuteAsync(IReactiveCommand <Unit> command, Exception exception)
        {
            command.ThrownExceptions.Subscribe();

            var failed = false;

            try {
                await command.ExecuteAsync();
            }
            catch (Exception ex) {
                failed = ex == exception;
            }

            Assert.True(failed);
        }
Example #4
0
        private static async Task AssertThrowsOnExecuteAsync(IReactiveCommand<Unit> command, Exception exception)
        {
            command.ThrownExceptions.Subscribe();

            var failed = false;

            try
            {
                await command.ExecuteAsync();
            }
            catch (Exception ex)
            {
                failed = ex == exception;
            }

            Assert.True(failed);
        }
Example #5
0
        private static IEnumerable <UIButton> CreateButtons(UITextView controller, IReactiveCommand <string> postImage)
        {
            var pictureImage = UIImageHelper.FromFileAuto("Images/MarkdownComposer/picture");
            var linkImage    = UIImageHelper.FromFileAuto("Images/MarkdownComposer/link");
            var photoImage   = UIImageHelper.FromFileAuto("Images/MarkdownComposer/photo");

            return(new []
            {
                CreateAccessoryButton("@", () => controller.InsertText("@")),
                CreateAccessoryButton("#", () => controller.InsertText("#")),
                CreateAccessoryButton("*", () => controller.InsertText("*")),
                CreateAccessoryButton("`", () => controller.InsertText("`")),
                CreateAccessoryButton(pictureImage, () => {
                    var range = controller.SelectedRange;
                    controller.InsertText("![]()");
                    controller.SelectedRange = new Foundation.NSRange(range.Location + 4, 0);
                }),

                CreateAccessoryButton(photoImage, () =>
                                      postImage.ExecuteAsync().Catch(Observable.Empty <string>())
                                      .ObserveOn(RxApp.MainThreadScheduler)
                                      .Subscribe(x => controller.InsertText("![Image](" + x + ")"))),

                CreateAccessoryButton(linkImage, () => {
                    var range = controller.SelectedRange;
                    controller.InsertText("[]()");
                    controller.SelectedRange = new Foundation.NSRange(range.Location + 1, 0);
                }),
                CreateAccessoryButton("~", () => controller.InsertText("~")),
                CreateAccessoryButton("=", () => controller.InsertText("=")),
                CreateAccessoryButton("-", () => controller.InsertText("-")),
                CreateAccessoryButton("+", () => controller.InsertText("+")),
                CreateAccessoryButton("_", () => controller.InsertText("_")),
                CreateAccessoryButton("[", () => controller.InsertText("[")),
                CreateAccessoryButton("]", () => controller.InsertText("]")),
                CreateAccessoryButton("<", () => controller.InsertText("<")),
                CreateAccessoryButton(">", () => controller.InsertText(">")),
            });
        }
        /// <summary>
        /// Setup the lookup logic, and use the interface to do the web call.
        /// </summary>
        /// <param name="caller"></param>
        public WebCallViewModel(IWebCaller caller)
        {
            // Do a search when nothing new has been entered for 800 ms and it isn't
            // an empty string... and don't search for the same thing twice.

            var newSearchNeeded = this.WhenAny(p => p.InputText, x => x.Value)
                                  .Throttle(TimeSpan.FromMilliseconds(800), RxApp.TaskpoolScheduler)
                                  .DistinctUntilChanged()
                                  .Where(x => !string.IsNullOrWhiteSpace(x));

            _doWebCall = ReactiveCommand.CreateAsyncObservable(x => caller.GetResult(x as string));

            newSearchNeeded.InvokeCommand(_doWebCall);

            // Run the web call and save the results back to the UI when done.
            var webResults =
                _doWebCall.ExecuteAsync();

            // The results are stuffed into the property, on the proper thread
            // (ToProperty takes care of that) when done. We never want the property to
            // be null, so we give it an initial value of "".
            webResults
            .ToProperty(this, x => x.ResultText, out _ResultTextOAPH, "");
        }
        /// <summary>
        /// Setup the lookup logic, and use the interface to do the web call.
        /// </summary>
        /// <param name="caller"></param>
        public WebCallViewModel(IWebCaller caller)
        {
            // Do a search when nothing new has been entered for 800 ms and it isn't
            // an empty string... and don't search for the same thing twice.

            var newSearchNeeded = this.WhenAny(p => p.InputText, x => x.Value)
                .Throttle(TimeSpan.FromMilliseconds(800), RxApp.TaskpoolScheduler)
                .DistinctUntilChanged()
                .Where(x => !string.IsNullOrWhiteSpace(x));

            _doWebCall = ReactiveCommand.CreateAsyncObservable(x => caller.GetResult(x as string));

            newSearchNeeded.InvokeCommand(_doWebCall);

            // Run the web call and save the results back to the UI when done.
            var webResults =
                _doWebCall.ExecuteAsync();

            // The results are stuffed into the property, on the proper thread
            // (ToProperty takes care of that) when done. We never want the property to
            // be null, so we give it an initial value of "".
            webResults
                .ToProperty(this, x => x.ResultText, out _ResultTextOAPH, "");
        }
Example #8
0
        public ShellViewModel(Library library, ViewSettings viewSettings, CoreSettings coreSettings, IWindowManager windowManager, MobileApiInfo mobileApiInfo)
        {
            this.library      = library;
            this.ViewSettings = viewSettings;
            this.coreSettings = coreSettings;

            this.disposable      = new CompositeDisposable();
            this.UpdateViewModel = new UpdateViewModel(viewSettings);

            this.library.Initialize();
            this.accessToken = this.library.LocalAccessControl.RegisterLocalAccessToken();

            this.library.WhenAnyValue(x => x.CurrentPlaylist).Subscribe(x => this.RaisePropertyChanged("CurrentPlaylist"));

            this.canChangeTime = this.library.LocalAccessControl.HasAccess(this.coreSettings.WhenAnyValue(x => x.LockTime), this.accessToken)
                                 .ToProperty(this, x => x.CanChangeTime);
            this.canChangeVolume = this.library.LocalAccessControl.HasAccess(this.coreSettings.WhenAnyValue(x => x.LockVolume), this.accessToken)
                                   .ToProperty(this, x => x.CanChangeVolume);
            this.canAlterPlaylist = this.library.LocalAccessControl.HasAccess(this.coreSettings.WhenAnyValue(x => x.LockPlaylist), this.accessToken)
                                    .ToProperty(this, x => x.CanAlterPlaylist);

            this.showVotes = this.library.RemoteAccessControl.WhenAnyValue(x => x.IsGuestSystemReallyEnabled)
                             .CombineLatest(mobileApiInfo.ConnectedClientCount, (enableGuestSystem, connectedClients) => enableGuestSystem && connectedClients > 0)
                             .ToProperty(this, x => x.ShowVotes);

            mobileApiInfo.VideoPlayerToggleRequest.Subscribe(_ => this.ShowVideoPlayer = !this.ShowVideoPlayer);

            this.isAdmin = this.library.LocalAccessControl.ObserveAccessPermission(this.accessToken)
                           .Select(x => x == AccessPermission.Admin)
                           .ToProperty(this, x => x.IsAdmin);

            this.NextSongCommand = ReactiveCommand.CreateAsyncTask(this.library.LocalAccessControl.HasAccess(this.coreSettings.WhenAnyValue(x => x.LockPlayPause), this.accessToken)
                                                                   .CombineLatest(this.library.WhenAnyValue(x => x.CurrentPlaylist.CanPlayNextSong), (x1, x2) => x1 && x2)
                                                                   .ObserveOn(RxApp.MainThreadScheduler),
                                                                   _ => this.library.PlayNextSongAsync(this.accessToken));

            this.PreviousSongCommand = ReactiveCommand.CreateAsyncTask(this.library.LocalAccessControl.HasAccess(this.coreSettings.WhenAnyValue(x => x.LockPlayPause), this.accessToken)
                                                                       .CombineLatest(this.library.WhenAnyValue(x => x.CurrentPlaylist.CanPlayPreviousSong), (x1, x2) => x1 && x2)
                                                                       .ObserveOn(RxApp.MainThreadScheduler),
                                                                       _ => this.library.PlayPreviousSongAsync(this.accessToken));

            if (!this.library.Playlists.Any())
            {
                this.library.AddAndSwitchToPlaylist(this.GetNewPlaylistName(), this.accessToken);
            }

            else
            {
                this.library.SwitchToPlaylist(this.library.Playlists.First(), this.accessToken);
            }

            this.SettingsViewModel = new SettingsViewModel(this.library, this.ViewSettings, this.coreSettings, windowManager, this.accessToken, mobileApiInfo);

            this.LocalViewModel         = new LocalViewModel(this.library, this.ViewSettings, this.coreSettings, accessToken);
            this.YoutubeViewModel       = new YoutubeViewModel(this.library, this.ViewSettings, this.coreSettings, accessToken);
            this.SoundCloudViewModel    = new SoundCloudViewModel(this.library, accessToken, this.coreSettings, this.ViewSettings);
            this.DirectYoutubeViewModel = new DirectYoutubeViewModel(this.library, this.coreSettings, accessToken);

            this.currentSongSource = this.WhenAnyValue(x => x.IsLocal, x => x.IsYoutube, x => x.IsSoundCloud,
                                                       (local, youtube, soundcloud) =>
            {
                if (local)
                {
                    return((ISongSourceViewModel)this.LocalViewModel);
                }

                if (youtube)
                {
                    return(this.YoutubeViewModel);
                }

                if (soundcloud)
                {
                    return(this.SoundCloudViewModel);
                }

                return(this.LocalViewModel);
            })
                                     .ToProperty(this, x => x.CurrentSongSource, null, ImmediateScheduler.Instance);

            this.MuteCommand = ReactiveCommand.Create(this.WhenAnyValue(x => x.IsAdmin));
            this.MuteCommand.Subscribe(x => this.Volume = 0);

            this.UnMuteCommand = ReactiveCommand.Create(this.WhenAnyValue(x => x.IsAdmin));
            this.UnMuteCommand.Subscribe(x => this.Volume = 1);

            this.canModifyWindow = this.library.LocalAccessControl.HasAccess(this.ViewSettings.WhenAnyValue(x => x.LockWindow), this.accessToken)
                                   .ToProperty(this, x => x.CanModifyWindow);

            this.isPlaying = this.library.PlaybackState
                             .Select(x => x == AudioPlayerState.Playing)
                             .ObserveOn(RxApp.MainThreadScheduler)
                             .ToProperty(this, x => x.IsPlaying);

            this.currentTime = this.library.CurrentPlaybackTime
                               .StartWith(TimeSpan.Zero)
                               .Select(x => x.FormatAdaptive())
                               .ToProperty(this, x => x.CurrentTime);

            this.currentSeconds = this.library.CurrentPlaybackTime
                                  .Select(x => (int)x.TotalSeconds)
                                  .ToProperty(this, x => x.CurrentSeconds);

            this.totalTime = this.library.TotalTime
                             .Select(x => x.FormatAdaptive())
                             .ToProperty(this, x => x.TotalTime);

            this.totalSeconds = this.library.TotalTime
                                .Select(x => (int)x.TotalSeconds)
                                .ToProperty(this, x => x.TotalSeconds);

            this.volume = this.library.WhenAnyValue(x => x.Volume, x => (double)x)
                          .ToProperty(this, x => x.Volume);

            this.AddPlaylistCommand = ReactiveCommand.Create(this.WhenAnyValue(x => x.CanAlterPlaylist));
            this.AddPlaylistCommand.Subscribe(x => this.AddPlaylist());

            this.Playlists = this.library.Playlists.CreateDerivedCollection(this.CreatePlaylistViewModel, x => x.Dispose());

            this.ShowSettingsCommand = ReactiveCommand.Create();
            this.ShowSettingsCommand.Subscribe(x => this.SettingsViewModel.HandleSettings());

            this.ShufflePlaylistCommand = ReactiveCommand.Create(this.WhenAnyValue(x => x.CanAlterPlaylist));
            this.ShufflePlaylistCommand.Subscribe(x => this.library.ShufflePlaylist(this.accessToken));

            IObservable <bool> canPlay = this.WhenAnyValue(x => x.CurrentPlaylist.SelectedEntries)
                                         .CombineLatest(this.library.LocalAccessControl.HasAccess(this.coreSettings.WhenAnyValue(x => x.LockPlayPause), this.accessToken), this.library.LoadedSong, this.library.PlaybackState,
                                                        (selectedPlaylistEntries, hasPlayAccess, loadedSong, playBackState) =>

                                                        // The admin can always play, but if we are in party mode, we have to check
                                                        // whether it is allowed to play
                                                        hasPlayAccess &&

                                                        // If exactly one song is selected, the command can be executed
                                                        (selectedPlaylistEntries != null && selectedPlaylistEntries.Count() == 1 ||

                                                         // If the current song is paused, the command can be executed
                                                         (loadedSong != null || playBackState == AudioPlayerState.Paused)));

            this.PlayCommand = ReactiveCommand.CreateAsyncTask(canPlay, async _ =>
            {
                if (await this.library.PlaybackState.FirstAsync() == AudioPlayerState.Paused || await this.library.LoadedSong.FirstAsync() != null)
                {
                    await this.library.ContinueSongAsync(this.accessToken);
                }

                else
                {
                    await this.library.PlaySongAsync(this.CurrentPlaylist.SelectedEntries.First().Index, this.accessToken);
                }
            });

            this.PlayOverrideCommand = ReactiveCommand.CreateAsyncTask(this.WhenAnyValue(x => x.CurrentPlaylist.SelectedEntries)
                                                                       .CombineLatest(this.library.LocalAccessControl.HasAccess(this.coreSettings.WhenAnyValue(x => x.LockPlayPause), this.accessToken),
                                                                                      (selectedPlaylistEntries, hasAccess) => hasAccess && (selectedPlaylistEntries != null && selectedPlaylistEntries.Count() == 1)),
                                                                       _ => this.library.PlaySongAsync(this.CurrentPlaylist.SelectedEntries.First().Index, this.accessToken));

            this.PauseCommand = ReactiveCommand.CreateAsyncTask(this.library.LocalAccessControl.HasAccess(this.coreSettings.WhenAnyValue(x => x.LockPlayPause), this.accessToken)
                                                                .CombineLatest(this.WhenAnyValue(x => x.IsPlaying), (hasAccess, isPlaying) => hasAccess && isPlaying),
                                                                _ => this.library.PauseSongAsync(this.accessToken));

            var pauseOrContinueCommand = this.WhenAnyValue(x => x.IsPlaying)
                                         .Select(x => x ? this.PauseCommand : this.PlayCommand).Publish(null);

            pauseOrContinueCommand.Connect();

            this.PauseContinueCommand = ReactiveCommand.CreateAsyncTask(
                pauseOrContinueCommand.Select(x => x.CanExecuteObservable).Switch().ObserveOn(RxApp.MainThreadScheduler),
                async _ =>
            {
                IReactiveCommand <Unit> command = await pauseOrContinueCommand.FirstAsync();
                await command.ExecuteAsync();
            });

            this.EditPlaylistNameCommand = ReactiveCommand.Create(this.WhenAnyValue(x => x.CanAlterPlaylist, x => x.CurrentPlaylist, (x1, x2) => x1 && !x2.Model.IsTemporary));
            this.EditPlaylistNameCommand.Subscribe(x => this.CurrentPlaylist.EditName = true);

            this.RemovePlaylistCommand = ReactiveCommand.Create(this.WhenAnyValue(x => x.CurrentEditedPlaylist, x => x.CurrentPlaylist, x => x.CanAlterPlaylist,
                                                                                  (currentEditedPlaylist, currentPlaylist, canAlterPlaylist) => (currentEditedPlaylist != null || currentPlaylist != null) && canAlterPlaylist));
            this.RemovePlaylistCommand.Subscribe(x => this.RemoveCurrentPlaylist());

            this.IsLocal = true;
        }
    // this was my first attempt without actually analyzing the current NavigateCommandFor source
    public static IReactiveCommand <object> NavigateCommandFor1 <T>(this RoutingState This, IReactiveCommand <object> navigationCommand = null, IDependencyResolver dependencyResolver = null, string contract = null)
        where T : IRoutableViewModel
    {
        navigationCommand = navigationCommand ?? This.Navigate;
        var ret = ReactiveCommand.CreateAsyncObservable(navigationCommand.CanExecuteObservable, _ => navigationCommand.ExecuteAsync((dependencyResolver ?? Locator.Current).GetService <T>(contract)));

        return(ret.SubscribeToCommand());
    }
Example #10
0
        private static async Task assertExceptionForwardedToThrownExceptions(IReactiveCommand<Unit> command, Exception exception)
        {
            var exceptions = command.ThrownExceptions.CreateCollection();

            await command.ExecuteAsync()
                         .Catch(Observable.Empty<Unit>())
                         .DefaultIfEmpty(Unit.Default);

            Assert.Equal(1, exceptions.Count);
            Assert.Contains(exception, exceptions);
        }