using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; using comal.timesheets.Tasks; using Comal.Classes; using InABox.Clients; using InABox.Configuration; using InABox.Core; using Xamarin.Forms; using Xamarin.Forms.Xaml; using XF.Material.Forms.UI; using XF.Material.Forms.UI.Dialogs; using Plugin.Media; using InABox.Mobile; using System.IO; using comal.timesheets.QAForms; using comal.timesheets.CustomControls; //using static Android.Provider.MediaStore; namespace comal.timesheets.Tasks { public delegate void TaskSavedEvent(int TaskNumber); [XamlCompilation(XamlCompilationOptions.Compile)] public partial class AddEditTask : ContentPage { public Kanban kanban = new Kanban(); bool newKanban = false; bool searching = false; bool displaying = false; List kanbanFormList = new List(); List observerList = new List(); Guid kanbanID = Guid.Empty; int estimatedTime; List imageList = new List(); Dictionary imagesourcedocs = new Dictionary(); public TaskSavedEvent OnTaskSaved; string kanbanTitle = ""; public AddEditTask(Guid selectedID = default(Guid), string title = "") { InitializeComponent(); kanbanID = selectedID; Title = "Loading"; AddToolBars(); kanbanTitle = title; if (selectedID == Guid.Empty) { NewKanbanTrack(); UpdateScreen(); } else { ExistingKanbanTrack(); } } #region OnAppearing and Screen Population protected override void OnAppearing() { base.OnAppearing(); searching = false; CheckForDigitalForms(); } private void NewKanbanTrack() { newKanban = true; kanban.DueDate = DateTime.Today; kanban.Category = "Open"; kanban.StartDate = DateTime.Today; kanban.EmployeeLink.ID = GlobalVariables.EmpID; kanban.ManagerLink.ID = GlobalVariables.EmpID; kanban.EmployeeLink.Name = GlobalVariables.EmpName; kanban.ManagerLink.Name = GlobalVariables.EmpName; kanban.Title = kanbanTitle; } private async void ExistingKanbanTrack() { await Task.Run(() => { try { kanban = new Client().Load( new Filter(x => x.ID).IsEqualTo(kanbanID)).FirstOrDefault(); } catch (ArgumentException e) when (kanban == null) { Device.BeginInvokeOnMainThread(() => { DisplayAlert("Error", "Failed to load from database", "Ok"); }); } UpdateImages(); UpdateScreen(); }); } private void AddToolBars() { NavigationPage.SetHasBackButton(this, false); ToolbarItems.Add(new ToolbarItem("Cancel", "", () => { Navigation.PopAsync(); })); ToolbarItems.Add(new ToolbarItem(" ", "", () => { //button added to create space on toolbar })); ToolbarItems.Add(new ToolbarItem("Save", "", () => { SubmitBtn_Clicked(); })); } public void UpdateScreen(bool lockTaskType = false) { Device.BeginInvokeOnMainThread(() => { if (newKanban) { Title = "New Task"; } else { Title = "Task " + kanban.Number; } titleEdt.Text = kanban.Title; jobNoLbl.Text = (kanban.JobLink.JobNumber + " " + kanban.JobLink.Name); descriptionEdt.Text = kanban.Summary; taskTypeLbl.Text = kanban.Type.Description; if (lockTaskType) taskTypeBtn.IsEnabled = false; assignedToLbl.Text = kanban.EmployeeLink.Name; allocatedByLbl.Text = kanban.ManagerLink.Name; categoryPck.SelectedIndex = chooseIndex(); dueDatePck.Date = kanban.DueDate; startDatePck.Date = kanban.StartDate; DisplayEstimatedTime(); DisplayObserverList(); if (kanban.Private) { privateCheckBox.IsChecked = true; } if (kanban.Locked) { categoryPck.IsEnabled = false; } }); } private async void CheckForDigitalForms() { if (newKanban) return; formsBtn.Text = "Checking"; await Task.Run(() => { kanbanFormList.Clear(); try { CoreTable table = new Client().Query( new Filter(x => x.Parent.ID).IsEqualTo(kanbanID), new Columns( x => x.ID, x => x.Parent.ID, x => x.Form.ID, x => x.Form.Description, x => x.Form.AppliesTo, x => x.Created, x => x.FormData, x => x.BlobData, x => x.FormCompleted, x => x.FormCompletedBy.ID, x => x.FormOpen, x => x.FormStarted ), new SortOrder(x => x.Created) ); if (table.Rows.Any()) { foreach (CoreRow row in table.Rows) { KanbanForm kanbanForm = row.ToObject(); kanbanFormList.Add(kanbanForm); } Device.BeginInvokeOnMainThread(() => { formsBtn.Text = "Forms"; formsBtn.IsEnabled = true; }); } else { Device.BeginInvokeOnMainThread(() => { formsBtn.Text = "Forms"; formsBtn.IsEnabled = true; }); } } catch { } }); } #endregion #region Fields Changed private void TitleEdt_Changed(object sender, EventArgs e) { kanban.Title = titleEdt.Text; } private void DescriptionEdt_Changed(object sender, EventArgs e) { kanban.Description = descriptionEdt.Text; } private void DueDatePck_Selected(object sender, EventArgs e) { kanban.DueDate = dueDatePck.Date; } private void StartDatePck_Selected(object sender, EventArgs e) { kanban.StartDate = startDatePck.Date; } private void JobNoBtn_Clicked(object sender, EventArgs e) { if (searching) return; else { searching = true; JobSelectionPage jobSelectionPage = new JobSelectionPage(); jobSelectionPage.OnItemSelected += (() => { kanban.JobLink.ID = jobSelectionPage.Job.ID; kanban.JobLink.Name = jobSelectionPage.Job.Name; kanban.JobLink.JobNumber = jobSelectionPage.Job.JobNumber; UpdateScreen(); }); Navigation.PushAsync(jobSelectionPage); } } private void TaskType_Clicked(object sender, EventArgs e) { if (searching) return; else { searching = true; GenericSelectionPage page = new GenericSelectionPage ( "Select Type", new SelectionViewModel ( new Filter(x => x.Hidden).IsEqualTo(false), new Expression>[] { x => x.Description }, new Expression>[] { x => x.Hidden }, new SortOrder(x => x.Description) )); page.OnItemSelected += (row) => { var kanbanType = row.ToObject(); kanban.Type.ID = kanbanType.ID; kanban.Type.Synchronise(kanbanType); UpdateScreen(); }; Navigation.PushAsync(page); } } private void AllocatedByBtn_Clicked(object sender, EventArgs e) { EmployeeSelectionPage employeeSelectionPage = new EmployeeSelectionPage(); employeeSelectionPage.OnItemSelected += (() => { kanban.ManagerLink.ID = employeeSelectionPage.employee.ID; kanban.ManagerLink.Name = employeeSelectionPage.employee.Name; UpdateScreen(); }); Navigation.PushAsync(employeeSelectionPage); } private void AssignedToBtn_Clicked(object sender, EventArgs e) { EmployeeSelectionPage employeeSelectionPage = new EmployeeSelectionPage(); employeeSelectionPage.OnItemSelected += (() => { kanban.EmployeeLink.ID = employeeSelectionPage.employee.ID; kanban.EmployeeLink.Name = employeeSelectionPage.employee.Name; UpdateScreen(); }); Navigation.PushAsync(employeeSelectionPage); } private void CheckPrivateChanged(object sender, CheckedChangedEventArgs e) { if (privateCheckBox.IsChecked) { Employee employee = new Employee(); var table = new Client().Query(new Filter(x => x.UserID).IsEqualTo(ClientFactory.UserGuid)); foreach (CoreRow row in table.Rows) { employee = row.ToObject(); } kanban.ManagerLink.ID = employee.ID; kanban.ManagerLink.Synchronise(employee); kanban.EmployeeLink.ID = employee.ID; kanban.EmployeeLink.Synchronise(employee); kanban.Private = true; assignedToBtn.IsEnabled = false; allocatedByBtn.IsEnabled = false; UpdateScreen(); } if (!privateCheckBox.IsChecked) { kanban.Private = false; assignedToBtn.IsEnabled = true; allocatedByBtn.IsEnabled = true; } } private void category_Changed(object sender, EventArgs e) { if (categoryPck.SelectedIndex == 0) { kanban.Category = "Open"; } if (categoryPck.SelectedIndex == 1) { kanban.Category = "In Progress"; } if (categoryPck.SelectedIndex == 2) { kanban.Category = "Waiting"; } if (categoryPck.SelectedIndex == 3) { kanban.Category = "Complete"; } } private int chooseIndex() { int indexNo = -1; if (kanban.Category != null) { if (kanban.Category.Equals("Open")) { indexNo = 0; } if (kanban.Category.Equals("In Progress")) { indexNo = 1; } if (kanban.Category.Equals("Waiting")) { indexNo = 2; } if (kanban.Category.Equals("Complete")) { indexNo = 3; } } return indexNo; } #endregion #region Estimated Time private void DecreaseBtn_Clicked(object sender, EventArgs e) { if (estimatedTime == 0 || estimatedTime < 0) return; else { estimatedTime = estimatedTime - 15; kanban.EstimatedTime = new TimeSpan(0, estimatedTime, 0); DisplayEstimatedTime(); } } private void IncreaseBtn_Clicked(object sender, EventArgs e) { estimatedTime = estimatedTime + 15; kanban.EstimatedTime = new TimeSpan(0, estimatedTime, 0); DisplayEstimatedTime(); } private void EstimatedHoursEdt_Changed(object sender, EventArgs e) { if (displaying) return; else CalculateEstimatedTime(); } private void EstimatedMinsEdt_Changed(object sender, EventArgs e) { if (displaying) return; else CalculateEstimatedTime(); } private async void CalculateEstimatedTime() //to timespan { try { int minutes = 0; int hours = 0; if (!string.IsNullOrWhiteSpace(estimatedHoursEdt.Text)) { hours = Convert.ToInt32(estimatedHoursEdt.Text); } if (!string.IsNullOrWhiteSpace(estimatedMinsEdt.Text)) { minutes = Convert.ToInt32(estimatedMinsEdt.Text); } kanban.EstimatedTime = new TimeSpan(hours, minutes, 0); estimatedTime = Convert.ToInt32(kanban.EstimatedTime.TotalMinutes); } catch { await DisplayAlert("Error", "Only whole numbers for estimated time fields", "OK"); int isNumber; if (!int.TryParse(estimatedHoursEdt.Text, out isNumber)) { estimatedHoursEdt.Text = "0"; }; if (!int.TryParse(estimatedMinsEdt.Text, out isNumber)) { estimatedMinsEdt.Text = "0"; }; } } private async void DisplayEstimatedTime() //from timespan { await Task.Run(() => { displaying = true; estimatedTime = Convert.ToInt32(kanban.EstimatedTime.TotalMinutes); int hours = estimatedTime / 60; int minutes = estimatedTime % 60; Device.BeginInvokeOnMainThread(() => { estimatedHoursEdt.Text = hours.ToString(); estimatedMinsEdt.Text = minutes.ToString(); displaying = false; }); }); } #endregion #region Display or add images private async void UpdateImages() { try { Device.BeginInvokeOnMainThread(async () => { if (kanban.Attachments != 0) { int count = kanban.Attachments; photosLbl.TextColor = Color.Orange; photosLbl.Text = "Loading " + kanban.Attachments + " Photos"; await Task.Run(() => { var table = new Client().Query( new Filter(x => x.EntityLink.ID).IsEqualTo(kanban.ID), new Columns(x => x.DocumentLink.ID), null ); if (table.Rows.Count != 0) { foreach (var row in table.Rows) { List list = row.Values; if (list[0] == null) { list[0] = Guid.Empty; } Guid kanbanDocLinkID = Guid.Parse(list[0].ToString()); new Client().Query( new Filter(x => x.ID).IsEqualTo(kanbanDocLinkID), null, null, (t, e) => { CoreRow docrow = t.Rows.FirstOrDefault(); if (docrow != null) { byte[] data = docrow.Get(x => x.Data); ImageSource src = ImageSource.FromStream(() => new MemoryStream(data)); Image img = new Image(); img.HeightRequest = 150; img.WidthRequest = 150; img.Aspect = Aspect.AspectFit; img.Source = src; img.GestureRecognizers.Add(new TapGestureRecognizer { Command = new Command(OnTap), CommandParameter = src, NumberOfTapsRequired = 1 }); imageList.Add(img); Device.BeginInvokeOnMainThread(() => { ImageScroller.IsVisible = true; images.Children.Add(img); count = count - 1; photosLbl.Text = "Loading " + count + " Photo(s)"; if (count == 0) { photosLbl.Text = "Photos"; photosLbl.TextColor = Color.Default; } }); } } ); } } }); } }); } catch { } } private void OnTap(object obj) { ImageViewerEditor imageViewEditor = new ImageViewerEditor(obj as ImageSource); imageViewEditor.OnSaveSelected += (byte[] array) => { try { Image img = imageList.Find(x => x.Source.Equals(obj as ImageSource)); imageList.Remove(img); imagesourcedocs.Remove(obj as ImageSource); } catch { } DataToImage(array); }; Navigation.PushAsync(imageViewEditor); } public void DataToImage(byte[] data) { try { ImageSource src = ImageSource.FromStream(() => new MemoryStream(data)); Image img = new Image(); img.HeightRequest = 150; img.WidthRequest = 150; img.Aspect = Aspect.AspectFit; img.VerticalOptions = LayoutOptions.FillAndExpand; img.HorizontalOptions = LayoutOptions.FillAndExpand; img.Source = src; img.GestureRecognizers.Add(new TapGestureRecognizer { Command = new Command(OnTap), CommandParameter = src, NumberOfTapsRequired = 1 }); if (img != null) { imageList.Add(img); RefreshView(); } String filename = String.Format("{0:yyyy-MM-dd HH:mm:ss.fff}.png", DateTime.Now); Document doc = new Document() { FileName = filename, Data = data, CRC = CoreUtils.CalculateCRC(data), TimeStamp = DateTime.Now }; imagesourcedocs.Add(src, doc); } catch { } } private void RefreshView() { Device.BeginInvokeOnMainThread(() => { images.Children.Clear(); foreach (Image img in imageList) { images.Children.Add(img); } }); } async void TakePhoto_Clicked(object sender, EventArgs e) { try { await CrossMedia.Current.Initialize(); if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported) { await DisplayAlert("No Camera", ":( No camera available.", "OK"); return; } String filename = String.Format("{0:yyyy-MM-dd HH:mm:ss.fff}.png", DateTime.Now); var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions { Name = filename, CompressionQuality = 10, PhotoSize = Plugin.Media.Abstractions.PhotoSize.Full }); if (file == null) return; using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Adding Photo")) { Image img = null; var memoryStream = new MemoryStream(); file.GetStream().CopyTo(memoryStream); var data = memoryStream.ToArray(); Document doc = new Document() { FileName = filename, Data = data, CRC = CoreUtils.CalculateCRC(data), TimeStamp = DateTime.Now }; ImageSource src = ImageSource.FromStream(() => new MemoryStream(data)); imagesourcedocs.Add(src, doc); img = new Image(); img.HeightRequest = 150; img.WidthRequest = 150; img.Aspect = Aspect.AspectFit; img.Source = src; img.GestureRecognizers.Add(new TapGestureRecognizer { Command = new Command(OnTap), CommandParameter = src, NumberOfTapsRequired = 1 }); file.Dispose(); if (img != null) { Device.BeginInvokeOnMainThread(() => { ImageScroller.IsVisible = true; images.Children.Add(img); }); } await pageScroller.ScrollToAsync(photoFrame, ScrollToPosition.Center, false); } } catch { } } async void ChooseImage_Clicked(object sender, EventArgs e) { try { await CrossMedia.Current.Initialize(); if (!CrossMedia.Current.IsPickPhotoSupported) { await DisplayAlert("No Library", ":( No Photo Library available.", "OK"); return; } var file = await CrossMedia.Current.PickPhotoAsync(new Plugin.Media.Abstractions.PickMediaOptions() { CompressionQuality = 10, PhotoSize = Plugin.Media.Abstractions.PhotoSize.Full }); if (file == null) return; using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Adding Photo")) { Image img = null; var memoryStream = new MemoryStream(); file.GetStream().CopyTo(memoryStream); var data = memoryStream.ToArray(); Document doc = new Document() { FileName = Path.GetFileName(file.Path), Data = data, CRC = CoreUtils.CalculateCRC(data), TimeStamp = DateTime.Now }; ImageSource src = ImageSource.FromStream(() => new MemoryStream(data)); imagesourcedocs.Add(src, doc); img = new Image(); img.HeightRequest = 150; img.WidthRequest = 150; img.Aspect = Aspect.AspectFit; img.Source = src; img.GestureRecognizers.Add(new TapGestureRecognizer { Command = new Command(OnTap), CommandParameter = src, NumberOfTapsRequired = 1 }); file.Dispose(); if (img != null) { Device.BeginInvokeOnMainThread(() => { ImageScroller.IsVisible = true; images.Children.Add(img); }); } await pageScroller.ScrollToAsync(photoFrame, ScrollToPosition.Center, false); } } catch { } } #endregion #region Digital Forms private async void Forms_Clicked(object sender, EventArgs e) { try { string chosenOptionOne = ""; if (kanbanFormList.Count == 0) { chosenOptionOne = await DisplayActionSheet("Choose An Option", "Cancel", null, "Add Form to Task"); } else if (kanbanFormList.Count > 0) { chosenOptionOne = await DisplayActionSheet("Choose An Option", "Cancel", null, "Add Form to Task", "View Completed Form (s)"); } switch (chosenOptionOne) { case "Cancel": return; case "Add Form to Task": DigitalFormsPicker digitalFormPicker = new DigitalFormsPicker(kanban); Navigation.PushAsync(digitalFormPicker); break; case "View Completed Form (s)": ChooseForm(); break; default: break; } } catch { } } private async void ChooseForm() { try { string chosenOption = ""; List formDescriptions = new List(); Dictionary pairs = new Dictionary(); foreach (KanbanForm kanbanForm in kanbanFormList) { string formDescription = kanbanForm.Form.Description + " Created " + kanbanForm.Created.ToString("hh:mm:ss tt - dd MMM yy"); formDescriptions.Add(formDescription); pairs.Add(kanbanForm, formDescription); } string[] array = pairs.Values.ToArray(); chosenOption = await DisplayActionSheet("Choose An Option", "Cancel", null, array); if (!string.IsNullOrEmpty(chosenOption)) { if (chosenOption != "Cancel") { KanbanForm form = pairs.FirstOrDefault(x => x.Value == chosenOption).Key; CoreTable table = new Client().Query( new Filter(x => x.Type).IsEqualTo(DFLayoutType.Mobile).And(x => x.Active).IsEqualTo(true).And(x => x.Form.Description).IsEqualTo(form.Form.Description), new Columns(x => x.Description, x => x.ID, x => x.Code, x => x.Form.AppliesTo, x => x.Form.ID, x => x.Layout), new SortOrder(x => x.Description) ); CoreRow row = table.Rows.FirstOrDefault(); DigitalFormLayout layout = row.ToObject(); //if (form.FormCompleted == DateTime.MinValue) //{ // QAFormHost digitalFormHost = new QAFormHost(layout, form, false); // Navigation.PushAsync(digitalFormHost); //} //else //{ // QAFormHost digitalFormHost = new QAFormHost(layout, form, true); // Navigation.PushAsync(digitalFormHost); //} } } } catch { } } #endregion #region Submit btn + photos save async void SubmitBtn_Clicked() { try { if (searching) return; else { searching = true; using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Saving")) { new Client().Save(kanban, "Updated From Mobile Device"); if (imagesourcedocs.Values.Count != 0) { new Client().Save(imagesourcedocs.Values, "Photo Taken on Device"); } var task = Task.Run(() => { SaveSubscribers(); }); SavePhotos(); } string successMessage = "Task number : " + kanban.Number + System.Environment.NewLine + "New Photo(s): " + imagesourcedocs.Values.Count; await DisplayAlert("Success", successMessage, "OK"); OnTaskSaved?.Invoke(kanban.Number); await Navigation.PopAsync(); } } catch (Exception ex) { DisplayAlert("Error saving", ex.Message, "OK"); } } private async void SavePhotos() { try { if (imagesourcedocs.Values.Count != 0) { ObservableList newKanbanDocuments = new ObservableList(); foreach (Document doc in imagesourcedocs.Values) { var kanbanDocument = new KanbanDocument(); kanbanDocument.EntityLink.ID = kanban.ID; kanbanDocument.DocumentLink.ID = doc.ID; kanbanDocument.DocumentLink.FileName = doc.FileName; newKanbanDocuments.Add(kanbanDocument); } Task.Run(() => { new Client().Save(newKanbanDocuments, "Photo Taken on Device"); }); } } catch { } } #endregion #region Subscribers Buttons / Functionality private async void DisplayObserverList() { try { await Task.Run(() => { if (!newKanban) { CoreTable table = new Client().Query( new Filter(x => x.Kanban.ID).IsEqualTo(kanban.ID).And(x => x.Observer).IsEqualTo(true) ); foreach (CoreRow row in table.Rows) { KanbanSubscriber subscriber = row.ToObject(); if (!subscriber.Manager && !subscriber.Assignee) { observerList.Add(subscriber); AddSubscriberLabel(subscriber); } } } }); } catch { } } private void AddSubscriberLabel(KanbanSubscriber subscriber) { Label label = new Label(); label.Text = subscriber.Employee.Name; label.FontSize = Device.GetNamedSize(NamedSize.Medium, label); label.Margin = 5; label.HorizontalTextAlignment = TextAlignment.Start; label.VerticalTextAlignment = TextAlignment.Center; Device.BeginInvokeOnMainThread(() => { observerStackLayout.Children.Add(label); }); } private async void AddSubscriberBtn_Clicked(object sender, EventArgs e) { string chosenOption = await DisplayActionSheet("Add", "Cancel", null, "Person", "Team"); switch (chosenOption) { case "Cancel": break; case "Person": SelectEmployeeForSubscriber(); break; case "Team": SelectTeamForSubscriber(); break; default: break; } } private void SelectEmployeeForSubscriber() { EmployeeSelectionPage employeeSelectionPage = new EmployeeSelectionPage(); employeeSelectionPage.OnItemSelected += (() => { KanbanSubscriber subscriber = new KanbanSubscriber(); subscriber.Kanban.ID = kanban.ID; subscriber.Observer = true; subscriber.Employee.ID = employeeSelectionPage.employee.ID; subscriber.Employee.Name = employeeSelectionPage.employee.Name; CheckListAndAddSubscriber(subscriber); }); Navigation.PushAsync(employeeSelectionPage); } private async void SelectTeamForSubscriber() { string[] array = GlobalVariables.TeamNames.ToArray(); string chosenTeam = await DisplayActionSheet("Choose Team", "Cancel", null, array); switch (chosenTeam) { case "Cancel": return; break; } if (!string.IsNullOrWhiteSpace(chosenTeam)) { List employees = GlobalVariables.TeamEmployeeShells.Where(x => x.TeamName == chosenTeam).ToList(); foreach (EmployeeShell employee in employees) { KanbanSubscriber subscriber = new KanbanSubscriber(); subscriber.Kanban.ID = kanban.ID; subscriber.Employee.ID = employee.ID; subscriber.Employee.Name = employee.Name; subscriber.Observer = true; CheckListAndAddSubscriber(subscriber); } } } private void CheckListAndAddSubscriber(KanbanSubscriber subscriber) { List guids = new List(); foreach (KanbanSubscriber sub in observerList) { guids.Add(sub.Employee.ID); } if (!guids.Contains(subscriber.Employee.ID)) { if (subscriber.Employee.ID != kanban.EmployeeLink.ID) { if (subscriber.Employee.ID != kanban.ManagerLink.ID) { observerList.Add(subscriber); AddSubscriberLabel(subscriber); } } } } private async void RemoveSubscriberBtn_Clicked(object sender, EventArgs e) { try { Dictionary nameSubscriberPairs = new Dictionary(); foreach (KanbanSubscriber subscriber in observerList) { nameSubscriberPairs.Add(subscriber.Employee.Name, subscriber); } string[] array = nameSubscriberPairs.Keys.ToArray(); string chosenOption = await DisplayActionSheet("Remove", "Cancel", null, array); if (chosenOption == "Cancel" || string.IsNullOrWhiteSpace(chosenOption)) { return; } else { KanbanSubscriber subscriber = nameSubscriberPairs[chosenOption]; observerList.Remove(subscriber); observerStackLayout.Children.Clear(); foreach (KanbanSubscriber sub in observerList) { AddSubscriberLabel(sub); } } } catch { } } #endregion #region Subscribers Saving private void SaveSubscribers() { Task.Run(() => { if (newKanban) { SaveNewSubs(); } else { SaveExistingSubs(); } }); } private void SaveNewSubs() { try { List subscribers = new List(); KanbanSubscriber sub = null; if (kanban.EmployeeLink.ID != Guid.Empty) { sub = new KanbanSubscriber(); sub.Kanban.ID = kanban.ID; sub.Employee.ID = kanban.EmployeeLink.ID; sub.Assignee = true; if (kanban.EmployeeLink.ID == kanban.ManagerLink.ID) { sub.Manager = true; } subscribers.Add(sub); } if (kanban.ManagerLink.ID != Guid.Empty) { if (kanban.ManagerLink.ID != kanban.EmployeeLink.ID) { sub = new KanbanSubscriber(); sub.Kanban.ID = kanban.ID; sub.Employee.ID = kanban.ManagerLink.ID; sub.Manager = true; subscribers.Add(sub); } } foreach (KanbanSubscriber subscriber in observerList) { subscriber.Kanban.ID = kanban.ID; subscribers.Add(subscriber); } new Client().Save(subscribers, ""); } catch { } } private void SaveExistingSubs() { try { KanbanSubscriber oldAssignee = new KanbanSubscriber(); KanbanSubscriber oldManager = new KanbanSubscriber(); KanbanSubscriber oldBoth = new KanbanSubscriber(); List oldObservers = new List(); List subscribersToDelete = new List(); List subscribersToSave = new List(); List subscribers = new List(); CoreTable table = new Client().Query( new Filter(x => x.Kanban.ID).IsEqualTo(kanban.ID) ); foreach (CoreRow row in table.Rows) { KanbanSubscriber subscriber = row.ToObject(); if (subscriber.Assignee && subscriber.Manager) { oldBoth = subscriber; } else { if (subscriber.Assignee) { oldAssignee = subscriber; } else if (subscriber.Manager) { oldManager = subscriber; } else if (subscriber.Observer) { oldObservers.Add(subscriber); } } } if (kanban.ManagerLink.ID == kanban.EmployeeLink.ID) { if (kanban.ManagerLink.ID != oldBoth.Employee.ID && oldBoth.Employee.ID != Guid.Empty) { subscribersToDelete.Add(oldBoth); KanbanSubscriber subscriber = new KanbanSubscriber(); subscriber.Assignee = true; subscriber.Manager = true; subscriber.Kanban.ID = kanban.ID; subscriber.Employee.ID = kanban.EmployeeLink.ID; subscribersToSave.Add(subscriber); } } if (oldAssignee.Employee.ID != kanban.EmployeeLink.ID && oldAssignee.Employee.ID != Guid.Empty) { subscribersToDelete.Add(oldAssignee); KanbanSubscriber subscriber = new KanbanSubscriber(); subscriber.Assignee = true; subscriber.Manager = false; subscriber.Kanban.ID = kanban.ID; subscriber.Employee.ID = kanban.EmployeeLink.ID; subscribersToSave.Add(subscriber); } if (oldManager.Employee.ID != kanban.ManagerLink.ID && oldManager.Employee.ID != Guid.Empty) { subscribersToDelete.Add(oldManager); KanbanSubscriber subscriber = new KanbanSubscriber(); subscriber.Assignee = false; subscriber.Manager = true; subscriber.Kanban.ID = kanban.ID; subscriber.Employee.ID = kanban.ManagerLink.ID; subscribersToSave.Add(subscriber); } List oldGuids = new List(); List newGuids = new List(); foreach (KanbanSubscriber sub in observerList) { newGuids.Add(sub.Employee.ID); } foreach (KanbanSubscriber sub in oldObservers) { oldGuids.Add(sub.Employee.ID); if (!newGuids.Contains(sub.Employee.ID)) { subscribersToDelete.Add(sub); } } foreach (KanbanSubscriber sub in observerList) { if (!oldGuids.Contains(sub.Employee.ID)) { subscribersToSave.Add(sub); } } new Client().Save(subscribersToSave, "Updated from mobile device"); new Client().Delete(subscribersToDelete, "Updated from mobile device"); } catch { } } #endregion } }