public EditTimeEntryViewModel( ITimeService timeService, ITogglDataSource dataSource, ISyncManager syncManager, IInteractorFactory interactorFactory, IMvxNavigationService navigationService, IOnboardingStorage onboardingStorage, IDialogService dialogService, IAnalyticsService analyticsService, IStopwatchProvider stopwatchProvider, IRxActionFactory actionFactory, ISchedulerProvider schedulerProvider) { Ensure.Argument.IsNotNull(dataSource, nameof(dataSource)); Ensure.Argument.IsNotNull(syncManager, nameof(syncManager)); Ensure.Argument.IsNotNull(timeService, nameof(timeService)); Ensure.Argument.IsNotNull(dialogService, nameof(dialogService)); Ensure.Argument.IsNotNull(interactorFactory, nameof(interactorFactory)); Ensure.Argument.IsNotNull(onboardingStorage, nameof(onboardingStorage)); Ensure.Argument.IsNotNull(navigationService, nameof(navigationService)); Ensure.Argument.IsNotNull(analyticsService, nameof(analyticsService)); Ensure.Argument.IsNotNull(stopwatchProvider, nameof(stopwatchProvider)); Ensure.Argument.IsNotNull(schedulerProvider, nameof(schedulerProvider)); Ensure.Argument.IsNotNull(actionFactory, nameof(actionFactory)); this.dataSource = dataSource; this.syncManager = syncManager; this.timeService = timeService; this.dialogService = dialogService; this.interactorFactory = interactorFactory; this.navigationService = navigationService; this.analyticsService = analyticsService; this.stopwatchProvider = stopwatchProvider; this.schedulerProvider = schedulerProvider; this.actionFactory = actionFactory; OnboardingStorage = onboardingStorage; workspaceIdSubject .Where(id => id.HasValue) .Subscribe(id => workspaceId = id.Value) .DisposedBy(disposeBag); isEditingDescriptionSubject = new BehaviorSubject <bool>(false); Description = new BehaviorRelay <string>(string.Empty, CommonFunctions.Trim); projectClientTaskSubject = new BehaviorSubject <ProjectClientTaskInfo>(ProjectClientTaskInfo.Empty); ProjectClientTask = projectClientTaskSubject .AsDriver(ProjectClientTaskInfo.Empty, schedulerProvider); IsBillableAvailable = workspaceIdSubject .Where(id => id.HasValue) .SelectMany(workspaceId => interactorFactory.IsBillableAvailableForWorkspace(workspaceId.Value).Execute()) .DistinctUntilChanged() .AsDriver(false, schedulerProvider); isBillableSubject = new BehaviorSubject <bool>(false); IsBillable = isBillableSubject .DistinctUntilChanged() .AsDriver(false, schedulerProvider); startTimeSubject = new BehaviorSubject <DateTimeOffset>(DateTimeOffset.UtcNow); var startTimeObservable = startTimeSubject.DistinctUntilChanged(); StartTime = startTimeObservable .AsDriver(default(DateTimeOffset), schedulerProvider); var now = timeService.CurrentDateTimeObservable.StartWith(timeService.CurrentDateTime); durationSubject = new ReplaySubject <TimeSpan?>(bufferSize: 1); Duration = durationSubject .Select(duration => duration.HasValue ? Observable.Return(duration.Value) : now.CombineLatest( startTimeObservable, (currentTime, startTime) => currentTime - startTime)) .Switch() .DistinctUntilChanged() .AsDriver(TimeSpan.Zero, schedulerProvider); var stopTimeObservable = Observable.CombineLatest(startTimeObservable, durationSubject, calculateStopTime) .DistinctUntilChanged(); StopTime = stopTimeObservable .AsDriver(null, schedulerProvider); var isTimeEntryRunningObservable = stopTimeObservable .Select(stopTime => !stopTime.HasValue) .Do(value => isRunning = value) .DistinctUntilChanged(); IsTimeEntryRunning = isTimeEntryRunningObservable .AsDriver(false, schedulerProvider); tagsSubject = new BehaviorSubject <IEnumerable <IThreadSafeTag> >(Enumerable.Empty <IThreadSafeTag>()); Tags = tagsSubject .Select(tags => tags.Select(ellipsize).ToImmutableList()) .AsDriver(ImmutableList <string> .Empty, schedulerProvider); isInaccessibleSubject = new BehaviorSubject <bool>(false); IsInaccessible = isInaccessibleSubject .DistinctUntilChanged() .AsDriver(false, schedulerProvider); syncErrorMessageSubject = new BehaviorSubject <string>(string.Empty); SyncErrorMessage = syncErrorMessageSubject .Select(error => error ?? string.Empty) .DistinctUntilChanged() .AsDriver(string.Empty, schedulerProvider); IsSyncErrorMessageVisible = syncErrorMessageSubject .Select(error => !string.IsNullOrEmpty(error)) .DistinctUntilChanged() .AsDriver(false, schedulerProvider); Preferences = interactorFactory.GetPreferences().Execute() .AsDriver(null, schedulerProvider); // Actions Close = actionFactory.FromAsync(closeWithConfirmation); SelectProject = actionFactory.FromAsync(selectProject); SelectTags = actionFactory.FromAsync(selectTags); ToggleBillable = actionFactory.FromAction(toggleBillable); EditTimes = actionFactory.FromAsync <EditViewTapSource>(editTimes); SelectStartDate = actionFactory.FromAsync(selectStartDate); StopTimeEntry = actionFactory.FromAction(stopTimeEntry, isTimeEntryRunningObservable); DismissSyncErrorMessage = actionFactory.FromAction(dismissSyncErrorMessage); Save = actionFactory.FromAsync(save); Delete = actionFactory.FromAsync(delete); }