AddEditTask.xaml.cs 45 KB

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