AddEditTask.xaml.cs 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.ComponentModel;
  5. using System.Linq;
  6. using System.Linq.Expressions;
  7. using System.Threading.Tasks;
  8. using comal.timesheets.Tasks;
  9. using Comal.Classes;
  10. using InABox.Clients;
  11. using InABox.Configuration;
  12. using InABox.Core;
  13. using Xamarin.Forms;
  14. using Xamarin.Forms.Xaml;
  15. using XF.Material.Forms.UI;
  16. using XF.Material.Forms.UI.Dialogs;
  17. using Plugin.Media;
  18. using InABox.Mobile;
  19. using System.IO;
  20. using comal.timesheets.QAForms;
  21. using comal.timesheets.CustomControls;
  22. using PRSSecurity = InABox.Core.Security;
  23. using Xamarin.Essentials;
  24. namespace comal.timesheets.Tasks
  25. {
  26. public delegate void TaskSavedEvent(int TaskNumber);
  27. [XamlCompilation(XamlCompilationOptions.Compile)]
  28. public partial class AddEditTask : ContentPage
  29. {
  30. public Kanban kanban = new Kanban();
  31. bool newKanban = false;
  32. bool searching = false;
  33. bool displaying = false;
  34. List<KanbanForm> kanbanFormList = new List<KanbanForm>();
  35. List<KanbanSubscriber> observerList = new List<KanbanSubscriber>();
  36. Guid kanbanID = Guid.Empty;
  37. int estimatedTime;
  38. List<Image> imageList = new List<Image>();
  39. Dictionary<ImageSource, Document> imagesourcedocs = new Dictionary<ImageSource, Document>();
  40. public TaskSavedEvent OnTaskSaved;
  41. string kanbanTitle = "";
  42. public AddEditTask(Guid selectedID = default(Guid), string title = "")
  43. {
  44. InitializeComponent();
  45. kanbanID = selectedID;
  46. Title = "Loading";
  47. AddToolBars();
  48. kanbanTitle = title;
  49. if (selectedID == Guid.Empty)
  50. {
  51. NewKanbanTrack();
  52. UpdateScreen();
  53. }
  54. else
  55. {
  56. ExistingKanbanTrack();
  57. if (PRSSecurity.IsAllowed<CanShareTaskDetails>())
  58. shareBtn.IsVisible = true;
  59. }
  60. }
  61. #region OnAppearing and Screen Population
  62. protected override void OnAppearing()
  63. {
  64. base.OnAppearing();
  65. searching = false;
  66. CheckForDigitalForms();
  67. }
  68. private void NewKanbanTrack()
  69. {
  70. newKanban = true;
  71. kanban.DueDate = DateTime.Today;
  72. kanban.Category = "Open";
  73. kanban.StartDate = DateTime.Today;
  74. kanban.EmployeeLink.ID = GlobalVariables.EmpID;
  75. kanban.ManagerLink.ID = GlobalVariables.EmpID;
  76. kanban.EmployeeLink.Name = GlobalVariables.EmpName;
  77. kanban.ManagerLink.Name = GlobalVariables.EmpName;
  78. kanban.Title = kanbanTitle;
  79. }
  80. private void ExistingKanbanTrack()
  81. {
  82. Task.Run(() =>
  83. {
  84. CoreTable table = QueryKanban();
  85. while (table == null)
  86. table = QueryKanban();
  87. kanban = table.Rows.FirstOrDefault().ToObject<Kanban>();
  88. UpdateImages();
  89. UpdateScreen();
  90. });
  91. }
  92. private CoreTable QueryKanban()
  93. {
  94. try
  95. {
  96. return new Client<Kanban>().Query(
  97. new Filter<Kanban>(x => x.ID).IsEqualTo(kanbanID),
  98. new Columns<Kanban>(
  99. x => x.ID,
  100. x => x.Title,
  101. x => x.Category,
  102. x => x.StartDate,
  103. x => x.Number,
  104. x => x.Notes,
  105. x => x.DueDate,
  106. x => x.JobLink.ID,
  107. x => x.JobLink.Name,
  108. x => x.JobLink.JobNumber,
  109. x => x.Private,
  110. x => x.Description,
  111. x => x.Summary,
  112. x => x.Type.Description,
  113. x => x.EmployeeLink.ID,
  114. x => x.EmployeeLink.Name,
  115. x => x.EmployeeLink.Code,
  116. x => x.ManagerLink.ID,
  117. x => x.ManagerLink.Name,
  118. x => x.ManagerLink.Code,
  119. x => x.EstimatedTime,
  120. x => x.Completed,
  121. x => x.ActualTime,
  122. x => x.Locked,
  123. x => x.Closed,
  124. x => x.Attachments,
  125. x => x.Delivery.ID
  126. )
  127. );
  128. }
  129. catch (Exception ex)
  130. {
  131. var log = new MobileLogging(LogType.Query, "QueryKanban()", ex.Message + ex.StackTrace, this.GetType().Name);
  132. return null;
  133. }
  134. }
  135. private void AddToolBars()
  136. {
  137. NavigationPage.SetHasBackButton(this, false);
  138. ToolbarItems.Add(new ToolbarItem("Cancel", "", () =>
  139. {
  140. Navigation.PopAsync();
  141. }));
  142. ToolbarItems.Add(new ToolbarItem(" ", "", () =>
  143. {
  144. //button added to create space on toolbar
  145. }));
  146. ToolbarItems.Add(new ToolbarItem("Save", "", () =>
  147. {
  148. SubmitBtn_Clicked();
  149. }));
  150. }
  151. public void UpdateScreen(bool lockTaskType = false)
  152. {
  153. Device.BeginInvokeOnMainThread(() =>
  154. {
  155. if (newKanban)
  156. {
  157. Title = "New Task";
  158. }
  159. else
  160. {
  161. Title = "Task " + kanban.Number;
  162. }
  163. titleEdt.Text = kanban.Title;
  164. jobNoLbl.Text = (kanban.JobLink.JobNumber + " " + kanban.JobLink.Name);
  165. descriptionEdt.Text = kanban.Summary;
  166. descriptionEdt.IsEnabled = kanban.ID == Guid.Empty ? true : false;
  167. existingNotesLbl.Text = BuildNotes(kanban.Notes);
  168. taskTypeLbl.Text = kanban.Type.Description;
  169. if (lockTaskType)
  170. taskTypeBtn.IsEnabled = false;
  171. assignedToLbl.Text = kanban.EmployeeLink.Name;
  172. allocatedByLbl.Text = kanban.ManagerLink.Name;
  173. categoryPck.SelectedIndex = chooseIndex();
  174. dueDatePck.Date = kanban.DueDate;
  175. startDatePck.Date = kanban.StartDate;
  176. DisplayEstimatedTime();
  177. DisplayObserverList();
  178. if (kanban.Private)
  179. {
  180. privateCheckBox.IsChecked = true;
  181. }
  182. if (kanban.Locked)
  183. {
  184. categoryPck.IsEnabled = false;
  185. }
  186. });
  187. }
  188. private string BuildNotes(string[] notes)
  189. {
  190. string result = "";
  191. foreach (string note in notes)
  192. result = result + note + System.Environment.NewLine;
  193. return result;
  194. }
  195. private void AddNotes_Clicked(object sender, EventArgs e)
  196. {
  197. if (kanban.Notes.Count() == 0)
  198. {
  199. kanban.Notes = new string[] { DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " " + GlobalVariables.EmpName + ": " + notesEdt.Text };
  200. notesEdt.Text = "";
  201. }
  202. else
  203. {
  204. var list = kanban.Notes.ToList();
  205. list.Add("===================================");
  206. list.Add(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " " + GlobalVariables.EmpName + ": " + notesEdt.Text);
  207. kanban.Notes = list.ToArray();
  208. notesEdt.Text = "";
  209. }
  210. UpdateScreen();
  211. }
  212. private void NotesEdt_TextChanged(object sender, EventArgs e)
  213. {
  214. addNotesBtn.IsEnabled = string.IsNullOrWhiteSpace(notesEdt.Text) ? false : true;
  215. }
  216. private async void CheckForDigitalForms()
  217. {
  218. if (newKanban) return;
  219. formsBtn.Text = "Checking";
  220. await Task.Run(() =>
  221. {
  222. kanbanFormList.Clear();
  223. try
  224. {
  225. CoreTable table = QueryKanbanForms();
  226. while (table == null)
  227. table = QueryKanbanForms();
  228. if (table.Rows.Any())
  229. {
  230. foreach (CoreRow row in table.Rows)
  231. {
  232. KanbanForm kanbanForm = row.ToObject<KanbanForm>();
  233. kanbanFormList.Add(kanbanForm);
  234. }
  235. Device.BeginInvokeOnMainThread(() =>
  236. {
  237. formsBtn.Text = "Forms";
  238. formsBtn.IsEnabled = true;
  239. });
  240. }
  241. else
  242. {
  243. Device.BeginInvokeOnMainThread(() =>
  244. {
  245. formsBtn.Text = "Forms";
  246. formsBtn.IsEnabled = true;
  247. });
  248. }
  249. }
  250. catch
  251. { }
  252. });
  253. }
  254. private CoreTable QueryKanbanForms()
  255. {
  256. try
  257. {
  258. return new Client<KanbanForm>().Query(
  259. new Filter<KanbanForm>(x => x.Parent.ID).IsEqualTo(kanbanID),
  260. new Columns<KanbanForm>(
  261. x => x.ID,
  262. x => x.Parent.ID,
  263. x => x.Form.ID,
  264. x => x.Form.Description,
  265. x => x.Form.AppliesTo,
  266. x => x.Created,
  267. x => x.FormData,
  268. x => x.BlobData,
  269. x => x.FormCompleted,
  270. x => x.FormCompletedBy.ID,
  271. x => x.FormCompletedBy.UserID,
  272. x => x.FormOpen,
  273. x => x.FormStarted
  274. ),
  275. new SortOrder<KanbanForm>(x => x.Created)
  276. );
  277. }
  278. catch (Exception ex)
  279. {
  280. var log = new MobileLogging(LogType.Query, "QueryKanbanForms()", ex.Message + ex.StackTrace, this.GetType().Name);
  281. return null;
  282. }
  283. }
  284. #endregion
  285. #region Fields Changed
  286. private async void ShareBtn_Clicked(object sender, EventArgs e)
  287. {
  288. try
  289. {
  290. CoreTable table = QueryKanban();
  291. while (table == null)
  292. table = QueryKanban();
  293. if (table.Rows.Any())
  294. {
  295. var detail = KanbanGrid.GenerateDetail(table.Rows.First());
  296. var message = new EmailMessage
  297. {
  298. Subject = "Task Details shared from: " + GlobalVariables.EmpName,
  299. Body = detail,
  300. };
  301. await Xamarin.Essentials.Email.ComposeAsync(message);
  302. }
  303. }
  304. catch { }
  305. }
  306. private void TitleEdt_Changed(object sender, EventArgs e)
  307. {
  308. kanban.Title = titleEdt.Text;
  309. }
  310. private void DescriptionEdt_Changed(object sender, EventArgs e)
  311. {
  312. kanban.Description = descriptionEdt.Text;
  313. }
  314. private void DueDatePck_Selected(object sender, EventArgs e)
  315. {
  316. kanban.DueDate = dueDatePck.Date;
  317. }
  318. private void StartDatePck_Selected(object sender, EventArgs e)
  319. {
  320. kanban.StartDate = startDatePck.Date;
  321. }
  322. private void JobNoBtn_Clicked(object sender, EventArgs e)
  323. {
  324. if (searching)
  325. return;
  326. else
  327. {
  328. searching = true;
  329. JobSelectionPage jobSelectionPage = new JobSelectionPage();
  330. jobSelectionPage.OnItemSelected += (() =>
  331. {
  332. kanban.JobLink.ID = jobSelectionPage.Job.ID;
  333. kanban.JobLink.Name = jobSelectionPage.Job.Name;
  334. kanban.JobLink.JobNumber = jobSelectionPage.Job.JobNumber;
  335. UpdateScreen();
  336. });
  337. Navigation.PushAsync(jobSelectionPage);
  338. }
  339. }
  340. private void TaskType_Clicked(object sender, EventArgs e)
  341. {
  342. if (searching)
  343. return;
  344. else
  345. {
  346. searching = true;
  347. GenericSelectionPage page = new GenericSelectionPage
  348. (
  349. "Select Type",
  350. new SelectionViewModel<KanbanType>
  351. (
  352. new Filter<KanbanType>(x => x.Hidden).IsEqualTo(false),
  353. new Expression<Func<KanbanType, object>>[] { x => x.Description },
  354. new Expression<Func<KanbanType, object>>[] { x => x.Hidden },
  355. new SortOrder<KanbanType>(x => x.Description)
  356. ));
  357. page.OnItemSelected += (row) =>
  358. {
  359. var kanbanType = row.ToObject<KanbanType>();
  360. kanban.Type.ID = kanbanType.ID;
  361. kanban.Type.Synchronise(kanbanType);
  362. UpdateScreen();
  363. };
  364. Navigation.PushAsync(page);
  365. }
  366. }
  367. private void AllocatedByBtn_Clicked(object sender, EventArgs e)
  368. {
  369. EmployeeSelectionPage employeeSelectionPage = new EmployeeSelectionPage();
  370. employeeSelectionPage.OnItemSelected += (() =>
  371. {
  372. kanban.ManagerLink.ID = employeeSelectionPage.employee.ID;
  373. kanban.ManagerLink.Name = employeeSelectionPage.employee.Name;
  374. UpdateScreen();
  375. });
  376. Navigation.PushAsync(employeeSelectionPage);
  377. }
  378. private void AssignedToBtn_Clicked(object sender, EventArgs e)
  379. {
  380. EmployeeSelectionPage employeeSelectionPage = new EmployeeSelectionPage();
  381. employeeSelectionPage.OnItemSelected += (() =>
  382. {
  383. kanban.EmployeeLink.ID = employeeSelectionPage.employee.ID;
  384. kanban.EmployeeLink.Name = employeeSelectionPage.employee.Name;
  385. UpdateScreen();
  386. });
  387. Navigation.PushAsync(employeeSelectionPage);
  388. }
  389. private void CheckPrivateChanged(object sender, CheckedChangedEventArgs e)
  390. {
  391. if (privateCheckBox.IsChecked)
  392. {
  393. Employee employee = new Employee();
  394. var table = new Client<Employee>().Query(new Filter<Employee>(x => x.UserLink.ID).IsEqualTo(ClientFactory.UserGuid));
  395. foreach (CoreRow row in table.Rows)
  396. {
  397. employee = row.ToObject<Employee>();
  398. }
  399. kanban.ManagerLink.ID = employee.ID;
  400. kanban.ManagerLink.Synchronise(employee);
  401. kanban.EmployeeLink.ID = employee.ID;
  402. kanban.EmployeeLink.Synchronise(employee);
  403. kanban.Private = true;
  404. assignedToBtn.IsEnabled = false;
  405. allocatedByBtn.IsEnabled = false;
  406. UpdateScreen();
  407. }
  408. if (!privateCheckBox.IsChecked)
  409. {
  410. kanban.Private = false;
  411. assignedToBtn.IsEnabled = true;
  412. allocatedByBtn.IsEnabled = true;
  413. }
  414. }
  415. private void category_Changed(object sender, EventArgs e)
  416. {
  417. if (categoryPck.SelectedIndex == 0)
  418. {
  419. kanban.Category = "Open";
  420. }
  421. if (categoryPck.SelectedIndex == 1)
  422. {
  423. kanban.Category = "In Progress";
  424. }
  425. if (categoryPck.SelectedIndex == 2)
  426. {
  427. kanban.Category = "Waiting";
  428. }
  429. if (categoryPck.SelectedIndex == 3)
  430. {
  431. kanban.Category = "Complete";
  432. }
  433. }
  434. private int chooseIndex()
  435. {
  436. int indexNo = -1;
  437. if (kanban.Category != null)
  438. {
  439. if (kanban.Category.Equals("Open"))
  440. {
  441. indexNo = 0;
  442. }
  443. if (kanban.Category.Equals("In Progress"))
  444. {
  445. indexNo = 1;
  446. }
  447. if (kanban.Category.Equals("Waiting"))
  448. {
  449. indexNo = 2;
  450. }
  451. if (kanban.Category.Equals("Complete"))
  452. {
  453. indexNo = 3;
  454. }
  455. }
  456. return indexNo;
  457. }
  458. #endregion
  459. #region Estimated Time
  460. private void DecreaseBtn_Clicked(object sender, EventArgs e)
  461. {
  462. if (estimatedTime == 0 || estimatedTime < 0)
  463. return;
  464. else
  465. {
  466. estimatedTime = estimatedTime - 15;
  467. kanban.EstimatedTime = new TimeSpan(0, estimatedTime, 0);
  468. DisplayEstimatedTime();
  469. }
  470. }
  471. private void IncreaseBtn_Clicked(object sender, EventArgs e)
  472. {
  473. estimatedTime = estimatedTime + 15;
  474. kanban.EstimatedTime = new TimeSpan(0, estimatedTime, 0);
  475. DisplayEstimatedTime();
  476. }
  477. private void EstimatedHoursEdt_Changed(object sender, EventArgs e)
  478. {
  479. if (displaying)
  480. return;
  481. else
  482. CalculateEstimatedTime();
  483. }
  484. private void EstimatedMinsEdt_Changed(object sender, EventArgs e)
  485. {
  486. if (displaying)
  487. return;
  488. else
  489. CalculateEstimatedTime();
  490. }
  491. private async void CalculateEstimatedTime() //to timespan
  492. {
  493. try
  494. {
  495. int minutes = 0;
  496. int hours = 0;
  497. if (!string.IsNullOrWhiteSpace(estimatedHoursEdt.Text))
  498. {
  499. hours = Convert.ToInt32(estimatedHoursEdt.Text);
  500. }
  501. if (!string.IsNullOrWhiteSpace(estimatedMinsEdt.Text))
  502. {
  503. minutes = Convert.ToInt32(estimatedMinsEdt.Text);
  504. }
  505. kanban.EstimatedTime = new TimeSpan(hours, minutes, 0);
  506. estimatedTime = Convert.ToInt32(kanban.EstimatedTime.TotalMinutes);
  507. }
  508. catch
  509. {
  510. await DisplayAlert("Error", "Only whole numbers for estimated time fields", "OK");
  511. int isNumber;
  512. if (!int.TryParse(estimatedHoursEdt.Text, out isNumber))
  513. {
  514. estimatedHoursEdt.Text = "0";
  515. };
  516. if (!int.TryParse(estimatedMinsEdt.Text, out isNumber))
  517. {
  518. estimatedMinsEdt.Text = "0";
  519. };
  520. }
  521. }
  522. private async void DisplayEstimatedTime() //from timespan
  523. {
  524. await Task.Run(() =>
  525. {
  526. displaying = true;
  527. estimatedTime = Convert.ToInt32(kanban.EstimatedTime.TotalMinutes);
  528. int hours = estimatedTime / 60;
  529. int minutes = estimatedTime % 60;
  530. Device.BeginInvokeOnMainThread(() =>
  531. {
  532. estimatedHoursEdt.Text = hours.ToString();
  533. estimatedMinsEdt.Text = minutes.ToString();
  534. displaying = false;
  535. });
  536. });
  537. }
  538. #endregion
  539. #region Display or add images
  540. private async void UpdateImages()
  541. {
  542. try
  543. {
  544. Device.BeginInvokeOnMainThread(() =>
  545. {
  546. if (kanban.Attachments != 0)
  547. {
  548. int count = kanban.Attachments;
  549. photosLbl.TextColor = Color.Orange;
  550. photosLbl.Text = "Loading " + kanban.Attachments + " Photos";
  551. Task.Run(() =>
  552. {
  553. var table = QueryKanbanDocuments();
  554. while (table == null)
  555. table = QueryKanbanDocuments();
  556. if (table.Rows.Count != 0)
  557. {
  558. foreach (var row in table.Rows)
  559. {
  560. CoreTable docstable = QueryDocument(row.Get<KanbanDocument, Guid>(x => x.DocumentLink.ID));
  561. while (docstable == null)
  562. docstable = QueryDocument(row.Get<KanbanDocument, Guid>(x => x.DocumentLink.ID));
  563. CoreRow docrow = docstable.Rows.FirstOrDefault();
  564. if (docrow != null)
  565. {
  566. byte[] data = docrow.Get<Document, byte[]>(x => x.Data);
  567. ImageSource src = ImageSource.FromStream(() => new MemoryStream(data));
  568. Image img = new Image();
  569. img.HeightRequest = 150;
  570. img.WidthRequest = 150;
  571. img.Aspect = Aspect.AspectFit;
  572. img.Source = src;
  573. img.GestureRecognizers.Add(new TapGestureRecognizer
  574. {
  575. Command = new Command(OnTap),
  576. CommandParameter = src,
  577. NumberOfTapsRequired = 1
  578. });
  579. imageList.Add(img);
  580. Device.BeginInvokeOnMainThread(() =>
  581. {
  582. ImageScroller.IsVisible = true;
  583. images.Children.Add(img);
  584. count = count - 1;
  585. photosLbl.Text = "Loading " + count + " Photo(s)";
  586. if (count == 0)
  587. {
  588. photosLbl.Text = "Photos";
  589. photosLbl.TextColor = Color.Default;
  590. }
  591. });
  592. }
  593. }
  594. }
  595. });
  596. }
  597. });
  598. }
  599. catch { }
  600. }
  601. private CoreTable QueryKanbanDocuments()
  602. {
  603. try
  604. {
  605. return new Client<KanbanDocument>().Query(
  606. new Filter<KanbanDocument>(x => x.EntityLink.ID).IsEqualTo(kanban.ID),
  607. new Columns<KanbanDocument>(x => x.DocumentLink.ID),
  608. null
  609. );
  610. }
  611. catch (Exception ex)
  612. {
  613. var log = new MobileLogging(LogType.Query, "QueryKanbanDocuments()", ex.Message + ex.StackTrace, this.GetType().Name);
  614. return null;
  615. }
  616. }
  617. private CoreTable QueryDocument(Guid id)
  618. {
  619. try
  620. {
  621. return new Client<Document>().Query(new Filter<Document>(x => x.ID).IsEqualTo(id),
  622. new Columns<Document>(x => x.Data));
  623. }
  624. catch (Exception ex)
  625. {
  626. var log = new MobileLogging(LogType.Query, "QueryDocument()", ex.Message + ex.StackTrace, this.GetType().Name);
  627. return null;
  628. }
  629. }
  630. private void OnTap(object obj)
  631. {
  632. ImageViewerEditor imageViewEditor = new ImageViewerEditor(obj as ImageSource);
  633. imageViewEditor.OnSaveSelected += (byte[] array) =>
  634. {
  635. try
  636. {
  637. Image img = imageList.Find(x => x.Source.Equals(obj as ImageSource));
  638. imageList.Remove(img);
  639. imagesourcedocs.Remove(obj as ImageSource);
  640. }
  641. catch { }
  642. DataToImage(array);
  643. };
  644. Navigation.PushAsync(imageViewEditor);
  645. }
  646. public void DataToImage(byte[] data)
  647. {
  648. try
  649. {
  650. ImageSource src = ImageSource.FromStream(() => new MemoryStream(data));
  651. Image img = new Image();
  652. img.HeightRequest = 150;
  653. img.WidthRequest = 150;
  654. img.Aspect = Aspect.AspectFit;
  655. img.VerticalOptions = LayoutOptions.FillAndExpand;
  656. img.HorizontalOptions = LayoutOptions.FillAndExpand;
  657. img.Source = src;
  658. img.GestureRecognizers.Add(new TapGestureRecognizer
  659. {
  660. Command = new Command(OnTap),
  661. CommandParameter = src,
  662. NumberOfTapsRequired = 1
  663. });
  664. if (img != null)
  665. {
  666. imageList.Add(img);
  667. RefreshView();
  668. }
  669. String filename = String.Format("{0:yyyy-MM-dd HH:mm:ss.fff}.png", DateTime.Now);
  670. Document doc = new Document()
  671. {
  672. FileName = filename,
  673. Data = data,
  674. CRC = CoreUtils.CalculateCRC(data),
  675. TimeStamp = DateTime.Now
  676. };
  677. imagesourcedocs.Add(src, doc);
  678. }
  679. catch
  680. { }
  681. }
  682. private void RefreshView()
  683. {
  684. Device.BeginInvokeOnMainThread(() =>
  685. {
  686. images.Children.Clear();
  687. foreach (Image img in imageList)
  688. {
  689. images.Children.Add(img);
  690. }
  691. });
  692. }
  693. async void TakePhoto_Clicked(object sender, EventArgs e)
  694. {
  695. try
  696. {
  697. await CrossMedia.Current.Initialize();
  698. if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
  699. {
  700. await DisplayAlert("No Camera", ":( No camera available.", "OK");
  701. return;
  702. }
  703. String filename = String.Format("{0:yyyy-MM-dd HH:mm:ss.fff}.png", DateTime.Now);
  704. var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
  705. {
  706. Name = filename,
  707. CompressionQuality = 10,
  708. PhotoSize = Plugin.Media.Abstractions.PhotoSize.Full
  709. });
  710. if (file == null)
  711. return;
  712. using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Adding Photo"))
  713. {
  714. Image img = null;
  715. var memoryStream = new MemoryStream();
  716. file.GetStream().CopyTo(memoryStream);
  717. var data = memoryStream.ToArray();
  718. Document doc = new Document()
  719. {
  720. FileName = filename,
  721. Data = data,
  722. CRC = CoreUtils.CalculateCRC(data),
  723. TimeStamp = DateTime.Now
  724. };
  725. ImageSource src = ImageSource.FromStream(() => new MemoryStream(data));
  726. imagesourcedocs.Add(src, doc);
  727. img = new Image();
  728. img.HeightRequest = 150;
  729. img.WidthRequest = 150;
  730. img.Aspect = Aspect.AspectFit;
  731. img.Source = src;
  732. img.GestureRecognizers.Add(new TapGestureRecognizer
  733. {
  734. Command = new Command(OnTap),
  735. CommandParameter = src,
  736. NumberOfTapsRequired = 1
  737. });
  738. file.Dispose();
  739. if (img != null)
  740. {
  741. Device.BeginInvokeOnMainThread(() =>
  742. {
  743. ImageScroller.IsVisible = true;
  744. images.Children.Add(img);
  745. });
  746. }
  747. await pageScroller.ScrollToAsync(photoFrame, ScrollToPosition.Center, false);
  748. }
  749. }
  750. catch { }
  751. }
  752. async void ChooseImage_Clicked(object sender, EventArgs e)
  753. {
  754. try
  755. {
  756. await CrossMedia.Current.Initialize();
  757. if (!CrossMedia.Current.IsPickPhotoSupported)
  758. {
  759. await DisplayAlert("No Library", ":( No Photo Library available.", "OK");
  760. return;
  761. }
  762. var file = await CrossMedia.Current.PickPhotoAsync(new Plugin.Media.Abstractions.PickMediaOptions()
  763. {
  764. CompressionQuality = 10,
  765. PhotoSize = Plugin.Media.Abstractions.PhotoSize.Full
  766. });
  767. if (file == null)
  768. return;
  769. using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Adding Photo"))
  770. {
  771. Image img = null;
  772. var memoryStream = new MemoryStream();
  773. file.GetStream().CopyTo(memoryStream);
  774. var data = memoryStream.ToArray();
  775. Document doc = new Document()
  776. {
  777. FileName = Path.GetFileName(file.Path),
  778. Data = data,
  779. CRC = CoreUtils.CalculateCRC(data),
  780. TimeStamp = DateTime.Now
  781. };
  782. ImageSource src = ImageSource.FromStream(() => new MemoryStream(data));
  783. imagesourcedocs.Add(src, doc);
  784. img = new Image();
  785. img.HeightRequest = 150;
  786. img.WidthRequest = 150;
  787. img.Aspect = Aspect.AspectFit;
  788. img.Source = src;
  789. img.GestureRecognizers.Add(new TapGestureRecognizer
  790. {
  791. Command = new Command(OnTap),
  792. CommandParameter = src,
  793. NumberOfTapsRequired = 1
  794. });
  795. file.Dispose();
  796. if (img != null)
  797. {
  798. Device.BeginInvokeOnMainThread(() =>
  799. {
  800. ImageScroller.IsVisible = true;
  801. images.Children.Add(img);
  802. });
  803. }
  804. await pageScroller.ScrollToAsync(photoFrame, ScrollToPosition.Center, false);
  805. }
  806. }
  807. catch { }
  808. }
  809. #endregion
  810. #region Digital Forms
  811. private async void Forms_Clicked(object sender, EventArgs e)
  812. {
  813. try
  814. {
  815. string chosenOptionOne = "";
  816. if (kanbanFormList.Count == 0)
  817. {
  818. chosenOptionOne = await DisplayActionSheet("Choose An Option", "Cancel", null, "Add Form to Task");
  819. }
  820. else if (kanbanFormList.Count > 0)
  821. {
  822. chosenOptionOne = await DisplayActionSheet("Choose An Option", "Cancel", null, "Add Form to Task", "View Form(s)");
  823. }
  824. switch (chosenOptionOne)
  825. {
  826. case "Cancel":
  827. return;
  828. case "Add Form to Task":
  829. DigitalFormsPicker digitalFormPicker = new DigitalFormsPicker(kanban);
  830. Navigation.PushAsync(digitalFormPicker);
  831. break;
  832. case "View Form(s)":
  833. ChooseForm();
  834. break;
  835. default: break;
  836. }
  837. }
  838. catch { }
  839. }
  840. private async void ChooseForm()
  841. {
  842. ListSelectionPage page = new ListSelectionPage(CreatePairs(), "Forms");
  843. page.OnDictionaryItemTapped += (id, value) => { LaunchForm(id); };
  844. Navigation.PushAsync(page);
  845. }
  846. private Dictionary<Guid, string> CreatePairs()
  847. {
  848. Dictionary<Guid, string> pairs = new Dictionary<Guid, string>();
  849. foreach (KanbanForm kanbanForm in kanbanFormList)
  850. {
  851. string formDescription = CreateDescription(kanbanForm);
  852. pairs.Add(kanbanForm.ID, formDescription);
  853. }
  854. return pairs;
  855. }
  856. private string CreateDescription(KanbanForm kanbanForm)
  857. {
  858. string formDescription = kanbanForm.Form.Description;
  859. if (kanbanForm.FormCompleted != DateTime.MinValue)
  860. formDescription = formDescription
  861. + " (Completed: "
  862. + kanbanForm.FormCompleted.ToString("hh:mm - dd MMM yy")
  863. + " by "
  864. + kanbanForm.FormCompletedBy.UserID
  865. + ")";
  866. else
  867. formDescription = formDescription
  868. + " (Created: "
  869. + kanbanForm.Created.ToString("hh:mm - dd MMM yy")
  870. + ")";
  871. return formDescription;
  872. }
  873. private async void LaunchForm(Guid id)
  874. {
  875. KanbanForm form = kanbanFormList.FirstOrDefault(x => x.ID == id);
  876. CoreTable table = QueryDigitalFormLayout(form);
  877. while (table == null)
  878. table = QueryDigitalFormLayout(form);
  879. CoreRow row = table.Rows.FirstOrDefault();
  880. DigitalFormLayout layout = row.ToObject<DigitalFormLayout>();
  881. using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Loading"))
  882. {
  883. DigitalFormHost host = new DigitalFormHost(
  884. DigitalFormsHelper.LoadModel(
  885. layout, typeof(KanbanForm), kanban, Guid.Empty,
  886. new ExistingFormShell
  887. {
  888. ID = form.ID,
  889. ParentID = kanban.ID,
  890. Type = typeof(KanbanForm),
  891. FormID = form.ID,
  892. }
  893. ));
  894. Navigation.PushAsync(host);
  895. }
  896. }
  897. private CoreTable QueryDigitalFormLayout(KanbanForm form)
  898. {
  899. try
  900. {
  901. return new Client<DigitalFormLayout>().Query(
  902. new Filter<DigitalFormLayout>(x => x.Type).IsEqualTo(DFLayoutType.Mobile).And(x => x.Active).IsEqualTo(true).And(x => x.Form.Description).IsEqualTo(form.Form.Description),
  903. new Columns<DigitalFormLayout>(x => x.Description, x => x.ID, x => x.Code, x => x.Form.AppliesTo, x => x.Form.ID, x => x.Layout),
  904. new SortOrder<DigitalFormLayout>(x => x.Description)
  905. );
  906. }
  907. catch (Exception ex)
  908. {
  909. var log = new MobileLogging(LogType.Query, "QueryDigitalFormLayout()", ex.Message + ex.StackTrace, this.GetType().Name);
  910. return null;
  911. }
  912. }
  913. #endregion
  914. #region Submit btn + photos save
  915. private async void SubmitBtn_Clicked()
  916. {
  917. try
  918. {
  919. if (searching)
  920. return;
  921. else
  922. {
  923. searching = true;
  924. using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Saving"))
  925. {
  926. SaveKanban();
  927. SaveDocuments();
  928. Task.Run(() => { SaveSubscribers(); });
  929. SavePhotos();
  930. }
  931. string successMessage = "Task number : " + kanban.Number + System.Environment.NewLine
  932. + "New Photo(s): " + imagesourcedocs.Values.Count;
  933. await DisplayAlert("Success", successMessage, "OK");
  934. OnTaskSaved?.Invoke(kanban.Number);
  935. await Navigation.PopAsync();
  936. }
  937. }
  938. catch (Exception ex)
  939. {
  940. DisplayAlert("Error saving", ex.Message, "OK");
  941. }
  942. }
  943. private void SaveKanban()
  944. {
  945. try
  946. {
  947. new Client<Kanban>().Save(kanban, "Updated From Mobile Device");
  948. }
  949. catch (Exception ex)
  950. {
  951. var log = new MobileLogging(LogType.Save, "SaveKanban()", ex.Message + ex.StackTrace, this.GetType().Name);
  952. SaveKanban();
  953. }
  954. }
  955. private void SaveDocuments()
  956. {
  957. try
  958. {
  959. if (imagesourcedocs.Values.Count != 0)
  960. new Client<Document>().Save(imagesourcedocs.Values, "Photo Taken on Device");
  961. }
  962. catch (Exception ex)
  963. {
  964. var log = new MobileLogging(LogType.Save, "SaveDocuments()", ex.Message + ex.StackTrace, this.GetType().Name);
  965. SaveDocuments();
  966. }
  967. }
  968. private void SavePhotos()
  969. {
  970. try
  971. {
  972. if (imagesourcedocs.Values.Count != 0)
  973. {
  974. List<KanbanDocument> newKanbanDocuments = new List<KanbanDocument>();
  975. foreach (Document doc in imagesourcedocs.Values)
  976. {
  977. var kanbanDocument = new KanbanDocument();
  978. kanbanDocument.EntityLink.ID = kanban.ID;
  979. kanbanDocument.DocumentLink.ID = doc.ID;
  980. kanbanDocument.DocumentLink.FileName = doc.FileName;
  981. newKanbanDocuments.Add(kanbanDocument);
  982. }
  983. Task.Run(() =>
  984. {
  985. SaveKanbanDocuments(newKanbanDocuments);
  986. });
  987. }
  988. }
  989. catch { }
  990. }
  991. private void SaveKanbanDocuments(List<KanbanDocument> newKanbanDocuments)
  992. {
  993. try
  994. {
  995. new Client<KanbanDocument>().Save(newKanbanDocuments, "Photo Taken on Device");
  996. }
  997. catch (Exception ex)
  998. {
  999. var log = new MobileLogging(LogType.Save, typeof(KanbanDocument).ToString(), ex.Message, this.GetType().Name);
  1000. SaveKanbanDocuments(newKanbanDocuments);
  1001. }
  1002. }
  1003. #endregion
  1004. #region Subscribers Buttons / Functionality
  1005. private async void DisplayObserverList()
  1006. {
  1007. try
  1008. {
  1009. await Task.Run(() =>
  1010. {
  1011. if (!newKanban)
  1012. {
  1013. CoreTable table = QueryObservers();
  1014. while (table == null)
  1015. table = QueryObservers();
  1016. foreach (CoreRow row in table.Rows)
  1017. {
  1018. KanbanSubscriber subscriber = row.ToObject<KanbanSubscriber>();
  1019. if (!subscriber.Manager && !subscriber.Assignee)
  1020. {
  1021. observerList.Add(subscriber);
  1022. AddSubscriberLabel(subscriber);
  1023. }
  1024. }
  1025. }
  1026. });
  1027. }
  1028. catch { }
  1029. }
  1030. private CoreTable QueryObservers()
  1031. {
  1032. try
  1033. {
  1034. return new Client<KanbanSubscriber>().Query(
  1035. new Filter<KanbanSubscriber>(x => x.Kanban.ID).IsEqualTo(kanban.ID).And(x => x.Observer).IsEqualTo(true)
  1036. );
  1037. }
  1038. catch (Exception ex)
  1039. {
  1040. var log = new MobileLogging(LogType.Query, "QueryObservers()", ex.Message + ex.StackTrace, this.GetType().Name);
  1041. return null;
  1042. }
  1043. }
  1044. private void AddSubscriberLabel(KanbanSubscriber subscriber)
  1045. {
  1046. Label label = new Label();
  1047. label.Text = subscriber.Employee.Name;
  1048. label.FontSize = Device.GetNamedSize(NamedSize.Medium, label);
  1049. label.Margin = 5;
  1050. label.HorizontalTextAlignment = TextAlignment.Start;
  1051. label.VerticalTextAlignment = TextAlignment.Center;
  1052. Device.BeginInvokeOnMainThread(() =>
  1053. {
  1054. observerStackLayout.Children.Add(label);
  1055. });
  1056. }
  1057. private async void AddSubscriberBtn_Clicked(object sender, EventArgs e)
  1058. {
  1059. string chosenOption = await DisplayActionSheet("Add", "Cancel", null, "Person", "Team");
  1060. switch (chosenOption)
  1061. {
  1062. case "Cancel":
  1063. break;
  1064. case "Person":
  1065. SelectEmployeeForSubscriber();
  1066. break;
  1067. case "Team":
  1068. SelectTeamForSubscriber();
  1069. break;
  1070. default:
  1071. break;
  1072. }
  1073. }
  1074. private void SelectEmployeeForSubscriber()
  1075. {
  1076. EmployeeSelectionPage employeeSelectionPage = new EmployeeSelectionPage();
  1077. employeeSelectionPage.OnItemSelected += (() =>
  1078. {
  1079. KanbanSubscriber subscriber = new KanbanSubscriber();
  1080. subscriber.Kanban.ID = kanban.ID;
  1081. subscriber.Observer = true;
  1082. subscriber.Employee.ID = employeeSelectionPage.employee.ID;
  1083. subscriber.Employee.Name = employeeSelectionPage.employee.Name;
  1084. CheckListAndAddSubscriber(subscriber);
  1085. });
  1086. Navigation.PushAsync(employeeSelectionPage);
  1087. }
  1088. private async void SelectTeamForSubscriber()
  1089. {
  1090. string[] array = GlobalVariables.TeamNames.ToArray<string>();
  1091. string chosenTeam = await DisplayActionSheet("Choose Team", "Cancel", null, array);
  1092. switch (chosenTeam)
  1093. {
  1094. case "Cancel":
  1095. return;
  1096. break;
  1097. }
  1098. if (!string.IsNullOrWhiteSpace(chosenTeam))
  1099. {
  1100. List<EmployeeShell> employees = GlobalVariables.TeamEmployeeShells.Where(x => x.TeamName == chosenTeam).ToList();
  1101. foreach (EmployeeShell employee in employees)
  1102. {
  1103. KanbanSubscriber subscriber = new KanbanSubscriber();
  1104. subscriber.Kanban.ID = kanban.ID;
  1105. subscriber.Employee.ID = employee.ID;
  1106. subscriber.Employee.Name = employee.Name;
  1107. subscriber.Observer = true;
  1108. CheckListAndAddSubscriber(subscriber);
  1109. }
  1110. }
  1111. }
  1112. private void CheckListAndAddSubscriber(KanbanSubscriber subscriber)
  1113. {
  1114. List<Guid> guids = new List<Guid>();
  1115. foreach (KanbanSubscriber sub in observerList)
  1116. {
  1117. guids.Add(sub.Employee.ID);
  1118. }
  1119. if (!guids.Contains(subscriber.Employee.ID))
  1120. {
  1121. if (subscriber.Employee.ID != kanban.EmployeeLink.ID)
  1122. {
  1123. if (subscriber.Employee.ID != kanban.ManagerLink.ID)
  1124. {
  1125. observerList.Add(subscriber);
  1126. AddSubscriberLabel(subscriber);
  1127. }
  1128. }
  1129. }
  1130. }
  1131. private async void RemoveSubscriberBtn_Clicked(object sender, EventArgs e)
  1132. {
  1133. try
  1134. {
  1135. Dictionary<string, KanbanSubscriber> nameSubscriberPairs = new Dictionary<string, KanbanSubscriber>();
  1136. foreach (KanbanSubscriber subscriber in observerList)
  1137. {
  1138. nameSubscriberPairs.Add(subscriber.Employee.Name, subscriber);
  1139. }
  1140. string[] array = nameSubscriberPairs.Keys.ToArray();
  1141. string chosenOption = await DisplayActionSheet("Remove", "Cancel", null, array);
  1142. if (chosenOption == "Cancel" || string.IsNullOrWhiteSpace(chosenOption))
  1143. {
  1144. return;
  1145. }
  1146. else
  1147. {
  1148. KanbanSubscriber subscriber = nameSubscriberPairs[chosenOption];
  1149. observerList.Remove(subscriber);
  1150. observerStackLayout.Children.Clear();
  1151. foreach (KanbanSubscriber sub in observerList)
  1152. {
  1153. AddSubscriberLabel(sub);
  1154. }
  1155. }
  1156. }
  1157. catch { }
  1158. }
  1159. #endregion
  1160. #region Subscribers Saving
  1161. private void SaveSubscribers()
  1162. {
  1163. Task.Run(() =>
  1164. {
  1165. if (newKanban)
  1166. {
  1167. SaveNewSubs();
  1168. }
  1169. else
  1170. {
  1171. SaveExistingSubs();
  1172. }
  1173. });
  1174. }
  1175. private void SaveNewSubs()
  1176. {
  1177. try
  1178. {
  1179. List<KanbanSubscriber> subscribers = new List<KanbanSubscriber>();
  1180. KanbanSubscriber sub = null;
  1181. if (kanban.EmployeeLink.ID != Guid.Empty)
  1182. {
  1183. sub = new KanbanSubscriber();
  1184. sub.Kanban.ID = kanban.ID;
  1185. sub.Employee.ID = kanban.EmployeeLink.ID;
  1186. sub.Assignee = true;
  1187. if (kanban.EmployeeLink.ID == kanban.ManagerLink.ID)
  1188. {
  1189. sub.Manager = true;
  1190. }
  1191. subscribers.Add(sub);
  1192. }
  1193. if (kanban.ManagerLink.ID != Guid.Empty)
  1194. {
  1195. if (kanban.ManagerLink.ID != kanban.EmployeeLink.ID)
  1196. {
  1197. sub = new KanbanSubscriber();
  1198. sub.Kanban.ID = kanban.ID;
  1199. sub.Employee.ID = kanban.ManagerLink.ID;
  1200. sub.Manager = true;
  1201. subscribers.Add(sub);
  1202. }
  1203. }
  1204. foreach (KanbanSubscriber subscriber in observerList)
  1205. {
  1206. subscriber.Kanban.ID = kanban.ID;
  1207. subscribers.Add(subscriber);
  1208. }
  1209. DoSaveSubscribers(subscribers);
  1210. }
  1211. catch (Exception ex)
  1212. {
  1213. var log = new MobileLogging(LogType.Save, typeof(KanbanSubscriber).ToString(), ex.Message, this.GetType().Name);
  1214. }
  1215. }
  1216. private void DoSaveSubscribers(List<KanbanSubscriber> subscribers)
  1217. {
  1218. try
  1219. {
  1220. new Client<KanbanSubscriber>().Save(subscribers, "Updated from mobile device");
  1221. }
  1222. catch (Exception ex)
  1223. {
  1224. var log = new MobileLogging(LogType.Save, typeof(KanbanSubscriber).ToString(), ex.Message, this.GetType().Name);
  1225. DoSaveSubscribers(subscribers);
  1226. }
  1227. }
  1228. private void SaveExistingSubs()
  1229. {
  1230. try
  1231. {
  1232. KanbanSubscriber oldAssignee = new KanbanSubscriber();
  1233. KanbanSubscriber oldManager = new KanbanSubscriber();
  1234. KanbanSubscriber oldBoth = new KanbanSubscriber();
  1235. List<KanbanSubscriber> oldObservers = new List<KanbanSubscriber>();
  1236. List<KanbanSubscriber> subscribersToDelete = new List<KanbanSubscriber>();
  1237. List<KanbanSubscriber> subscribersToSave = new List<KanbanSubscriber>();
  1238. List<KanbanSubscriber> subscribers = new List<KanbanSubscriber>();
  1239. CoreTable table = QuerySubscribers();
  1240. while (table == null)
  1241. table = QuerySubscribers();
  1242. foreach (CoreRow row in table.Rows)
  1243. {
  1244. KanbanSubscriber subscriber = row.ToObject<KanbanSubscriber>();
  1245. if (subscriber.Assignee && subscriber.Manager)
  1246. {
  1247. oldBoth = subscriber;
  1248. }
  1249. else
  1250. {
  1251. if (subscriber.Assignee)
  1252. {
  1253. oldAssignee = subscriber;
  1254. }
  1255. else if (subscriber.Manager)
  1256. {
  1257. oldManager = subscriber;
  1258. }
  1259. else if (subscriber.Observer)
  1260. {
  1261. oldObservers.Add(subscriber);
  1262. }
  1263. }
  1264. }
  1265. if (kanban.ManagerLink.ID == kanban.EmployeeLink.ID)
  1266. {
  1267. if (kanban.ManagerLink.ID != oldBoth.Employee.ID && oldBoth.Employee.ID != Guid.Empty)
  1268. {
  1269. subscribersToDelete.Add(oldBoth);
  1270. KanbanSubscriber subscriber = new KanbanSubscriber();
  1271. subscriber.Assignee = true;
  1272. subscriber.Manager = true;
  1273. subscriber.Kanban.ID = kanban.ID;
  1274. subscriber.Employee.ID = kanban.EmployeeLink.ID;
  1275. subscribersToSave.Add(subscriber);
  1276. }
  1277. }
  1278. if (oldAssignee.Employee.ID != kanban.EmployeeLink.ID && oldAssignee.Employee.ID != Guid.Empty)
  1279. {
  1280. subscribersToDelete.Add(oldAssignee);
  1281. KanbanSubscriber subscriber = new KanbanSubscriber();
  1282. subscriber.Assignee = true;
  1283. subscriber.Manager = false;
  1284. subscriber.Kanban.ID = kanban.ID;
  1285. subscriber.Employee.ID = kanban.EmployeeLink.ID;
  1286. subscribersToSave.Add(subscriber);
  1287. }
  1288. if (oldManager.Employee.ID != kanban.ManagerLink.ID && oldManager.Employee.ID != Guid.Empty)
  1289. {
  1290. subscribersToDelete.Add(oldManager);
  1291. KanbanSubscriber subscriber = new KanbanSubscriber();
  1292. subscriber.Assignee = false;
  1293. subscriber.Manager = true;
  1294. subscriber.Kanban.ID = kanban.ID;
  1295. subscriber.Employee.ID = kanban.ManagerLink.ID;
  1296. subscribersToSave.Add(subscriber);
  1297. }
  1298. List<Guid> oldGuids = new List<Guid>();
  1299. List<Guid> newGuids = new List<Guid>();
  1300. foreach (KanbanSubscriber sub in observerList)
  1301. {
  1302. newGuids.Add(sub.Employee.ID);
  1303. }
  1304. foreach (KanbanSubscriber sub in oldObservers)
  1305. {
  1306. oldGuids.Add(sub.Employee.ID);
  1307. if (!newGuids.Contains(sub.Employee.ID))
  1308. {
  1309. subscribersToDelete.Add(sub);
  1310. }
  1311. }
  1312. foreach (KanbanSubscriber sub in observerList)
  1313. {
  1314. if (!oldGuids.Contains(sub.Employee.ID))
  1315. {
  1316. subscribersToSave.Add(sub);
  1317. }
  1318. }
  1319. DoSaveSubscribers(subscribersToSave);
  1320. DeleteSubscribers(subscribersToDelete);
  1321. }
  1322. catch (Exception ex)
  1323. {
  1324. var log = new MobileLogging(LogType.Save, typeof(KanbanSubscriber).ToString(), ex.Message, this.GetType().Name);
  1325. }
  1326. }
  1327. private CoreTable QuerySubscribers()
  1328. {
  1329. try
  1330. {
  1331. return new Client<KanbanSubscriber>().Query(
  1332. new Filter<KanbanSubscriber>(x => x.Kanban.ID).IsEqualTo(kanban.ID)
  1333. );
  1334. }
  1335. catch (Exception ex)
  1336. {
  1337. var log = new MobileLogging(LogType.Query, typeof(KanbanSubscriber).ToString(), ex.Message, this.GetType().Name);
  1338. return null;
  1339. }
  1340. }
  1341. private void DeleteSubscribers(List<KanbanSubscriber> subscribersToDelete)
  1342. {
  1343. try
  1344. {
  1345. new Client<KanbanSubscriber>().Delete(subscribersToDelete, "Updated from mobile device");
  1346. }
  1347. catch (Exception ex)
  1348. {
  1349. var log = new MobileLogging(LogType.Delete, typeof(KanbanSubscriber).ToString(), ex.Message, this.GetType().Name);
  1350. DeleteSubscribers(subscribersToDelete);
  1351. }
  1352. }
  1353. #endregion
  1354. }
  1355. }