public MainViewModel( ITogglDataSource dataSource, ITimeService timeService, IRatingService ratingService, IUserPreferences userPreferences, IAnalyticsService analyticsService, IOnboardingStorage onboardingStorage, IInteractorFactory interactorFactory, IMvxNavigationService navigationService, IRemoteConfigService remoteConfigService, ISuggestionProviderContainer suggestionProviders, ISchedulerProvider schedulerProvider) { Ensure.Argument.IsNotNull(dataSource, nameof(dataSource)); Ensure.Argument.IsNotNull(timeService, nameof(timeService)); Ensure.Argument.IsNotNull(ratingService, nameof(ratingService)); Ensure.Argument.IsNotNull(userPreferences, nameof(userPreferences)); Ensure.Argument.IsNotNull(analyticsService, nameof(analyticsService)); Ensure.Argument.IsNotNull(interactorFactory, nameof(interactorFactory)); Ensure.Argument.IsNotNull(onboardingStorage, nameof(onboardingStorage)); Ensure.Argument.IsNotNull(navigationService, nameof(navigationService)); Ensure.Argument.IsNotNull(remoteConfigService, nameof(remoteConfigService)); Ensure.Argument.IsNotNull(suggestionProviders, nameof(suggestionProviders)); Ensure.Argument.IsNotNull(schedulerProvider, nameof(schedulerProvider)); this.dataSource = dataSource; this.timeService = timeService; this.userPreferences = userPreferences; this.analyticsService = analyticsService; this.interactorFactory = interactorFactory; this.navigationService = navigationService; this.onboardingStorage = onboardingStorage; this.schedulerProvider = schedulerProvider; SuggestionsViewModel = new SuggestionsViewModel(dataSource, interactorFactory, onboardingStorage, suggestionProviders); RatingViewModel = new RatingViewModel(timeService, dataSource, ratingService, analyticsService, onboardingStorage, navigationService, this.schedulerProvider); TimeEntriesLogViewModel = new TimeEntriesLogViewModel(timeService, dataSource, interactorFactory, onboardingStorage, analyticsService, navigationService); timeEntriesViewModel = new TimeEntriesViewModel(dataSource, interactorFactory); LogEmpty = timeEntriesViewModel.Empty.AsDriver(this.schedulerProvider); TimeEntriesCount = timeEntriesViewModel.Count.AsDriver(this.schedulerProvider); ratingViewExperiment = new RatingViewExperiment(timeService, dataSource, onboardingStorage, remoteConfigService); RefreshCommand = new MvxCommand(Refresh); OpenReportsCommand = new MvxAsyncCommand(openReports); OpenSettingsCommand = new MvxAsyncCommand(openSettings); OpenSyncFailuresCommand = new MvxAsyncCommand(openSyncFailures); EditTimeEntryCommand = new MvxAsyncCommand(editTimeEntry, canExecuteEditTimeEntryCommand); StopTimeEntryCommand = new MvxAsyncCommand(stopTimeEntry, () => isStopButtonEnabled); StartTimeEntryCommand = new MvxAsyncCommand(startTimeEntry, () => CurrentTimeEntryId.HasValue == false); AlternativeStartTimeEntryCommand = new MvxAsyncCommand(alternativeStartTimeEntry, () => CurrentTimeEntryId.HasValue == false); ContinueTimeEntry = new InputAction <TimeEntryViewModel>(continueTimeEntry); DeleteTimeEntry = new InputAction <TimeEntryViewModel>(deleteTimeEntry); SelectTimeEntry = new InputAction <TimeEntryViewModel>(timeEntrySelected); RefreshAction = new UIAction(refresh); }
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 MainViewModel( ITogglDataSource dataSource, ITimeService timeService, IRatingService ratingService, IUserPreferences userPreferences, IFeedbackService feedbackService, IAnalyticsService analyticsService, IOnboardingStorage onboardingStorage, IInteractorFactory interactorFactory, IMvxNavigationService navigationService, IRemoteConfigService remoteConfigService, ISuggestionProviderContainer suggestionProviders) { Ensure.Argument.IsNotNull(dataSource, nameof(dataSource)); Ensure.Argument.IsNotNull(timeService, nameof(timeService)); Ensure.Argument.IsNotNull(ratingService, nameof(ratingService)); Ensure.Argument.IsNotNull(userPreferences, nameof(userPreferences)); Ensure.Argument.IsNotNull(feedbackService, nameof(feedbackService)); Ensure.Argument.IsNotNull(analyticsService, nameof(analyticsService)); Ensure.Argument.IsNotNull(interactorFactory, nameof(interactorFactory)); Ensure.Argument.IsNotNull(onboardingStorage, nameof(onboardingStorage)); Ensure.Argument.IsNotNull(navigationService, nameof(navigationService)); Ensure.Argument.IsNotNull(remoteConfigService, nameof(remoteConfigService)); Ensure.Argument.IsNotNull(suggestionProviders, nameof(suggestionProviders)); this.dataSource = dataSource; this.timeService = timeService; this.userPreferences = userPreferences; this.analyticsService = analyticsService; this.interactorFactory = interactorFactory; this.navigationService = navigationService; this.onboardingStorage = onboardingStorage; SuggestionsViewModel = new SuggestionsViewModel(dataSource, interactorFactory, onboardingStorage, suggestionProviders); RatingViewModel = new RatingViewModel(timeService, dataSource, ratingService, feedbackService, analyticsService, onboardingStorage, navigationService); TimeEntriesLogViewModel = new TimeEntriesLogViewModel(timeService, dataSource, interactorFactory, onboardingStorage, analyticsService, navigationService); ratingViewExperiment = new RatingViewExperiment(timeService, dataSource, onboardingStorage, remoteConfigService); RefreshCommand = new MvxCommand(refresh); OpenReportsCommand = new MvxAsyncCommand(openReports); OpenSettingsCommand = new MvxAsyncCommand(openSettings); OpenSyncFailuresCommand = new MvxAsyncCommand(openSyncFailures); EditTimeEntryCommand = new MvxAsyncCommand(editTimeEntry, () => CurrentTimeEntryId.HasValue); StopTimeEntryCommand = new MvxAsyncCommand(stopTimeEntry, () => isStopButtonEnabled); StartTimeEntryCommand = new MvxAsyncCommand(startTimeEntry, () => CurrentTimeEntryId.HasValue == false); AlternativeStartTimeEntryCommand = new MvxAsyncCommand(alternativeStartTimeEntry, () => CurrentTimeEntryId.HasValue == false); }
public MainViewModel( IScheduler scheduler, ITogglDataSource dataSource, ITimeService timeService, IUserPreferences userPreferences, IOnboardingStorage onboardingStorage, IInteractorFactory interactorFactory, IMvxNavigationService navigationService, ISuggestionProviderContainer suggestionProviders) { Ensure.Argument.IsNotNull(scheduler, nameof(scheduler)); 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(navigationService, nameof(navigationService)); Ensure.Argument.IsNotNull(suggestionProviders, nameof(suggestionProviders)); this.scheduler = scheduler; this.dataSource = dataSource; this.timeService = timeService; this.userPreferences = userPreferences; this.interactorFactory = interactorFactory; this.navigationService = navigationService; this.onboardingStorage = onboardingStorage; TimeEntriesLogViewModel = new TimeEntriesLogViewModel(timeService, dataSource, interactorFactory, onboardingStorage, navigationService); SuggestionsViewModel = new SuggestionsViewModel(dataSource, interactorFactory, suggestionProviders); RefreshCommand = new MvxCommand(refresh); OpenReportsCommand = new MvxAsyncCommand(openReports); OpenSettingsCommand = new MvxAsyncCommand(openSettings); EditTimeEntryCommand = new MvxAsyncCommand(editTimeEntry, () => CurrentTimeEntryId.HasValue); StopTimeEntryCommand = new MvxAsyncCommand(stopTimeEntry, () => isStopButtonEnabled); StartTimeEntryCommand = new MvxAsyncCommand(startTimeEntry, () => CurrentTimeEntryId.HasValue == false); }
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 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); }