예제 #1
0
        public NormalHeatMapControl()
        {
            var changes = MeanSubject
                          .CombineLatest(StandardDeviationSubject, MinXSubject, MaxXSubject, MaxYSubject, (a, b, c, d, e) => Calculate(a, b, c, d, e));


            var minMax = MeanSubject
                         .CombineLatest(StandardDeviationSubject, (a, b) => CalculateMinMax(a, b));

            var esee = MeanSubject.CombineLatest(minMax, (a, b) => Calculate2(a, b.min, b.max));

            var esdse = MeanSubject
                        .CombineLatest(MinXSubject, MaxXSubject, (a, b, c) => Calculate2(a, b, c));


            var changes2 = MeanSubject
                           .CombineLatest(StandardDeviationSubject, minMax, (a, b, c) =>
            {
                return(Calculate(a, b, c.min, c.max, 1));
            });



            rect1Subject
            .CombineLatest(changes.Merge(changes2), esdse.Merge(esee), (a, b, c) => (a, b, c))
            .Subscribe(c =>
            {
                var(lower, middle, upper) = c.b;
                GradientStopAnimationExample(c.a, c.c, lower, middle, upper);
            });
        }
예제 #2
0
 public Equality()
 {
     Value1Changes.CombineLatest(Value2Changes, (one, two) => new { one, two }).Subscribe(_ =>
     {
         this.SetValue(IsEqualProperty, _.one.Equals(_.two));
     });
 }
예제 #3
0
        public InputBindings(
            InputSourceMapping <TAction> initialMapping,
            IObservable <InputSettings> inputSettingChanges,
            IImmutableDictionary <InputDefaults, InputSourceMapping <TAction> > defaultMappings)
        {
            _defaultMappings    = defaultMappings;
            _usesDefaultMapping = false;
            foreach (var defaultMapping in defaultMappings.Values)
            {
                if (initialMapping.Equals(defaultMapping))
                {
                    _usesDefaultMapping = true;
                }
            }

            _inputMappings = new BehaviorSubject <InputSourceMapping <TAction> >(initialMapping);
            _inputMappings.Subscribe(mapping => {
                _currentMapping = mapping;
            });
            _activeControllerId      = null;
            _activeControllerUpdates = new BehaviorSubject <JoystickActivator.Controller?>(null);

            _actionMap = _inputMappings.CombineLatest(
                _activeControllerUpdates,
                inputSettingChanges.DistinctUntilChanged(EqualityComparer <InputSettings> .Default),
                (mapping, controller, settings) => {
                var controllerId = controller.HasValue ? controller.Value.Id : null;
                return(new ActionMapConfig <TAction> {
                    InputMapping = mapping,
                    ControllerId = controllerId,
                    InputSettings = settings
                });
            });
        }
예제 #4
0
 public GaussianControl()
 {
     rect1Subject
     .CombineLatest(ratioSubject, (a, b) => (a, b))
     .Subscribe(c =>
     {
         GradientStopAnimationExample(c.a, c.b / 100d);
     });
 }
예제 #5
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);
        }
예제 #6
0
        public override void OnApplyTemplate()
        {
            DataGrid = this.GetTemplateChild("DataGrid") as DataGrid;

            DataGrid.ItemsSource = dataTable?.DefaultView;
            var buttonSaveToCsv = this.GetTemplateChild("Save_To_Csv") as Button;

            buttonSave         = this.GetTemplateChild("Save") as Button;
            buttonLoad         = this.GetTemplateChild("Load") as Button;
            sliderItemsControl = this.GetTemplateChild("SliderItemsControl") as SliderItemsControl;

            Diagram = this.GetTemplateChild("Diagram") as OxyPlot.Wpf.PlotView;


            Observable.FromEventPattern <RoutedEventHandler, RoutedEventArgs>(h => buttonSave.Click += h, h => buttonSave.Click -= h)
            .WithLatestFrom <EventPattern <RoutedEventArgs>, object, Action>(regressorChanges, (a, b) => (b as ISaveLoad).Save)
            .Subscribe(_ => _.Invoke());

            Observable.FromEventPattern <RoutedEventHandler, RoutedEventArgs>(h => buttonLoad.Click += h, h => buttonLoad.Click -= h)
            .WithLatestFrom <EventPattern <RoutedEventArgs>, object, Action>(regressorChanges, (a, b) => (b as ISaveLoad).Load)
            .Subscribe(_ => _.Invoke());



            if (buttonSaveToCsv != null)
            {
                Observable.FromEventPattern <RoutedEventHandler, RoutedEventArgs>(h => buttonSaveToCsv.Click += h, h => buttonSaveToCsv.Click -= h)
                .WithLatestFrom <EventPattern <RoutedEventArgs>, object, Task <bool> >(trainDataViewChanges, (a, b) => SaveToCsv(dataTable))
                .Subscribe(async _ => await _);
            }

            var xxx = Observable.FromEventPattern <RoutedEventHandler, RoutedEventArgs>(h => sliderItemsControl.ValueChanged += h, h => sliderItemsControl.ValueChanged -= h)
                      .WithLatestFrom(regressorChanges, (a, b) => new Action(() => SliderItemsControl_ValueChanged(a.EventArgs, b)))
                      .Buffer(TimeSpan.FromMilliseconds(100))
                      .ObserveOnDispatcher()
                      .Subscribe(_ => _.LastOrDefault()?.Invoke());


            regressorChanges.CombineLatest(testDataViewChanges, AddPoints).Subscribe(async _ =>
            {
                await _;
            });


            Diagram.Model = CreatePlotModel();
            Diagram.Model.InvalidatePlot(true);


            // sliderItemsControl.ValueChanged +=(a,s SliderItemsControl_ValueChanged;
        }
예제 #7
0
 public static IControl Create <T>(
     ISubject <T> selection,
     IObservable <T> data,
     Func <SelectionState, IControl> control,
     Menu menu,
     Command defaultCommand,
     Text toolTip = default(Text))
 {
     return(control(
                new SelectionState
     {
         IsSelected = selection.CombineLatest(data, (s, d) => s.Equals(d)).Replay(1).RefCount(),
     })
            .WithBackground(Color.AlmostTransparent)
            .OnMouse(
                pressed: data.Switch(selection.Update),
                doubleClicked: defaultCommand)
            .SetContextMenu(menu)
            .SetToolTip(toolTip));
 }
예제 #8
0
        public ObjectControl()
        {
            converterChanges
            .CombineLatest(objectChanges, comparerChanges, textBlockChanges, filterChanges, (valueConverter, value, comparer, textBlock, filter) => (valueConverter, value, comparer, textBlock, filter))
            .Subscribe(valueTuple =>
            {
                var(valueConverter, value, comparer, textBlock, filter) = valueTuple;

                Task.Run(() =>
                         value switch
                {
                    string _ => (Visibility.Collapsed, value),
                    Version _ => (Visibility.Collapsed, value),
                    { } x when x.GetType().IsClass == false => (Visibility.Collapsed, value),
                    null => (Visibility.Collapsed, value),
                    IEnumerable <string> _ => (Visibility.Collapsed, value),
                    IEnumerable enumerable when enumerable.NotOfClassType() => (Visibility.Collapsed, enumerable),
                    IEnumerable enumerable when enumerable.OfSameType() => (Visibility.Collapsed, enumerable),
                    IEnumerable enumerable => DictionaryConverter.ConvertMany(enumerable, valueConverter, filter, comparer)
                    .Pipe(a => (a.Keys.Cast <object>().Any() ? Visibility.Visible : Visibility.Collapsed, a)),
                    _ => DictionaryConverter.Convert(value, valueConverter, filter, comparer)
                    .Pipe(a => (a.Keys.Cast <object>().Any() ? Visibility.Visible : Visibility.Collapsed, a))
                })
                .ToObservable()
                .ObserveOnDispatcher()
                .Subscribe(a =>
                {
                    var(visibility, content) = a;
                    textBlock.SetValue(VisibilityProperty, visibility);
                    this.SetValue(ContentProperty, content);
                }, e =>
                {
                    SetValue(ContentProperty, new OrderedDictionary(1)
                    {
                        { "Error", e.Message }
                    });
                    this.Log().Write(e, $"Error in {nameof(ObjectControl)} creating content", typeof(ObjectControl), LogLevel.Error);
                },
                           () => { });
            });
예제 #9
0
        public PathControl()
        {
            Uri resourceLocater = new Uri("/PathWpf;component/Themes/PathControl.xaml", System.UriKind.Relative);
            ResourceDictionary resourceDictionary = (ResourceDictionary)Application.LoadComponent(resourceLocater);

            Style = resourceDictionary["PathControlStyle"] as Style;



            Random rd = new Random();

            PointChanges
            .CombineLatest(DiameterChanges, SpeedChanges, (a, c, d) =>
            {
                var startPoint = (a as PathGeometry).Figures.First().StartPoint;
                var endPoint   = (a as PathGeometry).Figures.Last().StartPoint;

                byte[] rgb = new byte[] { (byte)rd.Next(0, 255), (byte)rd.Next(0, 255), (byte)rd.Next(0, 255) };

                Path particlePath = PathEllipse.GetPath(startPoint, endPoint, _storyboard, rgb, (a as PathGeometry), 2);

                return(PathEllipse.GetAnimation(startPoint, endPoint, c, a, rgb, _storyboard, 2, m_PointData));
            })
            .Subscribe(_ =>
            {
                foreach (var x in _)
                {
                    try
                    {
                        contentGrid.Children.Add((UIElement)x);
                    }
                    catch (Exception e)
                    {
                    }
                }
                _storyboard.Begin(this);
            });
        }
예제 #10
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ObservableTimer"/> class.
        /// </summary>
        /// <param name="schedulerProvider">The scheduler provider.</param>
        protected ObservableTimer(ISchedulerProvider schedulerProvider)
        {
            _timerEvents
            .Select(x => x is TimerStartEvent)
            .ToProperty(this, nameof(IsRunning), out _isRunning)
            .DisposeWith(Garbage);

            _elapsed =
                _timerEvents
                .CombineLatest(
                    _timerEvents
                    .OfType <TimerStartEvent>()
                    .Select(x => x.Duration),
                    (timerEvent, duration) => (duration, isRunning: timerEvent is TimerStartEvent))
                .Select(
                    x => x.isRunning
                            ? Observable
                    .Interval(TimeSpans.RefreshInterval, schedulerProvider.BackgroundThread)
                    .Scan(x.duration, (duration, _) => Accumulator(duration))
                    .TakeUntil(Elapsed)
                    .Do(elapsed => _resumeTime = elapsed, () => _resumeTime = x.duration)
                            : Observable.Return(_resumeTime))
                .Switch();
        }
예제 #11
0
        public TailViewModel([NotNull] ILogger logger,
                             [NotNull] ISchedulerProvider schedulerProvider,
                             [NotNull] IEnumerable <IFileWatcher> fileWatcher,
                             [NotNull] ISelectionMonitor selectionMonitor,
                             [NotNull] IClipboardHandler clipboardHandler,
                             [NotNull] ISearchInfoCollection searchInfoCollection,
                             [NotNull] IInlineViewerFactory inlineViewerFactory,
                             [NotNull] ISetting <GeneralOptions> generalOptions,
                             [NotNull] ISearchMetadataCollection searchMetadataCollection,
                             [NotNull] SearchOptionsViewModel searchOptionsViewModel,
                             [NotNull] SearchHints searchHints)
        {
            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }
            if (schedulerProvider == null)
            {
                throw new ArgumentNullException(nameof(schedulerProvider));
            }
            if (fileWatcher == null)
            {
                throw new ArgumentNullException(nameof(fileWatcher));
            }
            if (selectionMonitor == null)
            {
                throw new ArgumentNullException(nameof(selectionMonitor));
            }
            if (clipboardHandler == null)
            {
                throw new ArgumentNullException(nameof(clipboardHandler));
            }
            if (searchInfoCollection == null)
            {
                throw new ArgumentNullException(nameof(searchInfoCollection));
            }
            if (inlineViewerFactory == null)
            {
                throw new ArgumentNullException(nameof(inlineViewerFactory));
            }
            if (generalOptions == null)
            {
                throw new ArgumentNullException(nameof(generalOptions));
            }
            if (searchMetadataCollection == null)
            {
                throw new ArgumentNullException(nameof(searchMetadataCollection));
            }
            if (searchOptionsViewModel == null)
            {
                throw new ArgumentNullException(nameof(searchOptionsViewModel));
            }
            if (searchHints == null)
            {
                throw new ArgumentNullException(nameof(searchHints));
            }

            _stateProvider = new TailViewPersister(this);

            var enumerable = fileWatcher as IFileWatcher[] ?? fileWatcher.ToArray();

            Names            = enumerable.Select(t => t.FullName);
            SelectionMonitor = selectionMonitor;
            SearchOptions    = searchOptionsViewModel;
            SearchHints      = searchHints;
            SearchCollection = new SearchCollection(searchInfoCollection, schedulerProvider);

            CopyToClipboardCommand =
                new Command(() => clipboardHandler.WriteToClipboard(selectionMonitor.GetSelectedText()));
            OpenFileCommand   = new Command(() => Process.Start(enumerable[0].FullName));
            OpenFolderCommand = new Command(() => Process.Start(enumerable[0].Folder));

            UsingDarkTheme = generalOptions.Value
                             .ObserveOn(schedulerProvider.MainThread)
                             .Select(options => options.Theme == Theme.Dark)
                             .ForBinding();

            HighlightTail = generalOptions.Value
                            .ObserveOn(schedulerProvider.MainThread)
                            .Select(options => options.HighlightTail)
                            .ForBinding();

            HighlightDuration = generalOptions.Value
                                .ObserveOn(schedulerProvider.MainThread)
                                .Select(options => new Duration(TimeSpan.FromSeconds(options.HighlightDuration)))
                                .ForBinding();

            //An observable which acts as a scroll command
            var autoChanged = this.WhenValueChanged(vm => vm.AutoTail);
            var scroller    = _userScrollRequested.CombineLatest(autoChanged, (user, auto) =>
            {
                var mode = AutoTail ? ScrollReason.Tail : ScrollReason.User;
                return(new ScrollRequest(mode, user.PageSize, user.FirstIndex));
            })
                              .Do(x => logger.Info("Scrolling to {0}/{1}", x.FirstIndex, x.PageSize))
                              .DistinctUntilChanged();

            FileStatus = enumerable
                         .Select(t => t.Status)
                         .Merge()
                         .Scan(default(FileStatus), (status, fileStatus) => status | fileStatus)
                         .ForBinding();

            //command to add the current search to the tail collection
            var searchInvoker =
                SearchHints.SearchRequested.Subscribe(
                    request => { searchInfoCollection.Add(request.Text, request.UseRegEx); });

            //User feedback to show file size
            FileSizeText = enumerable
                           .Select(t => t.Latest)
                           .Merge()
                           .Select(t => t.Size)
                           .Scan(0f, (previousSize, currentSize) => previousSize + currentSize / 2f)
                           .Select(t => ((long)t).FormatWithAbbreviation())
                           .DistinctUntilChanged()
                           .ForBinding();


            //tailer is the main object used to tail, scroll and filter in a file
            var lineScroller = new LineScroller(SearchCollection.Latest.ObserveOn(schedulerProvider.Background),
                                                scroller);

            //load lines into observable collection
            var lineProxyFactory = new LineProxyFactory(new TextFormatter(searchMetadataCollection),
                                                        new LineMatches(searchMetadataCollection));

            var loader = lineScroller.Lines.Connect()
                         .RecordChanges(logger, "Received")
                         .Transform(lineProxyFactory.Create, new ParallelisationOptions(ParallelType.Ordered, 3))
                         .Sort(SortExpressionComparer <LineProxy> .Ascending(proxy => proxy))
                         .ObserveOn(schedulerProvider.MainThread)
                         .Bind(out _data, 100)
                         .DisposeMany()
                         .LogErrors(logger)
                         .Subscribe();


            //monitor matching lines and start index,
            Count = searchInfoCollection.All
                    .GroupBy(t => t)
                    .Select(groupedProvider => groupedProvider.Key.Count)
                    .Scan(0, (i, providerCount) => i + providerCount)
                    .ForBinding();
            CountText = searchInfoCollection.All
                        .GroupBy(t => t)
                        .Select(groupedProvider => groupedProvider.Key.Count)
                        .Scan(0, (i, providerCount) => i + providerCount)
                        .Select(latestCount => $"{latestCount.ToString("##,###")} lines")
                        .ForBinding();
            //iterate over every items to evaluate the lines' count
            LatestCount = SearchCollection.Latest
                          .GroupBy(t => t)
                          .Do(Console.WriteLine)
                          .Scan(0, (acc, provider) =>
            {
                if (provider.Key is IndexCollection && provider.Key.NumberOfPreviousProvider == 0)
                {
                    acc = 0;
                }
                else if (provider.Key is FileSearchResult && provider.Key.NumberOfPreviousProvider == 0)
                {
                    acc = 0;
                }
                return(provider.Key.Count + acc);
            })
                          .ForBinding();

            ////track first visible index
            var firstIndexMonitor = lineScroller.Lines.Connect()
                                    .Buffer(TimeSpan.FromMilliseconds(25)).FlattenBufferResult()
                                    .ToCollection()
                                    .Select(lines => lines.Count == 0 ? 0 : lines.Select(l => l.Index).Max() - lines.Count + 1)
                                    .ObserveOn(schedulerProvider.MainThread)
                                    .Subscribe(first => { FirstIndex = first; });

            //Create objects required for inline viewing
            var isUserDefinedChanged = SearchCollection.WhenValueChanged(sc => sc.Selected)
                                       .Where(selected => selected != null)
                                       .Select(selected => selected.IsUserDefined)
                                       .DistinctUntilChanged()
                                       .Replay(1)
                                       .RefCount();

            var inlineViewerVisible = isUserDefinedChanged.CombineLatest(this.WhenValueChanged(vm => vm.ShowInline),
                                                                         (userDefined, showInline) => userDefined && showInline);

            CanViewInline       = isUserDefinedChanged.ForBinding();
            InlineViewerVisible = inlineViewerVisible.ForBinding();

            //return an empty line provider unless user is viewing inline - this saves needless trips to the file

            var inline = searchInfoCollection.All.CombineLatest(inlineViewerVisible,
                                                                (index, ud) => ud ? index : new EmptyLineProvider());

            var firstVisibleRow = _data.ToObservableChangeSet().ToCollection()
                                  .Select(collection => collection.FirstOrDefault());

            //var itemToSelect = this.WhenValueChanged(vm => vm.SelectedItem)
            //    .CombineLatest(firstVisibleRow, (selected, first) => selected ?? first);
            ////
            InlineViewer = inlineViewerFactory.Create(inline, this.WhenValueChanged(vm => vm.SelectedItem),
                                                      lineProxyFactory);

            _cleanUp = new CompositeDisposable(lineScroller,
                                               loader,
                                               firstIndexMonitor,
                                               FileStatus,
                                               Count,
                                               LatestCount,
                                               FileSizeText,
                                               CanViewInline,
                                               InlineViewer,
                                               InlineViewerVisible,
                                               SearchCollection,
                                               searchInfoCollection,
                                               HighlightTail,
                                               UsingDarkTheme,
                                               searchHints,
                                               searchMetadataCollection,
                                               searchMetadataCollection,
                                               SelectionMonitor,
                                               SearchOptions,
                                               searchInvoker,
                                               _userScrollRequested.SetAsComplete());
        }
예제 #12
0
        public TailViewModel([NotNull] ILogger logger,
                             [NotNull] ISchedulerProvider schedulerProvider,
                             [NotNull] IFileWatcher fileWatcher,
                             [NotNull] ISelectionMonitor selectionMonitor,
                             [NotNull] IClipboardHandler clipboardHandler,
                             [NotNull] ISearchInfoCollection searchInfoCollection,
                             [NotNull] IInlineViewerFactory inlineViewerFactory,
                             [NotNull] GeneralOptionBindings generalOptionBindings,
                             [NotNull] ICombinedSearchMetadataCollection combinedSearchMetadataCollection,
                             [NotNull] IStateBucketService stateBucketService,
                             [NotNull] ITailViewStateRestorer restorer,
                             [NotNull] SearchHints searchHints,
                             [NotNull] ITailViewStateControllerFactory tailViewStateControllerFactory,
                             [NotNull] IThemeProvider themeProvider,
                             [NotNull] SearchCollection searchCollection,
                             [NotNull] ITextFormatter textFormatter,
                             [NotNull] ILineMatches lineMatches,
                             [NotNull] IObjectProvider objectProvider,
                             [NotNull] IDialogCoordinator dialogCoordinator)
        {
            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }
            if (schedulerProvider == null)
            {
                throw new ArgumentNullException(nameof(schedulerProvider));
            }
            if (fileWatcher == null)
            {
                throw new ArgumentNullException(nameof(fileWatcher));
            }
            if (clipboardHandler == null)
            {
                throw new ArgumentNullException(nameof(clipboardHandler));
            }
            if (searchInfoCollection == null)
            {
                throw new ArgumentNullException(nameof(searchInfoCollection));
            }
            if (inlineViewerFactory == null)
            {
                throw new ArgumentNullException(nameof(inlineViewerFactory));
            }
            if (stateBucketService == null)
            {
                throw new ArgumentNullException(nameof(stateBucketService));
            }
            if (themeProvider == null)
            {
                throw new ArgumentNullException(nameof(themeProvider));
            }
            if (textFormatter == null)
            {
                throw new ArgumentNullException(nameof(textFormatter));
            }
            if (lineMatches == null)
            {
                throw new ArgumentNullException(nameof(lineMatches));
            }
            if (objectProvider == null)
            {
                throw new ArgumentNullException(nameof(objectProvider));
            }
            if (dialogCoordinator == null)
            {
                throw new ArgumentNullException(nameof(dialogCoordinator));
            }
            if (combinedSearchMetadataCollection == null)
            {
                throw new ArgumentNullException(nameof(combinedSearchMetadataCollection));
            }

            Name                  = fileWatcher.FullName;
            SelectionMonitor      = selectionMonitor ?? throw new ArgumentNullException(nameof(selectionMonitor));
            GeneralOptionBindings = generalOptionBindings;
            SearchHints           = searchHints ?? throw new ArgumentNullException(nameof(searchHints));

            CopyToClipboardCommand     = new Command(() => clipboardHandler.WriteToClipboard(selectionMonitor.GetSelectedText()));
            OpenFileCommand            = new Command(() => Process.Start(fileWatcher.FullName));
            OpenFolderCommand          = new Command(() => Process.Start(fileWatcher.Folder));
            CopyPathToClipboardCommand = new Command(() => clipboardHandler.WriteToClipboard(fileWatcher.FullName));
            UnClearCommand             = new Command(fileWatcher.Reset);
            ClearCommand             = new Command(fileWatcher.Clear);
            KeyAutoTail              = new Command(() => { AutoTail = true; });
            OpenSearchOptionsCommand = new Command(async() =>
            {
                await Task.Run(() =>
                {
                    var content = objectProvider.Get <SearchOptionsViewModel>(new Argument <ICombinedSearchMetadataCollection>(combinedSearchMetadataCollection));
                    dialogCoordinator.Show(this, content, x => content.Dispose());
                });
            });

            var closeOnDeselect = this.WhenValueChanged(vm => vm.IsSelected, false)
                                  .Where(selected => !selected)
                                  .Subscribe(_ => dialogCoordinator.Close());

            SearchCollection         = searchCollection ?? throw new ArgumentNullException(nameof(searchCollection));
            SearchMetadataCollection = combinedSearchMetadataCollection.Local;

            var horizonalScrollArgs = new ReplaySubject <TextScrollInfo>(1);

            HorizonalScrollChanged = args => horizonalScrollArgs.OnNext(args);

            _tailViewStateControllerFactory = tailViewStateControllerFactory;

            //this deals with state when loading the system at start up and at shut-down
            _persister = new TailViewPersister(this, restorer);

            FileStatus = fileWatcher.Status.ForBinding();

            //command to add the current search to the tail collection
            var searchInvoker = SearchHints.SearchRequested.Subscribe(request => searchInfoCollection.Add(request.Text, request.UseRegEx));

            //An observable which acts as a scroll command
            var autoChanged = this.WhenValueChanged(vm => vm.AutoTail);
            var scroller    = _userScrollRequested.CombineLatest(autoChanged, (user, auto) =>
            {
                var mode = AutoTail ? ScrollReason.Tail : ScrollReason.User;
                return(new ScrollRequest(mode, user.PageSize, user.FirstIndex));
            })
                              .Do(x => logger.Info("Scrolling to {0}/{1}", x.FirstIndex, x.PageSize))
                              .DistinctUntilChanged();

            //User feedback to show file size
            FileSizeText = fileWatcher.Latest.Select(fn => fn.Size)
                           .Select(size => size.FormatWithAbbreviation())
                           .DistinctUntilChanged()
                           .ForBinding();


            //tailer is the main object used to tail, scroll and filter in a file
            var selectedProvider = SearchCollection.Latest.ObserveOn(schedulerProvider.Background);

            var lineScroller = new LineScroller(selectedProvider, scroller);

            MaximumChars = lineScroller.MaximumLines()
                           .ObserveOn(schedulerProvider.MainThread)
                           .ForBinding();

            var lineProxyFactory = new LineProxyFactory(textFormatter, lineMatches, horizonalScrollArgs.DistinctUntilChanged(), themeProvider);

            var loader = lineScroller.Lines.Connect()
                         .LogChanges(logger, "Received")
                         .Transform(lineProxyFactory.Create)
                         .LogChanges(logger, "Sorting")
                         .Sort(SortExpressionComparer <LineProxy> .Ascending(proxy => proxy))
                         .ObserveOn(schedulerProvider.MainThread)
                         .Bind(out _data, 100)
                         .LogChanges(logger, "Bound")
                         .DisposeMany()
                         .LogErrors(logger)
                         .Subscribe();

            //monitor matching lines and start index,
            Count       = searchInfoCollection.All.Select(latest => latest.Count).ForBinding();
            CountText   = searchInfoCollection.All.Select(latest => $"{latest.Count:##,###} lines").ForBinding();
            LatestCount = SearchCollection.Latest.Select(latest => latest.Count).ForBinding();

            ////track first visible index
            var firstIndexMonitor = lineScroller.Lines.Connect()
                                    .Buffer(TimeSpan.FromMilliseconds(25)).FlattenBufferResult()
                                    .ToCollection()
                                    .Select(lines => lines.Count == 0 ? 0 : lines.Select(l => l.Index).Max() - lines.Count + 1)
                                    .ObserveOn(schedulerProvider.MainThread)
                                    .Subscribe(first =>
            {
                FirstIndex = first;
            });

            //Create objects required for inline viewing
            var isUserDefinedChanged = SearchCollection.WhenValueChanged(sc => sc.Selected)
                                       .Where(selected => selected != null)
                                       .Select(selected => selected.IsUserDefined)
                                       .DistinctUntilChanged()
                                       .Replay(1)
                                       .RefCount();

            var showInline          = this.WhenValueChanged(vm => vm.ShowInline);
            var inlineViewerVisible = isUserDefinedChanged.CombineLatest(showInline, (userDefined, showInlne) => userDefined && showInlne);

            CanViewInline       = isUserDefinedChanged.ForBinding();
            InlineViewerVisible = inlineViewerVisible.ForBinding();

            //return an empty line provider unless user is viewing inline - this saves needless trips to the file
            var inline = searchInfoCollection.All.CombineLatest(inlineViewerVisible, (index, ud) => ud ? index : EmptyLineProvider.Instance);

            InlineViewer = inlineViewerFactory.Create(combinedSearchMetadataCollection, inline, this.WhenValueChanged(vm => vm.SelectedItem));

            _cleanUp = new CompositeDisposable(lineScroller,
                                               loader,
                                               firstIndexMonitor,
                                               FileStatus,
                                               Count,
                                               CountText,
                                               LatestCount,
                                               FileSizeText,
                                               CanViewInline,
                                               InlineViewer,
                                               InlineViewerVisible,
                                               SearchCollection,
                                               searchInfoCollection,
                                               searchHints,
                                               SelectionMonitor,
                                               closeOnDeselect,
                                               Disposable.Create(dialogCoordinator.Close),
                                               searchInvoker,
                                               MaximumChars,
                                               _stateMonitor,
                                               combinedSearchMetadataCollection,
                                               horizonalScrollArgs.SetAsComplete(),
                                               _userScrollRequested.SetAsComplete());
        }
예제 #13
0
        public FileTailerViewModel([NotNull] ILogger logger,
                                   [NotNull] ISchedulerProvider schedulerProvider,
                                   [NotNull] IFileWatcher fileWatcher,
                                   [NotNull] ISelectionMonitor selectionMonitor,
                                   [NotNull] IClipboardHandler clipboardHandler,
                                   [NotNull] ISearchInfoCollection searchInfoCollection,
                                   [NotNull] IInlineViewerFactory inlineViewerFactory,
                                   [NotNull] ISetting <GeneralOptions> generalOptions,
                                   [NotNull] IRecentSearchCollection recentSearchCollection,
                                   [NotNull] SearchHints searchHints)
        {
            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }
            if (schedulerProvider == null)
            {
                throw new ArgumentNullException(nameof(schedulerProvider));
            }
            if (fileWatcher == null)
            {
                throw new ArgumentNullException(nameof(fileWatcher));
            }
            if (selectionMonitor == null)
            {
                throw new ArgumentNullException(nameof(selectionMonitor));
            }
            if (clipboardHandler == null)
            {
                throw new ArgumentNullException(nameof(clipboardHandler));
            }
            if (searchInfoCollection == null)
            {
                throw new ArgumentNullException(nameof(searchInfoCollection));
            }
            if (inlineViewerFactory == null)
            {
                throw new ArgumentNullException(nameof(inlineViewerFactory));
            }
            if (generalOptions == null)
            {
                throw new ArgumentNullException(nameof(generalOptions));
            }
            if (searchHints == null)
            {
                throw new ArgumentNullException(nameof(searchHints));
            }

            SelectionMonitor       = selectionMonitor;
            SearchHints            = searchHints;
            CopyToClipboardCommand = new Command(() => clipboardHandler.WriteToClipboard(selectionMonitor.GetSelectedText()));
            SelectedItemsCount     = selectionMonitor.Selected.Connect().QueryWhenChanged(collection => collection.Count).ForBinding();
            SearchCollection       = new SearchCollection(searchInfoCollection, schedulerProvider);

            UsingDarkTheme = generalOptions.Value
                             .ObserveOn(schedulerProvider.MainThread)
                             .Select(options => options.Theme == Theme.Dark)
                             .ForBinding();

            HighlightTail = generalOptions.Value
                            .ObserveOn(schedulerProvider.MainThread)
                            .Select(options => options.HighlightTail)
                            .ForBinding();

            HighlightDuration = generalOptions.Value
                                .ObserveOn(schedulerProvider.MainThread)
                                .Select(options => new Duration(TimeSpan.FromSeconds(options.HighlightDuration)))
                                .ForBinding();

            //An observable which acts as a scroll command
            var autoChanged = this.WhenValueChanged(vm => vm.AutoTail);
            var scroller    = _userScrollRequested.CombineLatest(autoChanged, (user, auto) =>
            {
                var mode = AutoTail ? ScrollReason.Tail : ScrollReason.User;
                return(new ScrollRequest(mode, user.PageSize, user.FirstIndex));
            })
                              .ObserveOn(schedulerProvider.Background)
                              .DistinctUntilChanged();

            //tailer is the main object used to tail, scroll and filter in a file
            var lineScroller = new LineScroller(SearchCollection.Latest.ObserveOn(schedulerProvider.Background), scroller);

            //Add a complete file display [No search info here]
            var indexed = fileWatcher.Latest.Index()
                          .Replay(1).RefCount();

            IsLoading = indexed.Take(1).Select(_ => false).StartWith(true).ForBinding();
            searchInfoCollection.Add("<All>", indexed, SearchType.All);

            //command to add the current search to the tail collection
            KeepSearchCommand = new Command(() =>
            {
                var text   = SearchHints.SearchText;
                var latest = fileWatcher.Latest
                             .Search(s => s.Contains(text, StringComparison.OrdinalIgnoreCase))
                             .Replay(1).RefCount();

                searchInfoCollection.Add(text, latest);
                recentSearchCollection.Add(new RecentSearch(text));
                SearchHints.SearchText = string.Empty;
            }, () => SearchHints.SearchText.IsLongerThanOrEqualTo(3));

            //User feedback to show file size
            FileSizeText = fileWatcher.Latest.Select(fn => fn.Size)
                           .Select(size => size.FormatWithAbbreviation())
                           .DistinctUntilChanged()
                           .ForBinding();

            //User feedback to guide them whilst typing
            SearchHint = this.WhenValueChanged(vm => vm.SearchHints.SearchText)
                         .Select(text =>
            {
                if (string.IsNullOrEmpty(text))
                {
                    return("Type to search");
                }
                return(text.Length < 3 ? "Enter at least 3 characters" : "Hit enter to search");
            }).ForBinding();

            //load lines into observable collection
            var lineProxyFactory = new LineProxyFactory(new TextFormatter(searchInfoCollection));
            var loader           = lineScroller.Lines.Connect()
                                   .Transform(lineProxyFactory.Create, new ParallelisationOptions(ParallelType.Ordered, 5))
                                   .Sort(SortExpressionComparer <LineProxy> .Ascending(proxy => proxy))
                                   .ObserveOn(schedulerProvider.MainThread)
                                   .Bind(out _data)
                                   .DisposeMany()
                                   .Subscribe(changes => logger.Info($"Rows changed. {changes.Adds} adds, {changes.Removes} removed"),
                                              ex => logger.Error(ex, "There is a problem with bind data"));

            //monitor matching lines and start index,
            Count       = indexed.Select(latest => latest.Count).ForBinding();
            CountText   = indexed.Select(latest => $"{latest.Count.ToString("##,###")} lines").ForBinding();
            LatestCount = SearchCollection.Latest.Select(latest => latest.Count).ForBinding();

            //track first visible index
            var firstIndexMonitor = lineScroller.Lines.Connect()
                                    .Buffer(TimeSpan.FromMilliseconds(250)).FlattenBufferResult()
                                    .ToCollection()
                                    .Select(lines => lines.Count == 0 ? 0 : lines.Select(l => l.Index).Max() - lines.Count + 1)
                                    .ObserveOn(schedulerProvider.MainThread)
                                    .Subscribe(first => FirstIndex = first);

            //Create objects required for inline viewing
            var isUserDefinedChanged = SearchCollection.WhenValueChanged(sc => sc.Selected)
                                       .Select(selected => selected.IsUserDefined)
                                       .DistinctUntilChanged();

            var inlineViewerVisible = isUserDefinedChanged.CombineLatest(this.WhenValueChanged(vm => vm.ShowInline),
                                                                         (userDefined, showInline) => userDefined && showInline);

            CanViewInline       = isUserDefinedChanged.ForBinding();
            InlineViewerVisible = inlineViewerVisible.ForBinding();

            //return an empty line provider unless user is viewing inline - this saves needless trips to the file
            var inline = indexed.CombineLatest(inlineViewerVisible, (index, ud) => ud ? index : new EmptyLineProvider());

            InlineViewer = inlineViewerFactory.Create(inline, this.WhenValueChanged(vm => vm.SelectedItem), lineProxyFactory);

            _cleanUp = new CompositeDisposable(lineScroller,
                                               loader,
                                               firstIndexMonitor,
                                               IsLoading,
                                               Count,
                                               LatestCount,
                                               FileSizeText,
                                               SearchHint,
                                               SelectedItemsCount,
                                               CanViewInline,
                                               InlineViewer,
                                               InlineViewerVisible,
                                               SearchCollection,
                                               searchInfoCollection,
                                               HighlightTail,
                                               UsingDarkTheme,
                                               searchHints,
                                               Disposable.Create(() =>
            {
                _userScrollRequested.OnCompleted();
                SelectionMonitor?.Dispose();
            }));
        }
예제 #14
0
        public FileTailerViewModel(ILogger logger, ISchedulerProvider schedulerProvider, FileInfo fileInfo)
        {
            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }
            if (schedulerProvider == null)
            {
                throw new ArgumentNullException(nameof(schedulerProvider));
            }
            if (fileInfo == null)
            {
                throw new ArgumentNullException(nameof(fileInfo));
            }

            var filterRequest = this.WhenValueChanged(vm => vm.SearchText).Throttle(TimeSpan.FromMilliseconds(125));
            var autoChanged   = this.WhenValueChanged(vm => vm.AutoTail);
            var scroller      = _userScrollRequested
                                .CombineLatest(autoChanged, (user, auto) =>
            {
                var mode = AutoTail ? ScrollingMode.Tail : ScrollingMode.User;
                return(new ScrollRequest(mode, user.PageSize, user.FirstIndex));
            })
                                .Sample(TimeSpan.FromMilliseconds(150))
                                .DistinctUntilChanged();

            var tailer = new FileTailer(fileInfo, filterRequest, scroller);


            //create user display for count line count
            var lineCounter = tailer.TotalLines.CombineLatest(tailer.MatchedLines, (total, matched) =>
            {
                return(total == matched
                    ? $"File has {total.ToString("#,###")} lines"
                    : $"Showing {matched.ToString("#,###")} of {total.ToString("#,###")} lines");
            })
                              .Subscribe(text => LineCountText = text);


            //load lines into observable collection
            var loader = tailer.Lines.Connect()
                         .Transform(line => new LineProxy(line))
                         .Sort(SortExpressionComparer <LineProxy> .Ascending(proxy => proxy.Number))
                         .ObserveOn(schedulerProvider.MainThread)
                         .Bind(out _data)
                         .Subscribe(changes => logger.Info($"Rows changed {changes.Adds} adds, {changes.Removes} removed"),
                                    ex => logger.Error(ex, "There is a problem with bind data"));


            //monitor matching lines and start index,
            var matchedLinesMonitor = tailer.MatchedLines
                                      .Subscribe(matched => MatchedLineCount = matched);

            //track first visible index
            var firstIndexMonitor = tailer.Lines.Connect()
                                    .QueryWhenChanged(lines => lines.Count == 0 ? 0 : lines.Select(l => l.Index).Min())
                                    .Subscribe(first => FirstIndex = first);


            _cleanUp = new CompositeDisposable(tailer,
                                               lineCounter,
                                               loader,
                                               firstIndexMonitor,
                                               matchedLinesMonitor,
                                               Disposable.Create(() =>
            {
                _userScrollRequested.OnCompleted();
            }));
        }
예제 #15
0
 public DateTimeControl()
 {
     startChanges.CombineLatest(endChanges, (s, e) => new { s, e }).Subscribe(_ =>
     {
     });
 }
예제 #16
0
        public MasterDetailView()
        {
            var outputChanges = SelectChanges(nameof(Output)).Where(obj => obj != null);

            //Dictionary<Type, object> dict = new Dictionary<Type, object>();
            outputChanges
            .CombineLatest(SelectChanges <string>(nameof(Id)).StartWith(Id), (a, b) => (a, b))
            .Select(vm =>
            {
                var id = vm.a.GetType().GetProperty(vm.b).GetValue(vm.a).ToString();
                return(id);
            }).Subscribe(NameChanges);

            outputChanges
            .CombineLatest(SelectChanges <IValueConverter>(nameof(DataConverter)).StartWith(default(IValueConverter)), (a, b) => (a, b))
            .SubscribeOn(TaskPoolScheduler.Default)
            .ObserveOnDispatcher()
            .Subscribe(collConv => Dispatcher.InvokeAsync(() =>
            {
                Convert(collConv.a, collConv.b, (items, conv) => conv.Convert(collConv.a, null, null, null) as IEnumerable);
            }, DispatcherPriority.Normal));

            SelectChanges <PropertyGroupDescription>().StartWith(PropertyGroupDescription)
            .CombineLatest(ControlChanges.Where(c => c.GetType() == typeof(DockPanel)).Take(1), (pgd, DockPanel) => (pgd, DockPanel)).Subscribe(_ =>
            {
                if ((_.DockPanel as DockPanel)?.FindResource("GroupedItems") is CollectionViewSource collectionViewSource)
                {
                    collectionViewSource.GroupDescriptions.Add(_.pgd);
                }
            });

            GroupClick = new Command.RelayCommand <string>(a => GroupNameChanges.OnNext(a));

            NameChanges
            .Merge(GroupNameChanges)
            .CombineLatest(ControlChanges.Select(c => c as TextBlock).Where(c => c != null),

                           (text, textBlock) => (text, textBlock))
            .ObserveOnDispatcher()
            .Subscribe(input =>
            {
                input.textBlock.Text       = input.text;
                input.textBlock.Visibility = Visibility.Visible;
                input.textBlock.IsEnabled  = true;
                input.textBlock.IsEnabled  = false;
            });

            GroupNameChanges.CombineLatest(
                SelectChanges <PropertyGroupDescription>().StartWith(PropertyGroupDescription),
                SelectChanges <IValueConverter>(nameof(DataConverter)).StartWith(default(IValueConverter)),
                SelectChanges <string>(nameof(Id)).StartWith(Id),
                (text, pg, conv, id) => (text, pg, conv, id))
            //.ObserveOn(TaskPoolScheduler.Default)
            .Subscribe(async input =>
            {
                await Dispatcher.InvokeAsync(() =>
                {
                    var paths = Items.Cast <object>();
                    var prop  = paths.First().GetType().GetProperty(input.pg.PropertyName);

                    // property-group-converter
                    var converter = input.pg.Converter;

                    var group = paths.Where(ad =>
                    {
                        bool result = converter != default ?
                                      input.text
                                      .Equals(converter.Convert(prop.GetValue(ad), null, null, null)) :
                                      input.text
                                      .Equals(prop.GetValue(ad));
                        return(result);
                    })
                                .Select(viewmodel =>
                                        new Property.KeyValue(
                                            viewmodel.GetType().GetProperty(input.id).GetValue(viewmodel).ToString(),
                                            viewmodel));
                    Convert(group, input.conv, (items, conv) => conv.Convert(items, null, null, null));
                }, DispatcherPriority.Background);
            });

            ContentTemplateSelector = new PropertyDataTemplateSelector();
        }
예제 #17
0
        public TailViewModel([NotNull] ILogger logger,
                             [NotNull] ISchedulerProvider schedulerProvider,
                             [NotNull] IFileWatcher fileWatcher,
                             [NotNull] ISelectionMonitor selectionMonitor,
                             [NotNull] IClipboardHandler clipboardHandler,
                             [NotNull] ISearchInfoCollection searchInfoCollection,
                             [NotNull] IInlineViewerFactory inlineViewerFactory,
                             [NotNull] ISetting <GeneralOptions> generalOptions,
                             [NotNull] ISearchMetadataCollection searchMetadataCollection,
                             [NotNull] IStateBucketService stateBucketService,
                             [NotNull] SearchOptionsViewModel searchOptionsViewModel,
                             [NotNull] ITailViewStateRestorer restorer,
                             [NotNull] SearchHints searchHints,
                             [NotNull] ITailViewStateControllerFactory tailViewStateControllerFactory)
        {
            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }
            if (schedulerProvider == null)
            {
                throw new ArgumentNullException(nameof(schedulerProvider));
            }
            if (fileWatcher == null)
            {
                throw new ArgumentNullException(nameof(fileWatcher));
            }
            if (selectionMonitor == null)
            {
                throw new ArgumentNullException(nameof(selectionMonitor));
            }
            if (clipboardHandler == null)
            {
                throw new ArgumentNullException(nameof(clipboardHandler));
            }
            if (searchInfoCollection == null)
            {
                throw new ArgumentNullException(nameof(searchInfoCollection));
            }
            if (inlineViewerFactory == null)
            {
                throw new ArgumentNullException(nameof(inlineViewerFactory));
            }
            if (generalOptions == null)
            {
                throw new ArgumentNullException(nameof(generalOptions));
            }
            if (searchMetadataCollection == null)
            {
                throw new ArgumentNullException(nameof(searchMetadataCollection));
            }
            if (stateBucketService == null)
            {
                throw new ArgumentNullException(nameof(stateBucketService));
            }
            if (searchOptionsViewModel == null)
            {
                throw new ArgumentNullException(nameof(searchOptionsViewModel));
            }
            if (searchHints == null)
            {
                throw new ArgumentNullException(nameof(searchHints));
            }

            Name                     = fileWatcher.FullName;
            SelectionMonitor         = selectionMonitor;
            SearchOptions            = searchOptionsViewModel;
            SearchHints              = searchHints;
            SearchCollection         = new SearchCollection(searchInfoCollection, schedulerProvider);
            CopyToClipboardCommand   = new Command(() => clipboardHandler.WriteToClipboard(selectionMonitor.GetSelectedText()));
            OpenFileCommand          = new Command(() => Process.Start(fileWatcher.FullName));
            OpenFolderCommand        = new Command(() => Process.Start(fileWatcher.Folder));
            SearchMetadataCollection = searchMetadataCollection;

            var horizonalScrollArgs = new ReplaySubject <TextScrollInfo>(1);

            HorizonalScrollChanged = args =>
            {
                horizonalScrollArgs.OnNext(args);
            };

            _tailViewStateControllerFactory = tailViewStateControllerFactory;

            //Move these 2 highlight fields to a service as all views require them
            UsingDarkTheme = generalOptions.Value
                             .ObserveOn(schedulerProvider.MainThread)
                             .Select(options => options.Theme == Theme.Dark)
                             .ForBinding();

            HighlightTail = generalOptions.Value
                            .ObserveOn(schedulerProvider.MainThread)
                            .Select(options => options.HighlightTail)
                            .ForBinding();

            //this deals with state when loading the system at start up and at shut-down
            _persister = new TailViewPersister(this, restorer);

            //An observable which acts as a scroll command
            var autoChanged = this.WhenValueChanged(vm => vm.AutoTail);
            var scroller    = _userScrollRequested.CombineLatest(autoChanged, (user, auto) =>
            {
                var mode = AutoTail ? ScrollReason.Tail : ScrollReason.User;
                return(new ScrollRequest(mode, user.PageSize, user.FirstIndex));
            })
                              .Do(x => logger.Info("Scrolling to {0}/{1}", x.FirstIndex, x.PageSize))
                              .DistinctUntilChanged();

            FileStatus = fileWatcher.Status.ForBinding();

            //command to add the current search to the tail collection
            var searchInvoker = SearchHints.SearchRequested.Subscribe(request =>
            {
                searchInfoCollection.Add(request.Text, request.UseRegEx);
            });

            //User feedback to show file size
            FileSizeText = fileWatcher.Latest.Select(fn => fn.Size)
                           .Select(size => size.FormatWithAbbreviation())
                           .DistinctUntilChanged()
                           .ForBinding();

            //tailer is the main object used to tail, scroll and filter in a file
            var lineScroller = new LineScroller(SearchCollection.Latest.ObserveOn(schedulerProvider.Background), scroller);

            MaximumChars = lineScroller.MaximumLines()
                           .ObserveOn(schedulerProvider.MainThread)
                           .ForBinding();

            //load lines into observable collection
            var lineProxyFactory = new LineProxyFactory(new TextFormatter(searchMetadataCollection), new LineMatches(searchMetadataCollection), horizonalScrollArgs.DistinctUntilChanged());

            var loader = lineScroller.Lines.Connect()
                         .LogChanges(logger, "Received")
                         .Transform(lineProxyFactory.Create, new ParallelisationOptions(ParallelType.Ordered, 3))
                         .LogChanges(logger, "Sorting")
                         .Sort(SortExpressionComparer <LineProxy> .Ascending(proxy => proxy))
                         .ObserveOn(schedulerProvider.MainThread)
                         .Bind(out _data, 100)
                         .LogChanges(logger, "Bound")
                         .DisposeMany()
                         .LogErrors(logger)
                         .Subscribe();

            //monitor matching lines and start index,
            Count       = searchInfoCollection.All.Select(latest => latest.Count).ForBinding();
            CountText   = searchInfoCollection.All.Select(latest => $"{latest.Count.ToString("##,###")} lines").ForBinding();
            LatestCount = SearchCollection.Latest.Select(latest => latest.Count).ForBinding();

            ////track first visible index
            var firstIndexMonitor = lineScroller.Lines.Connect()
                                    .Buffer(TimeSpan.FromMilliseconds(25)).FlattenBufferResult()
                                    .ToCollection()
                                    .Select(lines => lines.Count == 0 ? 0 : lines.Select(l => l.Index).Max() - lines.Count + 1)
                                    .ObserveOn(schedulerProvider.MainThread)
                                    .Subscribe(first =>
            {
                FirstIndex = first;
            });


            //Create objects required for inline viewing
            var isUserDefinedChanged = SearchCollection.WhenValueChanged(sc => sc.Selected)
                                       .Where(selected => selected != null)
                                       .Select(selected => selected.IsUserDefined)
                                       .DistinctUntilChanged()
                                       .Replay(1)
                                       .RefCount();

            var inlineViewerVisible = isUserDefinedChanged.CombineLatest(this.WhenValueChanged(vm => vm.ShowInline),
                                                                         (userDefined, showInline) => userDefined && showInline);

            CanViewInline       = isUserDefinedChanged.ForBinding();
            InlineViewerVisible = inlineViewerVisible.ForBinding();

            //return an empty line provider unless user is viewing inline - this saves needless trips to the file
            var inline = searchInfoCollection.All.CombineLatest(inlineViewerVisible, (index, ud) => ud ? index : new EmptyLineProvider());

            InlineViewer = inlineViewerFactory.Create(inline, this.WhenValueChanged(vm => vm.SelectedItem), searchMetadataCollection);

            _cleanUp = new CompositeDisposable(lineScroller,
                                               loader,
                                               firstIndexMonitor,
                                               FileStatus,
                                               Count,
                                               LatestCount,
                                               FileSizeText,
                                               CanViewInline,
                                               InlineViewer,
                                               InlineViewerVisible,
                                               SearchCollection,
                                               searchInfoCollection,
                                               HighlightTail,
                                               UsingDarkTheme,
                                               searchHints,
                                               searchMetadataCollection,
                                               SelectionMonitor,
                                               SearchOptions,
                                               searchInvoker,
                                               MaximumChars,
                                               _stateMonitor,
                                               horizonalScrollArgs.SetAsComplete(),
                                               _userScrollRequested.SetAsComplete());
        }
예제 #18
0
        public ReportsViewModel(ITogglDataSource dataSource,
                                ITimeService timeService,
                                INavigationService navigationService,
                                IInteractorFactory interactorFactory,
                                IAnalyticsService analyticsService,
                                ISchedulerProvider schedulerProvider,
                                IRxActionFactory rxActionFactory)
            : base(navigationService)
        {
            Ensure.Argument.IsNotNull(dataSource, nameof(dataSource));
            Ensure.Argument.IsNotNull(timeService, nameof(timeService));
            Ensure.Argument.IsNotNull(rxActionFactory, nameof(rxActionFactory));
            Ensure.Argument.IsNotNull(analyticsService, nameof(analyticsService));
            Ensure.Argument.IsNotNull(interactorFactory, nameof(interactorFactory));
            Ensure.Argument.IsNotNull(schedulerProvider, nameof(schedulerProvider));
            Ensure.Argument.IsNotNull(navigationService, nameof(navigationService));

            this.dataSource        = dataSource;
            this.timeService       = timeService;
            this.analyticsService  = analyticsService;
            this.interactorFactory = interactorFactory;

            CalendarViewModel = new ReportsCalendarViewModel(timeService, dataSource, rxActionFactory, navigationService);

            var totalsObservable = reportSubject
                                   .SelectMany(_ => interactorFactory.GetReportsTotals(userId, workspaceId, startDate, endDate).Execute())
                                   .Catch <ITimeEntriesTotals, OfflineException>(_ => Observable.Return <ITimeEntriesTotals>(null))
                                   .Where(report => report != null);

            BarChartViewModel = new ReportsBarChartViewModel(schedulerProvider, dataSource.Preferences, totalsObservable, navigationService);

            IsLoadingObservable = isLoading.AsObservable().StartWith(true).AsDriver(schedulerProvider);
            StartDate           = startDateSubject.AsObservable().AsDriver(schedulerProvider);
            EndDate             = endDateSubject.AsObservable().AsDriver(schedulerProvider);

            SelectWorkspace = rxActionFactory.FromAsync(selectWorkspace);

            WorkspaceNameObservable = workspaceSubject
                                      .Select(workspace => workspace?.Name ?? string.Empty)
                                      .DistinctUntilChanged()
                                      .AsDriver(schedulerProvider);

            WorkspaceHasBillableFeatureEnabled = workspaceSubject
                                                 .Where(workspace => workspace != null)
                                                 .SelectMany(workspace => interactorFactory.GetWorkspaceFeaturesById(workspace.Id).Execute())
                                                 .Select(workspaceFeatures => workspaceFeatures.IsEnabled(WorkspaceFeatureId.Pro))
                                                 .StartWith(false)
                                                 .DistinctUntilChanged()
                                                 .AsDriver(schedulerProvider);

            CurrentDateRange = currentDateRangeStringSubject
                               .Select(text => !string.IsNullOrEmpty(text) ? $"{text} ▾" : "")
                               .DistinctUntilChanged()
                               .AsDriver(schedulerProvider);

            WorkspacesObservable = interactorFactory.ObserveAllWorkspaces().Execute()
                                   .Select(list => list.Where(w => !w.IsInaccessible))
                                   .Select(readOnlyWorkspaceSelectOptions)
                                   .AsDriver(schedulerProvider);

            DurationFormatObservable = dataSource.Preferences.Current
                                       .Select(prefs => prefs.DurationFormat)
                                       .AsDriver(schedulerProvider);

            SegmentsObservable        = segmentsSubject.CombineLatest(DurationFormatObservable, applyDurationFormat);
            GroupedSegmentsObservable = SegmentsObservable.CombineLatest(DurationFormatObservable, groupSegments);
            ShowEmptyStateObservable  = SegmentsObservable.CombineLatest(IsLoadingObservable, shouldShowEmptyState);
        }