Exemple #1
0
        private void SetupMobileApi()
        {
            var library = Locator.Current.GetService <Library>();

            this.Log().Info("Remote control is {0}", this.coreSettings.EnableRemoteControl ? "enabled" : "disabled");
            this.Log().Info("Port is set to {0}", this.coreSettings.Port);

            IObservable <MobileApi> apiChanged = this.coreSettings.WhenAnyValue(x => x.Port).DistinctUntilChanged()
                                                 .CombineLatest(this.coreSettings.WhenAnyValue(x => x.EnableRemoteControl), Tuple.Create)
                                                 .Do(_ =>
            {
                if (this.mobileApi != null)
                {
                    this.mobileApi.Dispose();
                    this.mobileApi = null;
                }
            })
                                                 .Where(x => x.Item2)
                                                 .Select(x => x.Item1)
                                                 .Select(x => new MobileApi(x, library)).Publish(null).RefCount().Where(x => x != null);

            apiChanged.Subscribe(x =>
            {
                this.mobileApi = x;
                x.SendBroadcastAsync();
                x.StartClientDiscovery();
            });

            IConnectableObservable <IReadOnlyList <MobileClient> > connectedClients = apiChanged.Select(x => x.ConnectedClients).Switch().Publish(new List <MobileClient>());

            connectedClients.Connect();

            IConnectableObservable <bool> isPortOccupied = apiChanged.Select(x => x.IsPortOccupied).Switch().Publish(false);

            isPortOccupied.Connect();

            var apiStats = new MobileApiInfo(connectedClients, isPortOccupied);

            Locator.CurrentMutable.RegisterConstant(apiStats, typeof(MobileApiInfo));
        }
Exemple #2
0
        public SettingsViewModel(Library library, ViewSettings viewSettings, CoreSettings coreSettings, IWindowManager windowManager, Guid accessToken, MobileApiInfo mobileApiInfo)
        {
            if (library == null)
                Throw.ArgumentNullException(() => library);

            if (viewSettings == null)
                Throw.ArgumentNullException(() => viewSettings);

            if (coreSettings == null)
                Throw.ArgumentNullException(() => coreSettings);

            if (mobileApiInfo == null)
                throw new ArgumentNullException("mobileApiInfo");

            this.library = library;
            this.viewSettings = viewSettings;
            this.coreSettings = coreSettings;
            this.windowManager = windowManager;
            this.accessToken = accessToken;

            this.canCreateAdmin = this
                .WhenAnyValue(x => x.CreationPassword, x => !string.IsNullOrWhiteSpace(x) && !this.isAdminCreated)
                .ToProperty(this, x => x.CanCreateAdmin);

            this.CreateAdminCommand = ReactiveCommand.Create(this.WhenAnyValue(x => x.CanCreateAdmin),
                ImmediateScheduler.Instance); // Immediate execution, because we set the password to an empty string afterwards
            this.CreateAdminCommand.Subscribe(p =>
            {
                this.library.LocalAccessControl.SetLocalPassword(this.accessToken, this.CreationPassword);
                this.isAdminCreated = true;
            });

            this.ChangeToPartyCommand = ReactiveCommand.Create(this.CreateAdminCommand.Select(x => true).StartWith(false));
            this.ChangeToPartyCommand.Subscribe(p =>
            {
                this.library.LocalAccessControl.DowngradeLocalAccess(this.accessToken);
                this.ShowSettings = false;
            });

            this.canLogin = this.WhenAnyValue(x => x.LoginPassword, x => !string.IsNullOrWhiteSpace(x))
                .ToProperty(this, x => x.CanLogin);

            this.LoginCommand = ReactiveCommand.Create(this.WhenAnyValue(x => x.CanLogin),
                ImmediateScheduler.Instance); // Immediate execution, because we set the password to an empty string afterwards
            this.LoginCommand.Subscribe(p =>
            {
                try
                {
                    this.library.LocalAccessControl.UpgradeLocalAccess(this.accessToken, this.LoginPassword);
                    this.IsWrongPassword = false;

                    this.ShowLogin = false;
                    this.ShowSettings = true;
                }

                catch (WrongPasswordException)
                {
                    this.IsWrongPassword = true;
                }
            });

            this.OpenLinkCommand = ReactiveCommand.Create();
            this.OpenLinkCommand.Cast<string>().Subscribe(x =>
            {
                try
                {
                    Process.Start(x);
                }

                catch (Win32Exception ex)
                {
                    this.Log().ErrorException(String.Format("Could not open link {0}", x), ex);
                }
            });

            this.ReportBugCommand = ReactiveCommand.Create();
            this.ReportBugCommand.Subscribe(p => this.windowManager.ShowWindow(new BugReportViewModel()));

            this.ChangeAccentColorCommand = ReactiveCommand.Create();
            this.ChangeAccentColorCommand.Subscribe(x => this.viewSettings.AccentColor = (string)x);

            this.ChangeAppThemeCommand = ReactiveCommand.Create();
            this.ChangeAppThemeCommand.Subscribe(x => this.viewSettings.AppTheme = (string)x);

            this.UpdateLibraryCommand = ReactiveCommand.Create(this.library.WhenAnyValue(x => x.IsUpdating, x => !x)
                .ObserveOn(RxApp.MainThreadScheduler)
                .CombineLatest(this.library.WhenAnyValue(x => x.SongSourcePath).Select(x => !String.IsNullOrEmpty(x)), (x1, x2) => x1 && x2));
            this.UpdateLibraryCommand.Subscribe(_ => this.library.UpdateNow());

            this.librarySource = this.library.WhenAnyValue(x => x.SongSourcePath)
                .ToProperty(this, x => x.LibrarySource);

            this.port = this.coreSettings.Port;
            this.ChangePortCommand = ReactiveCommand.Create(this.WhenAnyValue(x => x.Port, NetworkHelpers.IsPortValid));
            this.ChangePortCommand.Subscribe(_ => this.coreSettings.Port = this.Port);

            this.remoteControlPassword = this.coreSettings.RemoteControlPassword;
            this.ChangeRemoteControlPasswordCommand = ReactiveCommand.Create(this.WhenAnyValue(x => x.RemoteControlPassword)
                .Select(x => !String.IsNullOrWhiteSpace(x)));
            this.ChangeRemoteControlPasswordCommand.Subscribe(x =>
                this.library.RemoteAccessControl.SetRemotePassword(this.accessToken, this.RemoteControlPassword));
            this.showRemoteControlPasswordError = this.WhenAnyValue(x => x.RemoteControlPassword, x => x.LockRemoteControl,
                    (password, lockRemoteControl) => String.IsNullOrWhiteSpace(password) && lockRemoteControl)
                .ToProperty(this, x => x.ShowRemoteControlPasswordError);

            this.isRemoteAccessReallyLocked = this.library.RemoteAccessControl.WhenAnyValue(x => x.IsRemoteAccessReallyLocked)
                .ToProperty(this, x => x.IsRemoteAccessReallyLocked);

            this.isPortOccupied = mobileApiInfo.IsPortOccupied.ToProperty(this, x => x.IsPortOccupied);

            this.enableChangelog = this.viewSettings.WhenAnyValue(x => x.EnableChangelog)
                .ToProperty(this, x => x.EnableChangelog);

            this.defaultPlaybackEngine = this.coreSettings.WhenAnyValue(x => x.DefaultPlaybackEngine)
                .ToProperty(this, x => x.DefaultPlaybackEngine);
        }
Exemple #3
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;
        }
Exemple #4
0
        public SettingsViewModel(Library library, ViewSettings viewSettings, CoreSettings coreSettings, IWindowManager windowManager, Guid accessToken, MobileApiInfo mobileApiInfo)
        {
            if (library == null)
            {
                throw new ArgumentNullException(nameof(library));
            }

            if (viewSettings == null)
            {
                throw new ArgumentNullException(nameof(viewSettings));
            }

            if (coreSettings == null)
            {
                throw new ArgumentNullException(nameof(coreSettings));
            }

            if (mobileApiInfo == null)
            {
                throw new ArgumentNullException(nameof(mobileApiInfo));
            }

            this.library       = library;
            this.viewSettings  = viewSettings;
            this.coreSettings  = coreSettings;
            this.windowManager = windowManager;
            this.accessToken   = accessToken;

            this.canCreateAdmin = this
                                  .WhenAnyValue(x => x.CreationPassword, x => !string.IsNullOrWhiteSpace(x) && !this.isAdminCreated)
                                  .ToProperty(this, x => x.CanCreateAdmin);

            this.CreateAdminCommand = ReactiveCommand.Create(this.WhenAnyValue(x => x.CanCreateAdmin),
                                                             ImmediateScheduler.Instance); // Immediate execution, because we set the password to an empty string afterwards
            this.CreateAdminCommand.Subscribe(p =>
            {
                this.library.LocalAccessControl.SetLocalPassword(this.accessToken, this.CreationPassword);
                this.isAdminCreated = true;
            });

            this.ChangeToPartyCommand = ReactiveCommand.Create(this.CreateAdminCommand.Select(x => true).StartWith(false));
            this.ChangeToPartyCommand.Subscribe(p =>
            {
                this.library.LocalAccessControl.DowngradeLocalAccess(this.accessToken);
                this.ShowSettings = false;
            });

            this.canLogin = this.WhenAnyValue(x => x.LoginPassword, x => !string.IsNullOrWhiteSpace(x))
                            .ToProperty(this, x => x.CanLogin);

            this.LoginCommand = ReactiveCommand.Create(this.WhenAnyValue(x => x.CanLogin),
                                                       ImmediateScheduler.Instance); // Immediate execution, because we set the password to an empty string afterwards
            this.LoginCommand.Subscribe(p =>
            {
                try
                {
                    this.library.LocalAccessControl.UpgradeLocalAccess(this.accessToken, this.LoginPassword);
                    this.IsWrongPassword = false;

                    this.ShowLogin    = false;
                    this.ShowSettings = true;
                }

                catch (WrongPasswordException)
                {
                    this.IsWrongPassword = true;
                }
            });

            this.OpenLinkCommand = ReactiveCommand.Create();
            this.OpenLinkCommand.Cast <string>().Subscribe(x =>
            {
                try
                {
                    Process.Start(x);
                }

                catch (Win32Exception ex)
                {
                    this.Log().ErrorException("Could not open link \{x}", ex);
                }
            });