AddEditTask.xaml.cs 52 KB

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