public RegistrationTypeSelectionPageViewModel( INavigationService navigationService, IAnalyticService analyticService, IFirebaseAuthService authService, IUserDialogs dialogs) : base(navigationService) { Title = "Registration Type"; analyticService.TrackScreen("registration-type"); Tradesman = ReactiveCommand.CreateFromTask(async() => { await dialogs.AlertAsync("Coming Soon!").ConfigureAwait(false); analyticService.TrackTapEvent("register-as-tradesman"); //await navigationService.NavigateAsync(nameof(TradesmentRegistrationPage)).ConfigureAwait(false); }); Contractor = ReactiveCommand.CreateFromTask(async() => { analyticService.TrackTapEvent("register-as-contractor"); await navigationService.NavigateAsync( nameof(ContractorRegistrationPage), new NavigationParameters { { "user_id", _userId } }).ConfigureAwait(false); }); GoBack = ReactiveCommand.CreateFromTask <Unit, Unit>(async _ => { var result = await dialogs.ConfirmAsync( new ConfirmConfig { Title = "Cancel Account Creation?", Message = "Are you sure you want to cancel account creation? This will discard any information you have entered so far", OkText = "Yes", CancelText = "No" }); if (result) { analyticService.TrackTapEvent("cancel-account-creation"); // make sure we log out so the user has to log in again await authService.Logout(); await NavigationService.NavigateToLoginPageAsync().ConfigureAwait(false); } return(Unit.Default); }); NavigatingTo .Where(args => args.ContainsKey("user_id")) .Select(args => args["user_id"].ToString()) .BindTo(this, x => x._userId); }
public ContactUsPageViewModel( INavigationService navigationService, IAnalyticService analyticService, IUserService userService) : base(navigationService) { Title = "Contact Us"; analyticService.TrackScreen("contact-us-page"); AddValidationRules(); Submit = ReactiveCommand.CreateFromTask( async _ => { if (!IsValid()) { return; } analyticService.TrackTapEvent("submit"); var random = new Random(); await Task.Delay(random.Next(400, 2000)); await NavigationService.GoBackAsync(useModalNavigation: true).ConfigureAwait(false); }); Submit.IsExecuting .StartWith(false) .ToProperty(this, x => x.IsBusy, out _isBusy); NavigatingTo .Take(1) .Subscribe(_ => { Email.Value = userService.AuthenticatedUser.EmailAddress; }); }
public ProjectsPageViewModel( INavigationService navigationService, IProjectDataStore projectDataStore, IAnalyticService analyticService) : base(navigationService) { Title = "Projects"; this.WhenActivated((CompositeDisposable _) => { // track every time this screen is activated analyticService.TrackScreen("my-projects"); }); ViewProjectDetails = ReactiveCommand.CreateFromTask <Project, Unit>(async project => { analyticService.TrackTapEvent("view-project"); await NavigationService.NavigateAsync( nameof(ProjectDetailsPage), new NavigationParameters { { "project", project } }).ConfigureAwait(false); return(Unit.Default); }); AddProject = ReactiveCommand.CreateFromTask(async() => { analyticService.TrackTapEvent("new-project"); await NavigationService.NavigateAsync($"NavigationPage/{nameof(EditProjectPage)}", useModalNavigation: true).ConfigureAwait(false); }); Filter = ReactiveCommand.CreateFromTask(async() => { // TODO: Finish this await NavigationService.NavigateAsync( $"NavigationPage/{nameof(ProjectFilterPage)}", new NavigationParameters { { "filter", _filter } }, useModalNavigation: true).ConfigureAwait(false); }); // set up the command used to load projects LoadProjects = ReactiveCommand.CreateFromTask(_ => { this.Log().Debug($"Loading projects on thread: {Thread.CurrentThread.ManagedThreadId}, IsBackground = {Thread.CurrentThread.IsBackground}"); AssertRunningOnBackgroundThread(); return(projectDataStore.LoadOldProjects(_oldestProject, ItemsPerPage)); }); // set up the command used to refresh projects RefreshProjects = ReactiveCommand.CreateFromTask(_ => { // TODO: Should track this with analytics? this.Log().Debug($"Refreshing projects on thread: {Thread.CurrentThread.ManagedThreadId}, IsBackground = {Thread.CurrentThread.IsBackground}"); AssertRunningOnBackgroundThread(); return(_newestProject != null ? projectDataStore.LoadNewProjects(_newestProject, ItemsPerPage) : projectDataStore.LoadNewProjects(ItemsPerPage)); }); LoadProjects .Merge(RefreshProjects) .SubscribeSafe(projects => { if (projects.Any()) { // NOTE: This probably isn't necessary... projects = projects.ExceptBy(Projects, p => p.ProjectId); // get the oldest and newest projects from the new data set. Age is simply // determined by the date the project was created var oldProject = projects.MinBy(p => p.CreateDate).First(); var newProject = projects.MaxBy(p => p.CreateDate).First(); if (_oldestProject == null && _newestProject == null) { _oldestProject = oldProject; _newestProject = newProject; // first projects being added. Add them to the list Projects.AddRange(projects); } else if (_oldestProject?.CreateDate > oldProject.CreateDate) { _oldestProject = oldProject; // if the projects are older, add them to the end of the list Projects.AddRange(projects); } else if (_newestProject?.CreateDate < newProject.CreateDate) { _newestProject = newProject; // if the projects are newer, insert them at the beginning of the list Projects.InsertRange(0, projects); } } }); // when either of the commands are executing, update the busy state LoadProjects.IsExecuting .CombineLatest(RefreshProjects.IsExecuting, (isLoadExecuting, isRefreshExecuting) => isLoadExecuting || isRefreshExecuting) .DistinctUntilChanged() .StartWith(false) .ToProperty(this, x => x.IsBusy, out _isBusy, scheduler: RxApp.MainThreadScheduler); // When an exception is thrown for either command, log the error and let the user handle // the exception LoadProjects.ThrownExceptions .Merge(RefreshProjects.ThrownExceptions) .SelectMany(exception => { this.Log().ErrorException("Error loading or refreshing data", exception); return(SharedInteractions.Error.Handle(exception)); }) .Subscribe(); }
public EditProjectPageViewModel( INavigationService navigationService, IUserDialogs dialogService, IAnalyticService analyticService) : base(navigationService) { Title = "New Project"; analyticService.TrackScreen("edit-project-page"); // store the fields in an enumerable for easy use later on in this class _validatableFields = new IValidity[] { ProjectName, //StartStatus, Description, SkillsRequired, PayRate, //PaymentType }; AddValidationRules(); Save = ReactiveCommand.CreateFromTask(async() => { if (!IsValid()) { return; } analyticService.TrackTapEvent("save"); if (_project != null) { // if the product was being edited, map the local fields back to the project and // save it //_project.Name = ProjectName.Value; _project.Description = Description.Value; //_project.SkillsRequired = SkillsRequired.Value; //_project.PaymentRate = decimal.Parse(PayRate.Value); //_project.PaymentType = PaymentType.Value; //switch (StartStatus.Value) //{ // case ProjectStartStatus.ReadyNow: // _project.EstimatedStartDate = DateTime.Today; // break; // case ProjectStartStatus.OneToTwoWeeks: _project.EstimatedStartDate = // DateTime.Today.AddDays(7); break; // case ProjectStartStatus.ThreeToFourWeeks: _project.EstimatedStartDate = // DateTime.Today.AddDays(7 * 3); break; // case ProjectStartStatus.FiveOrMoreWeeks: _project.EstimatedStartDate = // DateTime.Today.AddDays(7 * 5); break; // default: // throw new InvalidOperationException("Invalid start status"); //} // TODO: projectDataStore.Update(_project); } else { // the project was a new project. Save it // TODO: projectDataStore.Save(_project); } // TODO: Return the project in the navigation parameters so we can refresh it in the UI of the calling page. await NavigationService.GoBackAsync(useModalNavigation: true).ConfigureAwait(false); }); Cancel = ReactiveCommand.CreateFromTask(async() => { if (_validatableFields.Any(field => field.IsChanged)) { bool keepEditing = await dialogService.ConfirmAsync( new ConfirmConfig { Title = "Unsaved changes", Message = "Are you sure you want to discard this project?", OkText = "Keep Editing", CancelText = "Discard" }); if (keepEditing) { // the user has chosen the option to continue editing return; } } analyticService.TrackTapEvent("cancel"); // if there are no changes, or the user chooses to discard, go back to the previous screen await NavigationService.GoBackAsync(useModalNavigation: true).ConfigureAwait(false); }); NavigatingTo .Take(1) .Where(args => args.ContainsKey("project")) .Select(args => (Project)args["project"]) .Subscribe(project => { // store the project being edited _project = project; Title = "Edit Project"; // map the project being edited to the local fields //ProjectName.Value = project.Name; //StartStatus.Value = project.StartStatus; Description.Value = project.Description; //SkillsRequired.Value = project.SkillsRequired; //PayRate.Value = project.PaymentRate.ToString(); //PaymentType.Value = project.PaymentType; // accept changes for all fields foreach (var field in _validatableFields) { field.AcceptChanges(); } }); // accept changes so we can determine whether they've been changed later on foreach (var field in _validatableFields) { field.AcceptChanges(); } }
public MyProjectsPageViewModel( INavigationService navigationService, IProjectDataStore projectDataStore, IUserDialogs dialogService, IUserService userService, IAnalyticService analyticService) : base(navigationService) { Title = "My Projects"; this.WhenActivated((CompositeDisposable _) => { // track every time this screen is activated analyticService.TrackScreen("my-projects"); }); var initialize = ReactiveCommand.CreateFromTask <Unit, IEnumerable <Project> >(_ => { AssertRunningOnBackgroundThread(); return(projectDataStore.LoadProjectsForUser(userService.AuthenticatedUser.AccountId)); }); initialize .Subscribe(projects => { Projects.Reset(projects.Select(proj => new MyProjectViewModel(proj, Delete, Close, Edit))); }); Projects.ActOnEveryObject( _ => { this.Log().Debug("Item added"); }, projViewModel => { this.Log().Debug("Item removed"); // make sure we dispose of the item to release the subscription from the item's // commands to our commands projViewModel.Dispose(); }); // When an exception is thrown while loading data, log the error and let the user handle // the exception initialize.ThrownExceptions .SelectMany(exception => { this.Log().ErrorException("Error loading or refreshing data", exception); return(SharedInteractions.Error.Handle(exception)); }) .Subscribe(); Activator .Activated .Take(1) .ObserveOn(RxApp.TaskpoolScheduler) .InvokeCommand(initialize); ViewProjectDetails = ReactiveCommand.CreateFromTask <MyProjectViewModel, Unit>(async project => { analyticService.TrackTapEvent("view-project"); await NavigationService.NavigateAsync( nameof(ProjectDetailsPage), new NavigationParameters { { "project", project.Project } }).ConfigureAwait(false); return(Unit.Default); }); Delete = ReactiveCommand.CreateFromTask <MyProjectViewModel, Unit>(async project => { bool shouldDelete = await dialogService.ConfirmAsync( new ConfirmConfig { Message = "Are you sure you want to delete the project?", OkText = "Delete", CancelText = "Cancel" }); if (!shouldDelete) { return(Unit.Default); } analyticService.TrackTapEvent("delete-project"); // remove the project await projectDataStore.DeleteProjectAsync(project.Project); Projects.Remove(project); dialogService.Toast(new ToastConfig("Project deleted successfully!")); return(Unit.Default); }); Close = ReactiveCommand.CreateFromTask <MyProjectViewModel, Unit>(async project => { bool shouldDelete = await dialogService.ConfirmAsync( new ConfirmConfig { Message = "Are you sure you want to close the project?", OkText = "Close", CancelText = "Cancel" }); if (!shouldDelete) { return(Unit.Default); } analyticService.TrackTapEvent("close-project"); //project.Project.Status = ProjectStatus.Closed; // TODO: Save to the database return(Unit.Default); }); Edit = ReactiveCommand.CreateFromTask <MyProjectViewModel, Unit>(async project => { analyticService.TrackTapEvent("edit-project"); await NavigationService.NavigateAsync( $"NavigationPage/{nameof(EditProjectPage)}", new NavigationParameters { { "project", project.Project } }, useModalNavigation: true).ConfigureAwait(false); return(Unit.Default); }); initialize.IsExecuting .StartWith(false) .ToProperty(this, x => x.IsBusy, out _isBusy, scheduler: RxApp.MainThreadScheduler); }