public PlaylistViewModel(IScreen hostScreen, IEventAggregator eventAggregator, IPlayerModel player, IPlaylistStore playlistStore) : base(eventAggregator) { HostScreen = hostScreen; Player = player; this.playlistStore = playlistStore; GetPlaylistsCommand = ReactiveCommand.CreateFromTask(async _ => await GetPlaylists()); GetPlaylistsCommand.IsExecuting.Subscribe(_ => IsPlaylistsBusy = _); InitPlaylistItemsCommand = ReactiveCommand.CreateFromTask <Playlist>(async _ => await LoadPlaylist(_)); InitPlaylistItemsCommand.IsExecuting.Subscribe(_ => IsPlaylistItemsBusy = _); // detail this.WhenAnyValue(vm => vm.SelectedPlaylistItem) .NotNull() .Select(_ => _.Item) .Cast <IDetailEntity>() .ToProperty(this, _ => _.CurrentDetailEntity, out currentDetailEntity); // add to playlist AddPlaylistCommand = ReactiveCommand.CreateFromTask(async _ => await AddPlaylist()); AddToPlaylist = ReactiveCommand.CreateFromTask <Playlist>(async _ => await AddEpisodeToPlaylist(_)); // remove from playlist RemoveFromPlaylist = ReactiveCommand.CreateFromTask(async _ => await RemoveItemFromPlaylist()); // delete playlist DeletePlaylistCommand = ReactiveCommand.CreateFromTask <Playlist>(async _ => await DeletePlaylist(_)); // play PlayItemCommand = ReactiveCommand.Create <IPlayable>(_ => OnPlayItem()); // bring into view ScrollIntoView = ReactiveCommand.Create <int, int>(_ => _, this.WhenAny(_ => _.Player.Playlist.Current, _ => _ != null)); // sort order PlaylistItemOrderBy.OnNext(new IOrderByExpression <PlaylistItem>[] { new OrderByExpression <PlaylistItem, int>(e => e.OrderNumber) }); // locate current track this.WhenAnyValue(vm => vm.Player.LocateCurrent) .NotNull() .Subscribe(c => c.Subscribe(_ => LocatePageForCurrent())); // selected playlist changed this.WhenAnyValue(_ => _.SelectedPlaylist) .NotNull() .DistinctUntilChanged() .Subscribe(async _ => await OnSelectedPlaylist(_)); // on playlists changed this.WhenAnyValue(_ => _.Playlists).NotNull().Subscribe(_ => OnPlaylistsChanged()); // detail ToggleShowDetailCommand = ReactiveCommand.Create <bool, bool>(_ => _); // deactivation DeactivateCommand = ReactiveCommand.Create(() => { }); }
public PlayerViewModel(IEventAggregator eventAggregator, IPlaylistStore playlistStore, IPlayer player) : base(eventAggregator) { this.playlistStore = playlistStore; this.player = player; // toggle play var canTogglePlay = this.WhenAnyValue(vm => vm.MediaUri).Select(_ => _ != null); TogglePlayCommand = ReactiveCommand.Create <Unit>(_ => TogglePlay(), canTogglePlay); TogglePlayCommand.ThrownExceptions.Subscribe(OnMediaFailed); // open media OpenMediaCommand = ReactiveCommand.CreateFromTask(async _ => await OpenMedia()); OpenMediaCommand.IsExecuting.ToProperty(this, _ => _.IsBusy, out isBusy); // shortcut EventAggregator.GetEvent <ShortcutEvent>() .Where(_ => _.Type == ShortcutCommandType.TogglePlay) .Subscribe(_ => OnTogglePlayShortcut()); //play next, previous PlayPrevious = ReactiveCommand.Create <Unit>(_ => Playlist.PlayPrevious(), this.WhenAny(vm => vm.Playlist.Previous, e => e.Value != null)); PlayNext = ReactiveCommand.Create <Unit>(_ => Playlist.PlayNext(), this.WhenAny(vm => vm.Playlist.Next, e => e.Value != null)); // playlist // TODO obsolete? ShowPlaylist = ReactiveCommand.Create <Unit>(_ => { }, this.WhenAny(vm => vm.Playlist, p => p.Value != null && p.Value.AnyItems())); // volume MuteVolumeToggle = ReactiveCommand.Create <Unit>(_ => ToggleMute()); this.WhenAnyValue(vm => vm.Volume).Skip(1).Subscribe(v => Settings.Default.PlayerVolume = v); this.WhenAnyValue(vm => vm.Volume).Subscribe(volume => IsMuted = volume <= 0); // reset active / playing on change this.WhenAnyValue(_ => _.Playlist).Previous().NotNull().Subscribe(_ => _.ClearActive()); // current episode this.WhenAnyValue(vm => vm.Playlist.Current).WithPrevious().Subscribe(async _ => { if (_.OldValue?.ItemId != _.NewValue?.ItemId) { await UpdateElapsed(_.OldValue?.Item); } SelectEpisode(); }); // volume this.WhenAnyValue(_ => _.Volume).Subscribe(_ => player.Volume = _); // set playlist element playing this.WhenAnyValue(_ => _.IsPlaying) .CombineLatest(this.WhenAnyValue(_ => _.Playlist.Current), (isPlaying, _) => isPlaying) .Where(_ => Playlist.Current != null) .Subscribe(_ => Playlist.SetCurrentPlaying(_)); // sync stream position this.WhenAnyValue(_ => _.StreamPosition) .Where(_ => Playlist?.Current != null) .Select(_ => _.TotalSeconds) .Subscribe(_ => Playlist.Current.Item.ElapsedSeconds = _); // locate LocateCurrent = ReactiveCommand.Create <Unit>(_ => { }); this.WhenAnyValue(_ => _.MediaUri).NotNull().Subscribe(async _ => await OpenMediaCommand.Execute()); // player stopped player.PlaybackStopped.ObserveOn(RxApp.MainThreadScheduler).Subscribe(OnStreamStopped); }
public PodcastViewModel(IScreen hostScreen, IPlayerModel player, IEventAggregator eventAggregator, IDialogService dialogService, IFeedParser feedParser, IChannelStore channelStore, IPlaylistStore playlistStore) : base(eventAggregator) { HostScreen = hostScreen; Player = player; DialogService = dialogService; FeedParser = feedParser; this.channelStore = channelStore; this.playlistStore = playlistStore; GetChannelsCommand = ReactiveCommand.CreateFromTask(async _ => await GetChannels()); GetChannelsCommand.IsExecuting.ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => OnChannelsBusy(GetChannelsCommand.GetHashCode(), _)); PlayItemCommand = ReactiveCommand.CreateFromTask <IPlayable>(async _ => await OnPlayEpisode(_ as Episode)); // open url OpenUrlDialogCommand = ReactiveCommand.CreateFromTask(async _ => await OpenUrlDialog()); OpenUrlDialogCommand.ThrownExceptions.ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => LogAndNotify(NotificationType.Error, Messages.ERR_CHANNEL_LOAD)); // channels busy indicator this.WhenAnyObservable(_ => _.ChannelsBusyList.CountChanged).DistinctUntilChanged() .Subscribe(_ => IsChannelsBusy = _ > 0); // episodes busy indicator this.WhenAnyObservable(_ => _.EpisodesBusyList.CountChanged).DistinctUntilChanged() .Subscribe(_ => IsEpisodesBusy = _ > 0); OpenUrlCommand = ReactiveCommand.CreateFromTask <string>(async _ => await OnOpenUrl(_)); OpenUrlCommand.ThrownExceptions.ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => LogAndNotify(NotificationType.Error, Messages.ERR_CHANNEL_LOAD)); // load channel LoadChannelFromUrlCommand = ReactiveCommand.CreateFromTask <string>(LoadChannelFromUrlAsync); OpenUrlCommand.IsExecuting.ObserveOn(RxApp.MainThreadScheduler).Subscribe(_ => { OnChannelsBusy(OpenUrlCommand.GetHashCode(), _); OnEpisodesBusy(OpenUrlCommand.GetHashCode(), _); }); LoadChannelFromUrlCommand.ThrownExceptions.ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => LogAndNotify(NotificationType.Error, Messages.ERR_CHANNEL_LOAD)); // delete channel ConfirmDeleteChannelCommand = ReactiveCommand.CreateFromTask <Channel>(async _ => await ConfirmDelete(_)); DeleteChannelCommand = ReactiveCommand.CreateFromTask <Channel>(async _ => await DeleteChannel(_)); DeleteChannelCommand.ThrownExceptions.ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => LogAndNotify(NotificationType.Error, Messages.ERR_CHANNEL_DELETE)); DeleteChannelCommand.IsExecuting.Subscribe(_ => { OnChannelsBusy(DeleteChannelCommand.GetHashCode(), _); OnEpisodesBusy(DeleteChannelCommand.GetHashCode(), _); }); var existsSelectedChannel = this.WhenAny(vm => vm.SelectedChannel, _ => SelectedChannel != null); this.WhenAnyValue(vm => vm.SelectedChannel).Select(_ => _ == null ? 0 : SelectedChannel.Id) .ToProperty(this, _ => _.SelectedChannelId, out selectedChannelId); RemoveFilterCommand = ReactiveCommand.Create <Unit>(_ => SelectedChannel = null, existsSelectedChannel); MarkAllPlayedCommand = ReactiveCommand.CreateFromTask <Channel>(async _ => await MarkChannelPlayed(_)); CopyUrlCommand = ReactiveCommand.Create <Channel>(_ => Clipboard.SetText(_.Link)); var episodeSet = this.WhenAnyValue(_ => _.SelectedEpisode); // detail this.WhenAnyValue(vm => vm.SelectedChannel).NotNull().Cast <IDetailEntity>() .Merge(episodeSet.Cast <IDetailEntity>()) .ToProperty(this, _ => _.CurrentDetailEntity, out currentDetailEntity); this.WhenAnyValue(vm => vm.Player.LocateCurrent).NotNull() .Subscribe(c => c.Subscribe(_ => LocatePageForCurrent())); // episode list is loading this.WhenAnyValue(_ => _.EpisodeList.IsLoading).SubscribeOn(RxApp.MainThreadScheduler) .Subscribe(_ => OnEpisodesBusy(EpisodeList.GetHashCode(), _)); ScrollIntoView = ReactiveCommand.Create <int, int>(_ => _); // playlist AddToPlaylist = ReactiveCommand.CreateFromTask <Playlist>(async _ => await AddEpisodeToPlaylist(_)); // sort order this.WhenAnyValue(_ => _.SelectedEpisodeSortOrder) .Subscribe(_ => EpisodeOrderBy.OnNext(GetEpisodeSortOrder(_))); ToggleSortDirectionCommand = ReactiveCommand.Create( () => EpisodeOrderBy.OnNext(GetEpisodeSortOrder(SelectedEpisodeSortOrder, false))); // on channels changed this.WhenAnyValue(_ => _.Channels).NotNull().Subscribe(_ => OnChannelsChanged()); // update channels var canUpdate = new BehaviorSubject <bool>(false); UpdateChannelsCommand = ReactiveCommand.CreateFromTask(async _ => await UpdateChannelsAsync(), canUpdate.DistinctUntilChanged()); UpdateChannelsCommand.IsExecuting.CombineLatest(this.WhenAnyValue(_ => _.Channels.IsEmpty), (exec, empty) => !exec && !empty && IsUpdateEnabled).DistinctUntilChanged() .Subscribe(_ => canUpdate.OnNext(_)); UpdateChannelsCommand.IsExecuting.ObserveOn(RxApp.MainThreadScheduler).Subscribe(_ => IsUpdating = _); UpdateChannelsCommand.ThrownExceptions.ObserveOn(RxApp.MainThreadScheduler) .Subscribe(_ => LogAndNotify(NotificationType.Error, Messages.ERR_CHANNEL_UPDATE)); // init episodes EpisodeList = InitEpisodeList(); EpisodeList.Changed.Subscribe(_ => InitActivePlaylist()); // detail ToggleShowDetailCommand = ReactiveCommand.Create <bool, bool>(_ => _); DeactivateCommand = ReactiveCommand.Create(() => { }); }