public override async Task Initialize() { await base.Initialize(); await TimeEntriesLogViewModel.Initialize(); await SuggestionsViewModel.Initialize(); var tickDisposable = timeService .CurrentDateTimeObservable .Where(_ => currentTimeEntryStart != null) .Subscribe(currentTime => CurrentTimeEntryElapsedTime = currentTime - currentTimeEntryStart.Value); var currentlyRunningTimeEntryDisposable = dataSource .TimeEntries .CurrentlyRunningTimeEntry .Throttle(currentTimeEntryDueTime, scheduler) // avoid overwhelming the UI with frequent updates .Subscribe(setRunningEntry); var syncManagerDisposable = dataSource .SyncManager .ProgressObservable .Subscribe(progress => SyncingProgress = progress); var isEmptyChangedDisposable = Observable.Empty <Unit>() .Merge(dataSource.TimeEntries.TimeEntryUpdated.Select(_ => Unit.Default)) .Merge(dataSource.TimeEntries.TimeEntryDeleted.Select(_ => Unit.Default)) .Merge(dataSource.TimeEntries.TimeEntryCreated.Select(_ => Unit.Default)) .Subscribe(_ => { RaisePropertyChanged(nameof(ShouldShowTimeEntriesLog)); RaisePropertyChanged(nameof(ShouldShowWelcomeBack)); RaisePropertyChanged(nameof(ShouldShowEmptyState)); RaisePropertyChanged(nameof(IsLogEmpty)); RaisePropertyChanged(nameof(TimeEntriesCount)); }); disposeBag.Add(tickDisposable); disposeBag.Add(syncManagerDisposable); disposeBag.Add(isEmptyChangedDisposable); disposeBag.Add(currentlyRunningTimeEntryDisposable); switch (urlNavigationAction) { case ApplicationUrls.Main.Action.Continue: await continueMostRecentEntry(); break; case ApplicationUrls.Main.Action.Stop: await stopTimeEntry(); break; } }
public override async Task Initialize() { await base.Initialize(); await TimeEntriesViewModel.Initialize(); await TimeEntriesLogViewModel.Initialize(); await SuggestionsViewModel.Initialize(); await RatingViewModel.Initialize(); SyncProgressState = dataSource.SyncManager .ProgressObservable.AsDriver(schedulerProvider); var isWelcome = onboardingStorage.IsNewUser; var noTimeEntries = TimeEntriesViewModel.Empty .Select(e => e && SuggestionsViewModel.IsEmpty) .DistinctUntilChanged(); ShouldShowEmptyState = ObservableAddons.CombineLatestAll( isWelcome, noTimeEntries ) .DistinctUntilChanged() .AsDriver(schedulerProvider); ShouldShowWelcomeBack = ObservableAddons.CombineLatestAll( isWelcome.Select(b => !b), noTimeEntries ) .StartWith(false) .DistinctUntilChanged() .AsDriver(schedulerProvider); var connectableTimeEntryIsRunning = dataSource .TimeEntries .CurrentlyRunningTimeEntry .Do(setRunningEntry) .Select(timeEntry => timeEntry != null) .DistinctUntilChanged() .Replay(1); connectableTimeEntryIsRunning.Connect(); IsTimeEntryRunning = connectableTimeEntryIsRunning.AsDriver(schedulerProvider); CurrentTimeEntryHasDescription = dataSource .TimeEntries .CurrentlyRunningTimeEntry .Select(te => !string.IsNullOrWhiteSpace(te?.Description)) .DistinctUntilChanged() .AsDriver(schedulerProvider); timeService .CurrentDateTimeObservable .Where(_ => currentTimeEntryStart != null) .Subscribe(currentTime => CurrentTimeEntryElapsedTime = currentTime - currentTimeEntryStart.Value) .DisposedBy(disposeBag); dataSource .SyncManager .ProgressObservable .Subscribe(progress => SyncingProgress = progress) .DisposedBy(disposeBag); interactorFactory .GetItemsThatFailedToSync() .Execute() .Select(i => i.Count()) .Subscribe(n => NumberOfSyncFailures = n) .DisposedBy(disposeBag); timeService.MidnightObservable .Subscribe(onMidnight) .DisposedBy(disposeBag); switch (urlNavigationAction) { case ApplicationUrls.Main.Action.Continue: await continueMostRecentEntry(); break; case ApplicationUrls.Main.Action.Stop: await stopTimeEntry(); break; } ratingViewExperiment .RatingViewShouldBeVisible .Subscribe(presentRatingViewIfNeeded) .DisposedBy(disposeBag); onboardingStorage.StopButtonWasTappedBefore .Subscribe(hasBeen => hasStopButtonEverBeenUsed = hasBeen) .DisposedBy(disposeBag); }
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(); await TimeEntriesLogViewModel.Initialize(); await SuggestionsViewModel.Initialize(); await RatingViewModel.Initialize(); var connectableTimeEntryIsRunning = dataSource .TimeEntries .CurrentlyRunningTimeEntry .Do(setRunningEntry) .Select(timeEntry => timeEntry != null) .DistinctUntilChanged() .Replay(1); connectableTimeEntryIsRunning.Connect(); IsTimeEntryRunning = connectableTimeEntryIsRunning; var tickDisposable = timeService .CurrentDateTimeObservable .Where(_ => currentTimeEntryStart != null) .Subscribe(currentTime => CurrentTimeEntryElapsedTime = currentTime - currentTimeEntryStart.Value); var syncManagerDisposable = dataSource .SyncManager .ProgressObservable .Subscribe(progress => SyncingProgress = progress); var isEmptyChangedDisposable = Observable.Empty <Unit>() .Merge(dataSource.TimeEntries.Updated.Select(_ => Unit.Default)) .Merge(dataSource.TimeEntries.Deleted.Select(_ => Unit.Default)) .Merge(dataSource.TimeEntries.Created.Select(_ => Unit.Default)) .Subscribe((Unit _) => { RaisePropertyChanged(nameof(ShouldShowTimeEntriesLog)); RaisePropertyChanged(nameof(ShouldShowWelcomeBack)); RaisePropertyChanged(nameof(ShouldShowEmptyState)); RaisePropertyChanged(nameof(IsLogEmpty)); RaisePropertyChanged(nameof(TimeEntriesCount)); }); var getNumberOfSyncFailuresDisposable = interactorFactory .GetItemsThatFailedToSync() .Execute() .Select(i => i.Count()) .Subscribe(n => NumberOfSyncFailures = n); disposeBag.Add(tickDisposable); disposeBag.Add(syncManagerDisposable); disposeBag.Add(isEmptyChangedDisposable); disposeBag.Add(getNumberOfSyncFailuresDisposable); switch (urlNavigationAction) { case ApplicationUrls.Main.Action.Continue: await continueMostRecentEntry(); break; case ApplicationUrls.Main.Action.Stop: await stopTimeEntry(); break; } ratingViewExperiment .RatingViewShouldBeVisible .Subscribe(presentRatingViewIfNeeded) .DisposedBy(disposeBag); onboardingStorage.StopButtonWasTappedBefore .Subscribe(hasBeen => hasStopButtonEverBeenUsed = hasBeen) .DisposedBy(disposeBag); }