/// <summary>
        /// Create the new slides and load them up.
        /// </summary>
        /// <param name="n"></param>
        /// <param name="pdfFile"></param>
        /// <param name="fullVM"></param>
        /// <returns></returns>
        private async Task <SlideThumbViewModel[]> CreateNewThumbs(int n, PDFFile pdfFile, Lazy <FullTalkAsStripViewModel> fullVM)
        {
            var newSlides = Enumerable.Range(SlideThumbnails.Count, n - SlideThumbnails.Count).Select(i => new SlideThumbViewModel(pdfFile.GetPageStreamAndCacheInfo(i), fullVM, i)).ToArray();

            foreach (var sld in newSlides)
            {
                await sld.LoadSize();
            }
            return(newSlides);
        }
Example #2
0
        /// <summary>
        /// Get everything setup to show the PDF document
        /// </summary>
        /// <param name="docSequence"></param>
        /// <param name="initialPage">The page that should be shown when we start up. Zero indexed</param>
        /// <param name="screen">The screen that hosts everything (routing!)</param>
        public FullTalkAsStripViewModel(IScreen screen, PDFFile file)
        {
            Debug.Assert(file != null);
            Debug.Assert(screen != null);

            HostScreen = screen;

            // We basically re-set each time a new file comes down from the top.

            Pages = new ReactiveList <PDFPageViewModel>();

            var pageSizeChanged = file.WhenAny(x => x.NumberOfPages, x => x.Value)
                                  .DistinctUntilChanged()
                                  .ObserveOn(RxApp.MainThreadScheduler);

            var b = from newPageLength in pageSizeChanged
                    let np = Pages.Count
                             from allpages in CreateNPages(newPageLength - np, np, file)
                             select new {
                numPages   = newPageLength,
                freshPages = allpages
            };

            b
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(info => SetNPages(info.numPages, info.freshPages));

            // Page navigation. Make sure things are clean and we don't over-burden the UI before
            // we pass the info back to the UI!
            _moveToPage = new ReplaySubject <int>(1);
            _loaded     = new ReplaySubject <Unit>(1);
            MoveToPage  = _moveToPage
                          .CombineLatest(_loaded, (p, _) => p)
                          .Select(scrubPageIndex)
                          .DistinctUntilChanged();

            PageForward = ReactiveCommand.Create();
            PageForward
            .Cast <int>()
            .Select(pn => pn + 1)
            .Subscribe(_moveToPage);

            PageBack = ReactiveCommand.Create();
            PageBack
            .Cast <int>()
            .Select(pn => pn - 1)
            .Subscribe(_moveToPage);

            PageMove = ReactiveCommand.Create();
            PageMove
            .Cast <int>()
            .Subscribe(_moveToPage);
        }
Example #3
0
        /// <summary>
        /// Create n pages, as requested, and prepare them for the UI.
        /// </summary>
        /// <param name="n"></param>
        /// <param name="file"></param>
        /// <returns></returns>
        private async Task <PDFPageViewModel[]> CreateNPages(int n, int start_index, PDFFile file)
        {
            if (n <= 0)
            {
                return(new PDFPageViewModel[0]);
            }

            // Create and initialize pages
            var newPages        = Enumerable.Range(start_index, n).Select(i => new PDFPageViewModel(file.GetPageStreamAndCacheInfo(i))).ToArray();
            var sequenceOfPages = newPages.Select(p => p.LoadSize());

            foreach (var seq in sequenceOfPages)
            {
                var r = await seq.ToArray();
            }

            return(newPages);
        }
        /// <summary>
        /// Setup the VM for the file.
        /// </summary>
        /// <param name="downloader">The download controller. This assumes this is for a PDF file, and it is Valid.</param>
        /// <param name="talkTime">The time that this guy is relevant</param>
        public FileSlideListViewModel(PDFFile pdfFile, TimePeriod talkTime)
        {
            // Get the object consistent.
            SlideThumbnails = new ReactiveList <SlideThumbViewModel>();

            // We will want to refresh the view of this file depending on how close we are to the actual
            // meeting time.

            var innerBuffer = new TimePeriod(talkTime);

            innerBuffer.StartTime -= TimeSpan.FromMinutes(30);
            innerBuffer.EndTime   += TimeSpan.FromHours(2);

            var updateTalkFile = Observable.Empty <Unit>();

            if (innerBuffer.Contains(DateTime.Now))
            {
                // Fire every 15 minutes, but only while in the proper time.
                // We only check when requested, so we will start right off the bat.
                updateTalkFile = Observable.Return(default(Unit))
                                 .Concat(Observable.Interval(TimeSpan.FromMinutes(15))
                                         .Where(_ => innerBuffer.Contains(DateTime.Now))
                                         .Select(_ => default(Unit))
                                         )
                                 .Where(_ => Settings.AutoDownloadNewMeeting);
            }

            // A view model to show the whole thing as a strip view.
            var fullVM = new Lazy <FullTalkAsStripViewModel>(() => new FullTalkAsStripViewModel(Locator.Current.GetService <IScreen>(), pdfFile));

            // All we do is sit and watch for the # of pages to change, and when it does, we fix up the list of SlideThumbViewModel.
            var newSlideInfo = from nPages in pdfFile.WhenAny(x => x.NumberOfPages, x => x.Value).DistinctUntilChanged()
                               from newSlides in CreateNewThumbs(nPages, pdfFile, fullVM)
                               select new
            {
                n      = nPages,
                slides = newSlides
            };

            newSlideInfo
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(info => SetNumberOfThumbNails(info.n, info.slides));
        }
        /// <summary>
        /// Setup the links to run.
        /// </summary>
        public ExpandingSlideThumbViewModel(PDFFile downloader, TimePeriod talkTime)
        {
            // Showing the slides should generate it here, and nullify it everywhere else.
            ShowSlides = ReactiveCommand.Create();

            // FIre the reset command, with the current downloader as an argument
            ShowSlides
            .Select(_ => downloader)
            .InvokeCommand(_resetSlideShow);

            // When the reset shows up, only pay attention if a different file is being shown
            // and we have something to show!
            var noThumbs = _resetSlideShow
                           .Where(dl => downloader != dl && downloader.NumberOfPages != 0)
                           .Select(_ => (FileSlideListViewModel)null);

            // When we want to show the slides just create the new view model.
            var newThumbs = ShowSlides
                            .Select(_ => new FileSlideListViewModel(downloader, talkTime));

            // Now, allow the property we manage to flip back and forth here.
            Observable.Merge(newThumbs, noThumbs)
            .WriteLine(x => string.Format("--> writing out a {0} to the actual display property.", x == null ? "null" : "non-null"))
            .ToProperty(this, x => x.TalkAsThumbs, out _talkAsThumbs, null, RxApp.MainThreadScheduler);

            // The logic for canShowThumbs is tricky:
            // 1. True if the downloader has downloaded and opened the file and parsed it successfully (# pages != 0).
            // 2. False if we have fired off a new thumbs guy, but that can be only active if can show thumbs is true (right??).
            // 3. True if we've shown thumbs and we stop showing them.

            var downloaded = downloader.WhenAny(x => x.NumberOfPages, x => x.Value != 0);
            var areShowing = Observable.Merge(newThumbs, noThumbs)
                             .Select(x => x == null ? true : false);

            Observable.Merge(downloaded, areShowing)
            .WriteLine(x => string.Format("  -> and writing out {0} for can show thumbs", x))
            .ToProperty(this, x => x.CanShowThumbs, out _canShowThumbs, false, RxApp.MainThreadScheduler);

            // Track the # of pages. Used to display some info below the button in most implementations.
            downloader.WhenAny(x => x.NumberOfPages, x => x.Value)
            .ToProperty(this, x => x.NumberOfSlides, out _numberOfSlides, 0, RxApp.MainThreadScheduler);
        }
        /// <summary>
        /// Configure for showing multiple files.
        /// </summary>
        /// <param name="files"></param>
        public TalkFileCollectionUserControlViewModel(IFile[] files, ITalk t)
        {
            // The title we use is what we grab from the first file.
            Title = files.Length > 0 ? files[0].DisplayName : "";

            // Show the list of files that can downloaded/opened. These guys can opened by other
            // apps in the system by clicking or pressing on them.
            var allFilesVM = (from f in files
                              select new
            {
                FilePointer = f,
                UserControl = new FileUserControlViewModel(f)
            })
                             .ToArray();

            TalkFiles = new ReactiveList <FileUserControlViewModel>();
            TalkFiles.AddRange(allFilesVM.Select(f => f.UserControl));

#if WINDOWS_APP
            // If there is a PDF file, then we use that to show a "hero" slide.
            // TODO: WARNING - this will create a PDFFile, but one may not want that here
            // if one is also going to create other PDF file guys!!
            var pdf = allFilesVM.Where(f => f.FilePointer.FileType == "pdf" && f.FilePointer.IsValid).FirstOrDefault();
            if (pdf != null)
            {
                var pdfFile = new PDFFile(pdf.UserControl.FileDownloader);
                var fullVM  = new Lazy <FullTalkAsStripViewModel>(() => new FullTalkAsStripViewModel(Locator.Current.GetService <IScreen>(), pdfFile));
                HeroSlide = new FirstSlideHeroViewModel(pdfFile, fullVM);

                var timeSpan = new TimePeriod(t.StartTime, t.EndTime);
                Thumbs = new ExpandingSlideThumbViewModel(pdfFile, timeSpan);
            }
            else
            {
                HeroSlide = new FirstSlideHeroViewModel((PDFFile)null, null);
            }
#endif
        }
        /// <summary>
        /// Create the VM. We generate a first page hero slide.
        /// </summary>
        /// <param name="file">The PDF File to generate. If null, we will make this VM as invalid</param>
        public FirstSlideHeroViewModel(PDFFile file, Lazy <FullTalkAsStripViewModel> fullVM)
        {
            // If we are actually connected to a file, then
            // - setup the hero slide
            // - a button to show all slides
            _heroPageUC   = null;
            HaveHeroSlide = false;
            if (file != null)
            {
                // Hero slide. Tricky because we can't display until
                // a fetch has been done on the PDF data.
                var pdf = new PDFPageViewModel(file.GetPageStreamAndCacheInfo(0));
                _heroPageUC = pdf.LoadSize()
                              .Select(_ => pdf)
                              .ToProperty(this, m => m.HeroPageUC, scheduler: RxApp.MainThreadScheduler);

                HaveHeroSlide = true;

                // Allow a full view
                OpenFullView = ReactiveCommand.Create();
                OpenFullView
                .Subscribe(_ => fullVM.Value.LoadPage(0));
            }
        }