AddEditTask.xaml.cs 44 KB

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