// TODO: 視聴開始(会場後のみ、チャンネル会員限定やチケット必要な場合あり) // TODO: タイムシフト予約(tsがある場合のみ、会場前のみ、プレミアムの場合は会場後でも可) // TODO: 後からタイムシフト予約(プレミアムの場合のみ) // TODO: 配信説明 // TODO: タグ // TODO: 配信者(チャンネルやコミュニティ)の概要説明 // TODO: 配信者(チャンネルやコミュニティ)のフォロー // TODO: オススメ生放送(放送中、放送予定を明示) // TODO: ニコニコ市場 // TODO: SNS共有 // gateとwatchをどちらも扱った上でその差を意識させないように表現する // LiveInfo.Video.CurrentStatusは開演前、放送中は時間の経過によって変化する可能性がある public LiveInfomationPageViewModel( PageManager pageManager, Models.NiconicoSession niconicoSession, NicoLiveProvider nicoLiveProvider, DialogService dialogService, Services.HohoemaPlaylist hohoemaPlaylist, ExternalAccessService externalAccessService ) : base(pageManager) { NiconicoSession = niconicoSession; NicoLiveProvider = nicoLiveProvider; HohoemaDialogService = dialogService; HohoemaPlaylist = hohoemaPlaylist; ExternalAccessService = externalAccessService; IsLoadFailed = new ReactiveProperty <bool>(false) .AddTo(_CompositeDisposable); LoadFailedMessage = new ReactiveProperty <string>() .AddTo(_CompositeDisposable); IsLiveIdAvairable = this.ObserveProperty(x => x.LiveId) .Select(x => x != null ? NiconicoRegex.IsLiveId(x) : false) .ToReadOnlyReactiveProperty() .AddTo(_CompositeDisposable); IsLoggedIn = NiconicoSession.ObserveProperty(x => x.IsLoggedIn) .ToReadOnlyReactiveProperty() .AddTo(_CompositeDisposable); IsPremiumAccount = NiconicoSession.ObserveProperty(x => x.IsPremiumAccount) .ToReadOnlyReactiveProperty() .AddTo(_CompositeDisposable); _IsTsPreserved = new ReactiveProperty <bool>(false) .AddTo(_CompositeDisposable); LiveTags = new ReadOnlyObservableCollection <LiveTagViewModel>(_LiveTags); IchibaItems = new ReadOnlyObservableCollection <IchibaItem>(_IchibaItems); ReccomendItems = _ReccomendItems.ToReadOnlyReactiveCollection(x => { var liveId = "lv" + x.ProgramId; var liveInfoVM = new LiveInfoListItemViewModel(liveId); liveInfoVM.Setup(x); var reserve = _Reservations?.ReservedProgram.FirstOrDefault(reservation => liveId == reservation.Id); if (reserve != null) { liveInfoVM.SetReservation(reserve); } return(liveInfoVM); }) .AddTo(_CompositeDisposable); IsShowOpenLiveContentButton = this.ObserveProperty(x => LiveInfo) .Select(x => { if (LiveInfo == null) { return(false); } if (NiconicoSession.IsPremiumAccount) { if (LiveInfo.Video.OpenTime > DateTime.Now) { return(false); } return(LiveInfo.Video.TimeshiftEnabled); } else { // 一般アカウントは放送中のみ if (LiveInfo.Video.OpenTime > DateTime.Now) { return(false); } if (_IsTsPreserved.Value) { return(true); } if (LiveInfo.Video.EndTime < DateTime.Now) { return(false); } return(true); } }) .ToReadOnlyReactiveProperty() .AddTo(_CompositeDisposable); IsShowAddTimeshiftButton = this.ObserveProperty(x => LiveInfo) .Select(x => { if (LiveInfo == null) { return(false); } if (!LiveInfo.Video.TimeshiftEnabled) { return(false); } if (!NiconicoSession.IsLoggedIn) { return(false); } if (!niconicoSession.IsPremiumAccount) { // 一般アカウントは放送開始の30分前からタイムシフトの登録はできなくなる if ((LiveInfo.Video.StartTime - TimeSpan.FromMinutes(30)) < DateTime.Now) { return(false); } } if (LiveInfo.Video.TsArchiveEndTime != null && LiveInfo.Video.TsArchiveEndTime > DateTime.Now) { return(false); } if (_IsTsPreserved.Value) { return(false); } return(true); }) .ToReadOnlyReactiveProperty() .AddTo(_CompositeDisposable); IsShowDeleteTimeshiftButton = _IsTsPreserved; }
public SearchSummaryPageViewModel( SearchProvider searchProvider, Services.PageManager pageManager ) : base(pageManager) { RelatedVideoTags = new ObservableCollection <string>(); KeywordSearchResultItems = this.ObserveProperty(x => x.Keyword) .Where(x => !string.IsNullOrWhiteSpace(x)) .SelectMany(async(x, i, cancelToken) => { RelatedVideoTags.Clear(); var res = await SearchProvider.GetKeywordSearch(x, 0, 10); if (res.IsOK) { KeywordSearchItemsTotalCount = (int)res.GetTotalCount(); if (res.Tags != null) { foreach (var tag in res.Tags.TagItems) { RelatedVideoTags.Add(tag.Name); } } return(res.VideoInfoItems?.AsEnumerable() ?? Enumerable.Empty <Mntone.Nico2.Searches.Video.VideoInfo>()); } else { return(Enumerable.Empty <Mntone.Nico2.Searches.Video.VideoInfo>()); } }) .SelectMany(x => x) .Select(x => { var vm = new VideoInfoControlViewModel(x.Video.Id); vm.SetTitle(x.Video.Title); vm.SetThumbnailImage(x.Video.ThumbnailUrl.OriginalString); return(vm); }) .ToReadOnlyReactiveCollection(onReset: this.ObserveProperty(x => x.Keyword).ToUnit()) .AddTo(_CompositeDisposable); HasKeywordSearchResultItems = KeywordSearchResultItems .ObserveProperty(x => x.Count) .Select(x => x > 0) .ToReadOnlyReactiveProperty() .AddTo(_CompositeDisposable); RelatedLiveTags = new ObservableCollection <string>(); LiveSearchResultItems = this.ObserveProperty(x => x.Keyword) .Where(x => !string.IsNullOrWhiteSpace(x)) .SelectMany(async(x, i, cancelToken) => { RelatedLiveTags.Clear(); var res = await SearchProvider.LiveSearchAsync(x, false, length: 10); if (res.IsStatusOK) { if (res.Tags != null) { foreach (var tag in res.Tags.Tag) { RelatedLiveTags.Add(tag.Name); } } LiveSearchItemsTotalCount = res.TotalCount.FilteredCount; return(res.VideoInfo?.AsEnumerable() ?? Enumerable.Empty <Mntone.Nico2.Searches.Live.VideoInfo>()); } else { return(Enumerable.Empty <Mntone.Nico2.Searches.Live.VideoInfo>()); } }) .SelectMany(x => x) .Select(x => { var liveInfoVM = new LiveInfoListItemViewModel(x.Video.Id); liveInfoVM.Setup(x); return(liveInfoVM); }) .ToReadOnlyReactiveCollection(onReset: this.ObserveProperty(x => x.Keyword).ToUnit()); HasLiveSearchResultItems = LiveSearchResultItems .ObserveProperty(x => x.Count) .Select(x => x > 0) .ToReadOnlyReactiveProperty() .AddTo(_CompositeDisposable); SearchProvider = searchProvider; }