public ProjectFilterPageViewModel( INavigationService navigationService, IProjectDataStore projectDataStore) : base(navigationService) { Title = "Filter"; Apply = ReactiveCommand.CreateFromTask(async() => { _filter.StartDate = _selectedStartDate; _filter.StartDateComparison = _selectedStartDateComparisonType; _filter.Trades.Clear(); _filter.Trades.AddRange(_selectedTrades); await NavigationService.GoBackAsync(new NavigationParameters { { "filter", _filter } }, useModalNavigation: true).ConfigureAwait(false); }); Cancel = ReactiveCommand.CreateFromTask(() => NavigationService.GoBackAsync(useModalNavigation: true)); NavigatedTo .Where(args => args.ContainsKey("filter")) .Take(1) .Select(args => (ProjectFilter)args["filter"]) .Subscribe(filter => _filter = filter); NavigatedTo .Where(args => args.ContainsKey("selected_items")) .Select(args => (IEnumerable <SelectionViewModel>)args["selected_items"]) .Subscribe(selections => _selectedTrades = selections.Select(x => x.Item).Cast <Trade>()); // begin loading the trade data var trades = projectDataStore.GetTradesAsync(); SelectTrades = ReactiveCommand.CreateFromTask(async() => { var args = new NavigationParameters(); args.Add( "items", (await trades).Select(specialty => new SelectionViewModel <Trade>(specialty) { DisplayValue = specialty.Name, IsSelected = _selectedTrades?.Contains(specialty) == true })); await NavigationService.NavigateAsync(nameof(MultiSelectListViewPage), args).ConfigureAwait(false); }); }
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 EditableProfilePageViewModel( INavigationService navigationService, IUserDialogs dialogService, IProjectDataStore projectDataStore, IPermissionsService permissionsService) : base(navigationService) { Title = "Edit Profile"; AddValidationRules(); NavigatedTo .Take(1) .Select(args => args["user"] as Account) .Subscribe(user => { // TODO: Handle null user, handle editing... }); ChangePhoto = ReactiveCommand.CreateFromTask(async() => { try { // check if permission has been granted to the photos var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Photos); if (status != PermissionStatus.Granted) { status = await permissionsService.CheckPermissionsAsync(Permission.Photos, dialogService); } // if permission was granted, open the photo picker if (status == PermissionStatus.Granted) { using (var file = await CrossMedia.Current.PickPhotoAsync(_pickOptions)) { if (file != null) { Photo = file.GetStream(); } } } else { // permission was not granted. Let the user know they can't pick a photo // without permissions await dialogService.AlertAsync( new AlertConfig { Title = "Photos Not Supported", Message = ":( Permission not granted to photos.", OkText = "OK" }).ConfigureAwait(false); return; } } catch (MediaPermissionException mediaException) { await dialogService.AlertAsync( new AlertConfig { Title = "Permission Error", Message = $"Permissions not granted: {string.Join(", ", mediaException.Permissions)}", OkText = "OK" }).ConfigureAwait(false); } catch (Exception ex) { // TODO: log the exception... await dialogService.AlertAsync( new AlertConfig { Title = "Error", Message = "An error has occurred.", OkText = "OK" }).ConfigureAwait(false); } }); Save = ReactiveCommand.CreateFromTask(async() => { // TODO:... }); Cancel = ReactiveCommand.CreateFromTask(async() => { await NavigationService.GoBackAsync(useModalNavigation: true).ConfigureAwait(false); }); SelectCommunities = ReactiveCommand.CreateFromTask(async() => { var args = new NavigationParameters(); args.Add( "items", (await projectDataStore.GetTradesAsync()).Select(specialty => new SelectionViewModel <Trade>(specialty) { DisplayValue = specialty.Name })); await NavigationService.NavigateAsync(nameof(MultiSelectListViewPage), args).ConfigureAwait(false); }); }
public TradeSpecialtiesPageViewModel( INavigationService navigationService, IUserDialogs dialogService, IContainerRegistry containerRegistry, IProjectDataStore projectDataStore) : base(navigationService) { Title = "Trade Specialties"; SelectAll = ReactiveCommand.Create(() => { foreach (var item in Items) { item.IsSelected = true; } }); SelectNone = ReactiveCommand.Create(() => { foreach (var item in Items) { item.IsSelected = false; } }); Next = ReactiveCommand.CreateFromTask(async() => { // if there are no items selected, they can't move on. Must select at least one specialty var selectedItems = Items.Where(item => item.IsSelected).Select(item => item.Item); if (!selectedItems.Any()) { await dialogService.AlertAsync( new AlertConfig { Title = "Error", Message = "You must select at least one trade specialty", OkText = "OK" }).ConfigureAwait(false); return; } if (_account is ContractorAccount contractor) { contractor.AccountTrades.Clear(); contractor.AccountTrades.AddRange( selectedItems.Select(item => new AccountTrade { AccountId = contractor.AccountId, TradeId = item.TradeId })); } // TODO: Save the account... containerRegistry.RegisterInstance <IUserService>(new UserService(_account)); await NavigationService.NavigateHomeAsync().ConfigureAwait(false); }); projectDataStore .GetTradesAsync() .ContinueWith(t => { // TODO: Handle failure? Items.AddRange( t.Result.Select( specialty => new SelectionViewModel <Trade>(specialty) { DisplayValue = specialty.Name })); }); NavigatingTo .Select(args => (Account)args["account"]) .Subscribe(user => { _account = user; }); }
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); }