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)); }
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); }
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; }
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); } });