public ServiceHostEventListener(IQueryDispatcher queryDispatcher, IOptions <ServiceHostEventListenerOptions>?options, ILogger <ServiceHostEventListener>?logger)
        {
            _queryDispatcher = queryDispatcher ?? throw new ArgumentNullException(nameof(queryDispatcher));
            _logger          = logger ?? (ILogger)NullLogger.Instance;

            var optionsValue = options?.Value;

            _delayOnDropout = optionsValue?.DelayOnDropout ?? ServiceHostEventListenerOptions.DefaultDelayOnDropout;

            _isActiveSubject = new BehaviorSubject <bool>(true);

            IsActive = _isActiveSubject
                       .StartWith(true)
                       .DistinctUntilChanged();

            var events = Observable
                         .Create <Event>(observer =>
            {
                var query = new StreamBusEventsQuery
                {
                    OnEvent = (_, @event) => observer.OnNext(@event)
                };

                return(Observable
                       .FromAsync(async ct =>
                {
                    await _queryDispatcher.DispatchAsync(query, ct).ConfigureAwait(false);
                    throw new InvalidOperationException($"{nameof(StreamBusEventsQuery)} returned unexpectedly.");
                })
                       .Subscribe(Noop <Unit> .Action, observer.OnError));
            })
                         .Do(OnEventReceived, OnStreamError)
                         .Retry(wrapSubsequent: source => source.DelaySubscription(_delayOnDropout))
                         // when subject completes, event stream should complete as well
                         .TakeUntil(_isActiveSubject.Where(_ => false).Materialize())
                         .Publish();

            _events = events.AsObservable();

            // no need to explicitly disconnect in Dispose because of TakeUntil
            events.Connect();
        }
Beispiel #2
0
        protected override void Start()
        {
            var rectTransform = ((RectTransform)transform);
            var topMiddle     = new Vector2(0.5f, 1);

            rectTransform.anchorMin = topMiddle;
            rectTransform.anchorMax = topMiddle;
            Tweener tween = null;

            var dragging = false;

            m_Record
            .StartWith(new Record())
            .Pairwise()
            .Where(record => IsValid() && record.Current.piece != null)
            .Subscribe(pair =>
            {
                // TODO: Handle a client simulated record somehow special
                var value     = pair.Current;
                var previous  = pair.Previous;
                var thisStyle = m_Styles.First(style =>
                                               style.playerId == value.piece.playerId && style.pieceType == value.piece.pieceType);
                m_Image.sprite = thisStyle.sprite;
                m_Image.SetNativeSize();
                tween?.Kill();
                tween = rectTransform.DOAnchorPos(m_BoardView.GetPieceCenterFromTop(value.piece.position),
                                                  m_TweenDuration);
            })
            .AddTo(this);


            // Handle dragging and dropping
            this.OnBeginDragAsObservable()
            .Subscribe(pointer =>
            {
                dragging = true;
            }).AddTo(this);

            Observable.EveryUpdate()
            .Where(ignored => dragging)
            .Subscribe(ignore =>
            {
                var pointer            = ContinuousStandaloneInputModule.instance.pointerEventData;
                rectTransform.position = pointer.position;
            })
            .AddTo(this);

            this.OnEndDragAsObservable()
            .Subscribe(pointer =>
            {
                dragging        = false;
                var destination = m_BoardView.GetClosestIndexToPointer(pointer);
                if (destination == -1)
                {
                    // Not a valid destination, refresh the record to return to the source location.
                    m_Record.OnNext(m_Record.Value);
                    return;
                }

                var currentPieceRecord = pieceState;
                // Eagerly assume the move succeeded
                m_Record.OnNext(new Record()
                {
                    id    = m_Record.Value.id,
                    piece = new Piece()
                    {
                        pieceType = m_Record.Value.piece.pieceType,
                        playerId  = m_Record.Value.piece.playerId,
                        position  = destination
                    }
                });

                // Now actually request the move. Ensures that in order, the real result will always come first.
                m_MoveRequestedSubject.OnNext(new MoveEvent()
                {
                    sender      = this,
                    record      = currentPieceRecord,
                    destination = destination
                });
            }).AddTo(this);
        }
        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, schedulerProvider);

            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().AsDriver(schedulerProvider);
            StartDate           = startDateSubject.AsObservable().AsDriver(schedulerProvider);
            EndDate             = endDateSubject.AsObservable().AsDriver(schedulerProvider);

            SelectWorkspace = rxActionFactory.FromAsync(selectWorkspace);

            WorkspaceId = workspaceSubject
                          .Select(workspace => workspace.Id)
                          .DistinctUntilChanged()
                          .AsDriver(schedulerProvider);

            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
                               .StartWith(Resources.ThisWeek)
                               .Where(text => !string.IsNullOrEmpty(text))
                               .Select(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);
        }