public SendFeedbackViewModel( INavigationService navigationService, IInteractorFactory interactorFactory, IDialogService dialogService, ISchedulerProvider schedulerProvider, IRxActionFactory rxActionFactory) { Ensure.Argument.IsNotNull(interactorFactory, nameof(interactorFactory)); Ensure.Argument.IsNotNull(navigationService, nameof(navigationService)); Ensure.Argument.IsNotNull(dialogService, nameof(dialogService)); Ensure.Argument.IsNotNull(schedulerProvider, nameof(schedulerProvider)); Ensure.Argument.IsNotNull(rxActionFactory, nameof(rxActionFactory)); this.dialogService = dialogService; this.interactorFactory = interactorFactory; this.navigationService = navigationService; IsFeedbackEmpty = isEmptyObservable.DistinctUntilChanged().AsDriver(schedulerProvider); SendEnabled = sendingIsEnabledObservable.DistinctUntilChanged().AsDriver(schedulerProvider); Close = rxActionFactory.FromObservable(cancel); DismissError = rxActionFactory.FromAction(dismissError); Send = rxActionFactory.FromObservable(sendFeedback, sendingIsEnabledObservable); IsLoading = isLoadingSubject.AsDriver(false, schedulerProvider); Error = currentErrorSubject.AsDriver(default(Exception), schedulerProvider); }
public ForgotPasswordViewModel( ITimeService timeService, IUserAccessManager userAccessManager, IAnalyticsService analyticsService, INavigationService navigationService, IRxActionFactory rxActionFactory) : base(navigationService) { Ensure.Argument.IsNotNull(timeService, nameof(timeService)); Ensure.Argument.IsNotNull(userAccessManager, nameof(userAccessManager)); Ensure.Argument.IsNotNull(analyticsService, nameof(analyticsService)); Ensure.Argument.IsNotNull(rxActionFactory, nameof(rxActionFactory)); this.timeService = timeService; this.userAccessManager = userAccessManager; this.analyticsService = analyticsService; this.rxActionFactory = rxActionFactory; Reset = rxActionFactory.FromObservable(reset, Email.Select(email => email.IsValid)); var resetActionStartedObservable = Reset .Executing .Where(executing => executing) .Select(_ => (Exception)null); ErrorMessage = Reset.Errors .Merge(resetActionStartedObservable) .Select(toErrorString) .StartWith("") .DistinctUntilChanged(); PasswordResetSuccessful = Reset.Elements .Select(_ => true) .StartWith(false); }
public NoWorkspaceViewModel( ISyncManager syncManager, IInteractorFactory interactorFactory, INavigationService navigationService, IAccessRestrictionStorage accessRestrictionStorage, ISchedulerProvider schedulerProvider, IRxActionFactory rxActionFactory) : base(navigationService) { Ensure.Argument.IsNotNull(syncManager, nameof(syncManager)); Ensure.Argument.IsNotNull(accessRestrictionStorage, nameof(accessRestrictionStorage)); Ensure.Argument.IsNotNull(interactorFactory, nameof(interactorFactory)); Ensure.Argument.IsNotNull(schedulerProvider, nameof(schedulerProvider)); Ensure.Argument.IsNotNull(rxActionFactory, nameof(rxActionFactory)); this.syncManager = syncManager; this.accessRestrictionStorage = accessRestrictionStorage; this.interactorFactory = interactorFactory; this.rxActionFactory = rxActionFactory; CreateWorkspaceWithDefaultName = rxActionFactory.FromObservable(createWorkspaceWithDefaultName); TryAgain = rxActionFactory.FromAsync(tryAgain); IsLoading = Observable.CombineLatest( CreateWorkspaceWithDefaultName.Executing, TryAgain.Executing, CommonFunctions.Or); }
public ForgotPasswordViewModel( ITimeService timeService, IUserAccessManager userAccessManager, IAnalyticsService analyticsService, IMvxNavigationService navigationService, IRxActionFactory rxActionFactory) { Ensure.Argument.IsNotNull(timeService, nameof(timeService)); Ensure.Argument.IsNotNull(userAccessManager, nameof(userAccessManager)); Ensure.Argument.IsNotNull(analyticsService, nameof(analyticsService)); Ensure.Argument.IsNotNull(navigationService, nameof(navigationService)); Ensure.Argument.IsNotNull(rxActionFactory, nameof(rxActionFactory)); this.timeService = timeService; this.userAccessManager = userAccessManager; this.analyticsService = analyticsService; this.navigationService = navigationService; this.rxActionFactory = rxActionFactory; Reset = rxActionFactory.FromObservable(reset, Email.Select(email => email.IsValid)); Close = rxActionFactory.FromAction(returnEmail, Reset.Executing.Invert()); ErrorMessage = Reset.Errors .Select(toErrorString) .StartWith(""); PasswordResetSuccessful = Reset.Elements .Select(_ => true) .StartWith(false); }
public TokenResetViewModel( IUserAccessManager userAccessManager, ITogglDataSource dataSource, IDialogService dialogService, IMvxNavigationService navigationService, IUserPreferences userPreferences, IAnalyticsService analyticsService, ISchedulerProvider schedulerProvider, IRxActionFactory rxActionFactory, IInteractorFactory interactorFactory ) { Ensure.Argument.IsNotNull(dataSource, nameof(dataSource)); Ensure.Argument.IsNotNull(userAccessManager, nameof(userAccessManager)); Ensure.Argument.IsNotNull(dialogService, nameof(dialogService)); Ensure.Argument.IsNotNull(navigationService, nameof(navigationService)); Ensure.Argument.IsNotNull(userPreferences, nameof(userPreferences)); Ensure.Argument.IsNotNull(analyticsService, nameof(analyticsService)); Ensure.Argument.IsNotNull(schedulerProvider, nameof(schedulerProvider)); Ensure.Argument.IsNotNull(rxActionFactory, nameof(rxActionFactory)); Ensure.Argument.IsNotNull(interactorFactory, nameof(interactorFactory)); this.dataSource = dataSource; this.userAccessManager = userAccessManager; this.dialogService = dialogService; this.navigationService = navigationService; this.userPreferences = userPreferences; this.analyticsService = analyticsService; this.schedulerProvider = schedulerProvider; this.rxActionFactory = rxActionFactory; this.interactorFactory = interactorFactory; Email = emailSubject .DistinctUntilChanged() .AsDriver(schedulerProvider); IsPasswordMasked = isPasswordMaskedSubject .DistinctUntilChanged() .AsDriver(schedulerProvider); TogglePasswordVisibility = rxActionFactory.FromAction(togglePasswordVisibility); Done = rxActionFactory.FromObservable(done); SignOut = rxActionFactory.FromAsync(signout); Error = Done.Errors .Select(transformException); HasError = Error .Select(error => !string.IsNullOrEmpty(error)) .DistinctUntilChanged() .AsDriver(schedulerProvider); NextIsEnabled = Password .Select(Multivac.Password.From) .CombineLatest(Done.Executing, (password, isExecuting) => password.IsValid && !isExecuting) .DistinctUntilChanged() .AsDriver(schedulerProvider); }
protected SelectUserCalendarsViewModelBase( IUserPreferences userPreferences, IInteractorFactory interactorFactory, IRxActionFactory rxActionFactory) { Ensure.Argument.IsNotNull(userPreferences, nameof(userPreferences)); Ensure.Argument.IsNotNull(interactorFactory, nameof(interactorFactory)); Ensure.Argument.IsNotNull(rxActionFactory, nameof(rxActionFactory)); this.userPreferences = userPreferences; InteractorFactory = interactorFactory; this.rxActionFactory = rxActionFactory; SelectCalendar = rxActionFactory.FromObservable <SelectableUserCalendarViewModel>(selectCalendar); }
public SelectDefaultWorkspaceViewModel( ITogglDataSource dataSource, IInteractorFactory interactorFactory, INavigationService navigationService, IAccessRestrictionStorage accessRestrictionStorage, IRxActionFactory rxActionFactory) { Ensure.Argument.IsNotNull(dataSource, nameof(dataSource)); Ensure.Argument.IsNotNull(interactorFactory, nameof(interactorFactory)); Ensure.Argument.IsNotNull(navigationService, nameof(navigationService)); Ensure.Argument.IsNotNull(accessRestrictionStorage, nameof(accessRestrictionStorage)); Ensure.Argument.IsNotNull(rxActionFactory, nameof(rxActionFactory)); this.dataSource = dataSource; this.interactorFactory = interactorFactory; this.navigationService = navigationService; this.accessRestrictionStorage = accessRestrictionStorage; this.rxActionFactory = rxActionFactory; SelectWorkspace = rxActionFactory.FromObservable <SelectableWorkspaceViewModel>(selectWorkspace); }
public TokenResetViewModel( IUserAccessManager userAccessManager, ITogglDataSource dataSource, INavigationService navigationService, IUserPreferences userPreferences, IAnalyticsService analyticsService, ISchedulerProvider schedulerProvider, IRxActionFactory rxActionFactory, IInteractorFactory interactorFactory) : base(navigationService) { Ensure.Argument.IsNotNull(dataSource, nameof(dataSource)); Ensure.Argument.IsNotNull(rxActionFactory, nameof(rxActionFactory)); Ensure.Argument.IsNotNull(userPreferences, nameof(userPreferences)); Ensure.Argument.IsNotNull(analyticsService, nameof(analyticsService)); Ensure.Argument.IsNotNull(userAccessManager, nameof(userAccessManager)); Ensure.Argument.IsNotNull(schedulerProvider, nameof(schedulerProvider)); Ensure.Argument.IsNotNull(interactorFactory, nameof(interactorFactory)); this.dataSource = dataSource; this.userAccessManager = userAccessManager; this.interactorFactory = interactorFactory; Done = rxActionFactory.FromObservable(done); SignOut = rxActionFactory.FromAsync(signout); Error = Done.Errors .Select(transformException); HasError = Error .Select(error => !string.IsNullOrEmpty(error)) .DistinctUntilChanged() .AsDriver(schedulerProvider); NextIsEnabled = Password .Select(Shared.Password.From) .CombineLatest(Done.Executing, (password, isExecuting) => password.IsValid && !isExecuting) .DistinctUntilChanged() .AsDriver(schedulerProvider); }
public override Task Initialize() { base.Initialize(); StartTimeEntry = rxActionFactory.FromObservable <Suggestion, IThreadSafeTimeEntry>(startTimeEntry); var appResumedFromBackground = backgroundService .AppResumedFromBackground .SelectUnit() .Skip(1); var userCalendarPreferencesChanged = userPreferences .EnabledCalendars .SelectUnit() .Skip(1); Suggestions = syncManager.ProgressObservable .Where(progress => progress != SyncProgress.Syncing && progress != SyncProgress.Unknown && !backgroundService.AppIsInBackground) .Throttle(recalculationThrottleDuration, schedulerProvider.DefaultScheduler) .SelectUnit() .StartWith(Unit.Default) .Merge(recalculationRequested) .Merge(appResumedFromBackground) .Merge(userCalendarPreferencesChanged) .SelectMany(_ => getSuggestions()) .WithLatestFrom(permissionsChecker.CalendarPermissionGranted, (suggestions, isCalendarAuthorized) => (suggestions, isCalendarAuthorized)) .Do(item => trackPresentedSuggestions(item.suggestions, item.isCalendarAuthorized)) .Select(item => item.suggestions) .AsDriver(onErrorJustReturn: ImmutableList.Create <Suggestion>(), schedulerProvider: schedulerProvider); IsEmpty = Suggestions .Select(suggestions => suggestions.None()) .StartWith(true) .AsDriver(onErrorJustReturn: true, schedulerProvider: schedulerProvider); return(base.Initialize()); }
public EditProjectViewModel( ITogglDataSource dataSource, IRxActionFactory rxActionFactory, IInteractorFactory interactorFactory, ISchedulerProvider schedulerProvider, INavigationService navigationService) : base(navigationService) { Ensure.Argument.IsNotNull(dataSource, nameof(dataSource)); Ensure.Argument.IsNotNull(rxActionFactory, nameof(rxActionFactory)); Ensure.Argument.IsNotNull(interactorFactory, nameof(interactorFactory)); Ensure.Argument.IsNotNull(schedulerProvider, nameof(schedulerProvider)); this.dataSource = dataSource; this.interactorFactory = interactorFactory; Name = new BehaviorRelay <string>(""); IsPrivate = new BehaviorRelay <bool>(true); PickColor = rxActionFactory.FromObservable <Color>(pickColor); PickClient = rxActionFactory.FromObservable <IThreadSafeClient>(pickClient); PickWorkspace = rxActionFactory.FromObservable <IThreadSafeWorkspace>(pickWorkspace); var initialWorkspaceObservable = interactorFactory .GetDefaultWorkspace() .TrackException <InvalidOperationException, IThreadSafeWorkspace>("EditProjectViewModel.Initialize") .Execute() .SelectMany(defaultWorkspaceOrWorkspaceEligibleForProjectCreation) .Do(initialWorkspace => initialWorkspaceId = initialWorkspace.Id); currentWorkspace = initialWorkspaceObservable .Merge(PickWorkspace.Elements) .ShareReplay(1); currentClient = currentWorkspace .SelectValue((IThreadSafeClient)null) .Merge(PickClient.Elements) .ShareReplay(1); WorkspaceName = currentWorkspace .Select(w => w.Name) .DistinctUntilChanged() .AsDriver(schedulerProvider); CanCreatePublicProjects = currentWorkspace .Select(w => w.Admin) .DoIf(isAdmin => !isAdmin, _ => IsPrivate.Accept(true)) .DistinctUntilChanged() .AsDriver(schedulerProvider); var clientName = currentClient .Select(client => client?.Name ?? "") .DistinctUntilChanged(); ClientName = clientName .AsDriver(schedulerProvider); Color = PickColor.Elements .StartWith(getRandomColor()) .Merge(currentWorkspace .SelectMany(customColorIsEnabled) .SelectMany(customColorsAreAvailable => customColorsAreAvailable ? Observable.Empty <Color>() : Color.FirstAsync().Select(randomColorIfNotDefault))) .DistinctUntilChanged() .AsDriver(schedulerProvider); var saveEnabledObservable = Name.Select(checkNameValidity); var projectOrClientNameChanged = Observable .Merge(clientName.SelectUnit(), Name.SelectUnit()); Save = rxActionFactory.FromObservable(done, saveEnabledObservable); ToggleIsPrivate = rxActionFactory.FromAction(toggleIsPrivate); Error = Save.Errors .Select(e => e.Message) .Merge(projectOrClientNameChanged.SelectValue(string.Empty)) .AsDriver(schedulerProvider); IObservable <IThreadSafeWorkspace> defaultWorkspaceOrWorkspaceEligibleForProjectCreation(IThreadSafeWorkspace defaultWorkspace) => defaultWorkspace.IsEligibleForProjectCreation() ? Observable.Return(defaultWorkspace) : interactorFactory.GetAllWorkspaces().Execute() .Select(allWorkspaces => allWorkspaces.First(ws => ws.IsEligibleForProjectCreation())); IObservable <bool> customColorIsEnabled(IThreadSafeWorkspace workspace) => interactorFactory .AreCustomColorsEnabledForWorkspace(workspace.Id) .Execute(); Color getRandomColor() { var randomColorIndex = random.Next(0, Helper.Colors.DefaultProjectColors.Length); return(Helper.Colors.DefaultProjectColors[randomColorIndex]); } Color randomColorIfNotDefault(Color lastColor) { var hex = lastColor.ToHexString(); if (DefaultProjectColors.Any(defaultColor => defaultColor == hex)) { return(lastColor); } return(getRandomColor()); } bool checkNameValidity(string name) => !string.IsNullOrWhiteSpace(name) && name.LengthInBytes() <= Constants.MaxProjectNameLengthInBytes; }
public StartTimeEntryViewModel( ITimeService timeService, ITogglDataSource dataSource, IUserPreferences userPreferences, IOnboardingStorage onboardingStorage, IInteractorFactory interactorFactory, INavigationService navigationService, IAnalyticsService analyticsService, ISchedulerProvider schedulerProvider, IRxActionFactory rxActionFactory) : base(navigationService) { Ensure.Argument.IsNotNull(dataSource, nameof(dataSource)); Ensure.Argument.IsNotNull(timeService, nameof(timeService)); Ensure.Argument.IsNotNull(userPreferences, nameof(userPreferences)); Ensure.Argument.IsNotNull(interactorFactory, nameof(interactorFactory)); Ensure.Argument.IsNotNull(onboardingStorage, nameof(onboardingStorage)); Ensure.Argument.IsNotNull(analyticsService, nameof(analyticsService)); Ensure.Argument.IsNotNull(schedulerProvider, nameof(schedulerProvider)); Ensure.Argument.IsNotNull(rxActionFactory, nameof(rxActionFactory)); this.timeService = timeService; this.userPreferences = userPreferences; this.interactorFactory = interactorFactory; this.analyticsService = analyticsService; this.schedulerProvider = schedulerProvider; DataSource = dataSource; OnboardingStorage = onboardingStorage; TextFieldInfo = textFieldInfo.AsDriver(schedulerProvider); IsBillable = isBillable.AsDriver(schedulerProvider); IsSuggestingTags = isSuggestingTags.AsDriver(schedulerProvider); IsSuggestingProjects = isSuggestingProjects.AsDriver(schedulerProvider); IsBillableAvailable = isBillableAvailable.AsDriver(schedulerProvider); DisplayedTime = displayedTime .Select(time => time.ToFormattedString(DurationFormat.Improved)) .AsDriver(schedulerProvider); Done = rxActionFactory.FromObservable <IThreadSafeTimeEntry>(done); DurationTapped = rxActionFactory.FromAction(durationTapped); ToggleBillable = rxActionFactory.FromAction(toggleBillable); SetStartDate = rxActionFactory.FromAsync(setStartDate); ChangeTime = rxActionFactory.FromAsync(changeTime); ToggleTagSuggestions = rxActionFactory.FromAction(toggleTagSuggestions); ToggleProjectSuggestions = rxActionFactory.FromAction(toggleProjectSuggestions); SelectSuggestion = rxActionFactory.FromAsync <AutocompleteSuggestion>(selectSuggestion); SetRunningTime = rxActionFactory.FromAction <TimeSpan>(setRunningTime); ToggleTasks = rxActionFactory.FromAction <ProjectSuggestion>(toggleTasks); SetTextSpans = rxActionFactory.FromAction <IImmutableList <ISpan> >(setTextSpans); var queryByType = queryByTypeSubject .AsObservable() .SelectMany(type => interactorFactory.GetAutocompleteSuggestions(new QueryInfo("", type)).Execute()); var queryByText = textFieldInfo .SelectMany(setBillableValues) .Select(QueryInfo.ParseFieldInfo) .Do(onParsedQuery) .ObserveOn(schedulerProvider.BackgroundScheduler) .SelectMany(query => interactorFactory.GetAutocompleteSuggestions(query).Execute()); Suggestions = Observable.Merge(queryByText, queryByType) .Select(filter) .Select(group) .CombineLatest(expandedProjects, (groups, _) => groups) .Select(toCollections) .Select(addStaticElements) .AsDriver(schedulerProvider); }
public override async Task Initialize() { await base.Initialize(); await TimeEntriesViewModel.Initialize(); await SuggestionsViewModel.Initialize(); await RatingViewModel.Initialize(); SyncProgressState = dataSource .SyncManager .ProgressObservable .AsDriver(SchedulerProvider); var isWelcome = onboardingStorage.IsNewUser; var noTimeEntries = Observable .CombineLatest(TimeEntriesViewModel.Empty, SuggestionsViewModel.IsEmpty, (isTimeEntryEmpty, isSuggestionEmpty) => isTimeEntryEmpty && isSuggestionEmpty) .DistinctUntilChanged(); ShouldShowEmptyState = ObservableAddons.CombineLatestAll( isWelcome, noTimeEntries ) .DistinctUntilChanged() .AsDriver(SchedulerProvider); ShouldShowWelcomeBack = ObservableAddons.CombineLatestAll( isWelcome.Select(b => !b), noTimeEntries ) .StartWith(false) .DistinctUntilChanged() .AsDriver(SchedulerProvider); IsInManualMode = userPreferences .IsManualModeEnabledObservable .AsDriver(SchedulerProvider); ShouldShowRunningTimeEntryNotification = userPreferences.AreRunningTimerNotificationsEnabledObservable; ShouldShowStoppedTimeEntryNotification = userPreferences.AreStoppedTimerNotificationsEnabledObservable; CurrentRunningTimeEntry = dataSource .TimeEntries .CurrentlyRunningTimeEntry .AsDriver(SchedulerProvider); IsTimeEntryRunning = CurrentRunningTimeEntry .Select(te => te != null) .DistinctUntilChanged() .AsDriver(SchedulerProvider); var durationObservable = dataSource .Preferences .Current .Select(preferences => preferences.DurationFormat); ElapsedTime = TimeService .CurrentDateTimeObservable .CombineLatest(CurrentRunningTimeEntry, (now, te) => (now - te?.Start) ?? TimeSpan.Zero) .CombineLatest(durationObservable, (duration, format) => duration.ToFormattedString(format)) .AsDriver(SchedulerProvider); NumberOfSyncFailures = interactorFactory .GetItemsThatFailedToSync() .Execute() .Select(i => i.Count()) .AsDriver(SchedulerProvider); ShouldReloadTimeEntryLog = Observable.Merge( TimeService.MidnightObservable.SelectUnit(), TimeService.SignificantTimeChangeObservable.SelectUnit()) .AsDriver(SchedulerProvider); Refresh = rxActionFactory.FromAsync(refresh); OpenReports = rxActionFactory.FromAsync(openReports); OpenSettings = rxActionFactory.FromAsync(openSettings); OpenSyncFailures = rxActionFactory.FromAsync(openSyncFailures); SelectTimeEntry = rxActionFactory.FromAsync <long>(timeEntrySelected); DeleteTimeEntry = rxActionFactory.FromObservable <TimeEntryViewModel>(deleteTimeEntry); ContinueTimeEntry = rxActionFactory.FromObservable <TimeEntryViewModel>(continueTimeEntry); StartTimeEntry = rxActionFactory.FromAsync <bool>(startTimeEntry, IsTimeEntryRunning.Invert()); StopTimeEntry = rxActionFactory.FromAsync <TimeEntryStopOrigin>(stopTimeEntry, IsTimeEntryRunning); switch (urlNavigationAction) { case ApplicationUrls.Main.Action.Continue: await continueMostRecentEntry(); break; case ApplicationUrls.Main.Action.Stop: await stopTimeEntry(TimeEntryStopOrigin.Deeplink); break; } ratingViewExperiment .RatingViewShouldBeVisible .Subscribe(presentRatingViewIfNeeded) .DisposedBy(disposeBag); onboardingStorage.StopButtonWasTappedBefore .Subscribe(hasBeen => hasStopButtonEverBeenUsed = hasBeen) .DisposedBy(disposeBag); interactorFactory.GetDefaultWorkspace() .TrackException <InvalidOperationException, IThreadSafeWorkspace>("MainViewModel.Initialize") .Execute() .Subscribe(intentDonationService.SetDefaultShortcutSuggestions) .DisposedBy(disposeBag); dataSource .Workspaces .Created .Subscribe(_ => onWorkspaceCreated()) .DisposedBy(disposeBag); dataSource .Workspaces .Updated .Subscribe(onWorkspaceUpdated) .DisposedBy(disposeBag); }
public override async Task Initialize() { await base.Initialize(); interactorFactory.GetCurrentUser().Execute() .Select(u => u.Id) .Subscribe(analyticsService.SetAppCenterUserId); await SuggestionsViewModel.Initialize(); await RatingViewModel.Initialize(); widgetsService.Start(); SyncProgressState = syncManager.ProgressObservable .AsDriver(schedulerProvider); var isWelcome = OnboardingStorage.IsNewUser; var noTimeEntries = Observable .CombineLatest(TimeEntriesViewModel.Empty, SuggestionsViewModel.IsEmpty, (isTimeEntryEmpty, isSuggestionEmpty) => isTimeEntryEmpty && isSuggestionEmpty) .DistinctUntilChanged(); ShouldShowEmptyState = ObservableAddons.CombineLatestAll( isWelcome, noTimeEntries ) .DistinctUntilChanged() .AsDriver(schedulerProvider); ShouldShowWelcomeBack = ObservableAddons.CombineLatestAll( isWelcome.Select(b => !b), noTimeEntries ) .StartWith(false) .DistinctUntilChanged() .AsDriver(schedulerProvider); IsInManualMode = userPreferences .IsManualModeEnabledObservable .AsDriver(schedulerProvider); ShouldShowRunningTimeEntryNotification = userPreferences.AreRunningTimerNotificationsEnabledObservable; ShouldShowStoppedTimeEntryNotification = userPreferences.AreStoppedTimerNotificationsEnabledObservable; CurrentRunningTimeEntry = dataSource.TimeEntries .CurrentlyRunningTimeEntry .AsDriver(schedulerProvider); IsTimeEntryRunning = dataSource.TimeEntries .CurrentlyRunningTimeEntry .Select(te => te != null) .DistinctUntilChanged() .AsDriver(schedulerProvider); var durationObservable = dataSource .Preferences .Current .Select(preferences => preferences.DurationFormat); ElapsedTime = TimeService .CurrentDateTimeObservable .CombineLatest(CurrentRunningTimeEntry, (now, te) => (now - te?.Start) ?? TimeSpan.Zero) .CombineLatest(durationObservable, (duration, format) => duration.ToFormattedString(format)) .AsDriver(schedulerProvider); NumberOfSyncFailures = interactorFactory .GetItemsThatFailedToSync() .Execute() .Select(i => i.Count()) .AsDriver(schedulerProvider); ShouldReloadTimeEntryLog = Observable.Merge( TimeService.MidnightObservable.SelectUnit(), TimeService.SignificantTimeChangeObservable.SelectUnit()) .AsDriver(schedulerProvider); Refresh = rxActionFactory.FromAsync(refresh); OpenSettings = rxActionFactory.FromAsync(openSettings); OpenSyncFailures = rxActionFactory.FromAsync(openSyncFailures); SelectTimeEntry = rxActionFactory.FromAsync <EditTimeEntryInfo>(timeEntrySelected); ContinueTimeEntry = rxActionFactory.FromObservable <ContinueTimeEntryInfo, IThreadSafeTimeEntry>(continueTimeEntry); StartTimeEntry = rxActionFactory.FromAsync <bool>(startTimeEntry, IsTimeEntryRunning.Invert()); StopTimeEntry = rxActionFactory.FromObservable <TimeEntryStopOrigin>(stopTimeEntry, IsTimeEntryRunning); ShouldShowRatingView = Observable.Merge( ratingViewExperiment.RatingViewShouldBeVisible, RatingViewModel.HideRatingView.SelectValue(false), hideRatingView.AsObservable().SelectValue(false) ) .Select(canPresentRating) .DistinctUntilChanged() .Do(trackRatingViewPresentation) .AsDriver(schedulerProvider); OnboardingStorage.StopButtonWasTappedBefore .Subscribe(hasBeen => hasStopButtonEverBeenUsed = hasBeen) .DisposedBy(disposeBag); if (platformInfo.Platform == Platform.Giskard) { analyticsService.ApplicationInstallLocation.Track(platformInfo.InstallLocation); } SyncProgressState .Subscribe(postAccessibilityAnnouncementAboutSync) .DisposedBy(disposeBag); }