MainPage.xaml.cs 66 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. using Xamarin.Forms;
  7. using InABox.Core;
  8. using InABox.Configuration;
  9. using InABox.Clients;
  10. using InABox.Mobile;
  11. using Comal.Classes;
  12. using XF.Material.Forms.UI.Dialogs;
  13. using comal.timesheets.CustomControls;
  14. using comal.timesheets.StoreRequis;
  15. using PRSSecurity = InABox.Core.Security;
  16. using Plugin.LocalNotification;
  17. using comal.timesheets.Tasks;
  18. using System.IO;
  19. namespace comal.timesheets
  20. {
  21. public partial class MainPage : ContentPage
  22. {
  23. #region Fields
  24. List<ToolEntry> toolEntries = new List<ToolEntry>();
  25. public bool SettingsChanged { get; private set; }
  26. bool bUpdatingTimesheet = false;
  27. public static ConnectionSettings connectionSettings = null;
  28. bool midnightTimerOn = false;
  29. DateTime oneSecondBeforeMidnight = DateTime.Today.AddSeconds(864399);
  30. bool clockedOffInLast5Seconds = false;
  31. bool bRecentlyUpdatedTiles = false;
  32. bool bSharedDeviceFirstLoad = true;
  33. bool bSharedDevice = false;
  34. int NumberOfNotfications = 0;
  35. string matchedDeviceName = "";
  36. int notCount = 1;
  37. #endregion
  38. #region Constructor
  39. public MainPage()
  40. {
  41. InitializeComponent();
  42. try
  43. {
  44. InitItems();
  45. LoadCacheLists();
  46. //if (GlobalVariables.EmpID == Guid.Parse("40f6ccd9-5272-4b1a-99bf-de7542205aac"))
  47. RunCustomScript();
  48. }
  49. catch (Exception e) { }
  50. }
  51. private void RunCustomScript()
  52. {
  53. }
  54. private void InitItems()
  55. {
  56. NavigationPage.SetHasBackButton(this, false);
  57. MainPageUtils.Init();
  58. InitNotificationCentre();
  59. MainPageUtils.OnRefreshScreen += () =>
  60. {
  61. Device.BeginInvokeOnMainThread(() =>
  62. {
  63. RefreshScreen();
  64. });
  65. };
  66. MessagingCenter.Subscribe<App>(this, App.MessageOnResume,
  67. (o) =>
  68. {
  69. if (!App.GPS.RecentlyLocated)
  70. App.GPS.GetLocation();
  71. RefreshScreen();
  72. }
  73. );
  74. InitToolEntryList();
  75. CheckCurrentAssignment();
  76. NotifyChanges();
  77. }
  78. private void CheckCurrentAssignment()
  79. {
  80. Task.Run(() =>
  81. {
  82. try
  83. {
  84. var assgn = MainPageUtils.CheckCurrentAssignment();
  85. MainPageUtils.OnRequestUserInput += (taskID) => { RequestUserInput(taskID); };
  86. MainPageUtils.OnTaskTitleChanged += (title) => { taskBtn.Text = title; };
  87. MainPageUtils.Job.OnJobIDChanged += MainPageUtils.OnJobIDChanged;
  88. MainPageUtils.Job.OnJobNumberChanged += Job_OnJobNumberChanged;
  89. if (assgn == null)
  90. return;
  91. MainPageUtils.UseCurrentAssignment(assgn);
  92. RefreshJobBtn();
  93. }
  94. catch { }
  95. });
  96. }
  97. private void NotifyChanges()
  98. {
  99. Task.Run(() =>
  100. {
  101. string changes = NotifyMobileChanges.Notifiy();
  102. if (!string.IsNullOrWhiteSpace(changes))
  103. Device.BeginInvokeOnMainThread(() =>
  104. {
  105. DisplayAlert("Latest changes", changes, "OK");
  106. });
  107. });
  108. }
  109. #endregion
  110. #region OnAppearing and Display
  111. protected override void OnAppearing()
  112. {
  113. if (!App.IsUserLoggedIn)
  114. {
  115. Navigation.PopAsync();
  116. return;
  117. }
  118. if (!MainPageUtils.firstLoad)
  119. RefreshScreen();
  120. Task.Run(async () =>
  121. {
  122. bool isLatest = true;
  123. try
  124. {
  125. isLatest = await MobileUtils.AppVersion.IsUsingLatestVersion();
  126. }
  127. catch (Exception eLatest)
  128. {
  129. if (!MainPageUtils.recentlyAskedToUpdate)
  130. {
  131. Device.BeginInvokeOnMainThread(() =>
  132. {
  133. });
  134. MainPageUtils.recentlyAskedToUpdate = true;
  135. }
  136. string s = eLatest.Message;
  137. }
  138. if (!isLatest)
  139. {
  140. if (!MainPageUtils.recentlyAskedToUpdate)
  141. {
  142. string latestVersionNumber = await MobileUtils.AppVersion.GetLatestVersionNumber();
  143. if (MainPageUtils.updateCounter < 3)
  144. {
  145. Device.BeginInvokeOnMainThread(async () =>
  146. {
  147. string chosenOption = await DisplayActionSheet(String.Format("Version {0} Available. Update now?", latestVersionNumber), "You will be reminded again in 10 minutes.", null, "Yes", "No");
  148. switch (chosenOption)
  149. {
  150. case "No":
  151. break;
  152. case "Cancel":
  153. break;
  154. case "Yes":
  155. Dispatcher.BeginInvokeOnMainThread(() => { MobileUtils.AppVersion.OpenAppInStore(); });
  156. break;
  157. default:
  158. break;
  159. }
  160. });
  161. }
  162. else if (MainPageUtils.updateCounter >= 3)
  163. {
  164. Device.BeginInvokeOnMainThread(() =>
  165. {
  166. DisplayAlert(String.Format("Version {0} Available", latestVersionNumber), "Please update your software to the latest version.", "OK")
  167. .ContinueWith((Task task) =>
  168. {
  169. Dispatcher.BeginInvokeOnMainThread(() => { MobileUtils.AppVersion.OpenAppInStore(); });
  170. });
  171. });
  172. }
  173. MainPageUtils.recentlyAskedToUpdate = true;
  174. MainPageUtils.updateCounter++;
  175. }
  176. }
  177. });
  178. base.OnAppearing();
  179. }
  180. private void AutoLogoutUser(object o)
  181. {
  182. App.LogoutUser();
  183. Navigation.PopToRootAsync();
  184. }
  185. private void RefreshScreen()
  186. {
  187. try
  188. {
  189. Device.BeginInvokeOnMainThread(() =>
  190. {
  191. homeScreenGrid.RaiseChild(CurrentLocation);
  192. CheckClockOnRequired();
  193. bBusy = true;
  194. if (GlobalVariables.EmpID == Guid.Empty)
  195. {
  196. GlobalVariables.EmpID = GlobalVariables.GetEmployeeID();
  197. GlobalVariables.EmpName = GlobalVariables.GetEmployeeName();
  198. }
  199. clockOnButton.IsEnabled = false;
  200. bool PRSReady = (App.Data.Employee != null) && (App.Data.TimeSheets != null) && (GlobalVariables.EmpID != Guid.Empty);
  201. bool GateReady = CheckLocation();
  202. CurrentLocation.Text = DisplayAddress();
  203. if (CurrentLocation.Text.Contains("ERROR"))
  204. CurrentLocation.Text = "Unknown Address";
  205. Title = null;
  206. Title = App.Data.Employee != null ? App.Data.Employee.Name : "";
  207. CoreRow timesheet = App.Data.TimeSheets?.Rows.FirstOrDefault();
  208. clockOnButton.Text = PRSReady && GateReady ? timesheet == null ? "CLOCK ON" : "CLOCK OFF" : "PLEASE WAIT";
  209. clockOnButton.IsEnabled = PRSReady && GateReady;
  210. clockOnButton.BackgroundColor = PRSReady && GateReady ? timesheet == null ? Color.FromHex("#e6e6fa") : Color.FromHex("#15C7C1") : Color.Gainsboro;
  211. clockOnButton.BorderColor = PRSReady && GateReady ? timesheet == null ? Color.Black : Color.FromHex("#15C7C1") : Color.Gainsboro;
  212. if (clockOnButton.Text == "CLOCK OFF")
  213. {
  214. addNoteBtn.IsEnabled = true;
  215. taskBtn.IsEnabled = true;
  216. if (GlobalVariables.JobsLoaded)
  217. jobBtn.IsEnabled = true;
  218. }
  219. else
  220. {
  221. addNoteBtn.IsEnabled = false;
  222. jobBtn.IsEnabled = false;
  223. taskBtn.IsEnabled = false;
  224. }
  225. RefreshJobBtn();
  226. homeScreenGrid.RaiseChild(CurrentLocation);
  227. MainPageUtils.firstLoad = false;
  228. bBusy = false;
  229. });
  230. }
  231. catch (Exception e)
  232. {
  233. }
  234. }
  235. private void CheckClockOnRequired()
  236. {
  237. if (GlobalVariables.IsJobOnlyEmployee)
  238. {
  239. clockOnButton.IsVisible = false;
  240. CurrentLocation.IsVisible = false;
  241. buttonsGrid.IsVisible = false;
  242. taskBtn.IsVisible = false;
  243. row0.Height = 0;
  244. row1.Height = 0;
  245. row2.Height = 150;
  246. Image img = new Image { Source = "logo.png" };
  247. img.Margin = 15;
  248. Grid.SetRow(img, 2);
  249. homeScreenGrid.Children.Add(img);
  250. }
  251. else
  252. {
  253. clockOnButton.IsVisible = true;
  254. CurrentLocation.IsVisible = true;
  255. buttonsGrid.IsVisible = true;
  256. taskBtn.IsVisible = true;
  257. }
  258. }
  259. private void Job_OnJobNumberChanged(string jobnumber)
  260. {
  261. jobBtn.Text = "Job: " + jobnumber;
  262. }
  263. private void RefreshJobBtn()
  264. {
  265. if (MainPageUtils.Job.ID == Guid.Empty)
  266. jobBtn.Text = "No Job Selected";
  267. else if (!string.IsNullOrWhiteSpace(MainPageUtils.Job.JobNumber))
  268. jobBtn.Text = MainPageUtils.Job.JobNumber;
  269. }
  270. private void RefreshJobFromTimeSheet(CoreRow timesheet)
  271. {
  272. Guid jobid = timesheet == null ? Guid.Empty : timesheet.Get<TimeSheet, Guid>(x => x.JobLink.ID);
  273. if (!jobid.Equals(Guid.Empty))
  274. {
  275. jobBtn.Text = String.Format("{0}: {1}", timesheet.Get<TimeSheet, String>(x => x.JobLink.JobNumber), timesheet.Get<TimeSheet, String>(x => x.JobLink.Name));
  276. MainPageUtils.Job.ID = timesheet == null ? Guid.Empty : timesheet.Get<TimeSheet, Guid>(x => x.JobLink.ID);
  277. MainPageUtils.Job.JobNumber = timesheet == null ? String.Empty : timesheet.Get<TimeSheet, String>(x => x.JobLink.JobNumber);
  278. MainPageUtils.Job.Name = timesheet == null ? String.Empty : timesheet.Get<TimeSheet, String>(x => x.JobLink.Name);
  279. }
  280. else
  281. {
  282. jobBtn.Text = "No Job Selected";
  283. MainPageUtils.Job = new JobShell();
  284. }
  285. }
  286. #endregion
  287. #region Clock on/off
  288. private void DataChanged(object sender, Type type, Exception e)
  289. {
  290. RefreshScreen();
  291. }
  292. private void DataRefreshed()
  293. {
  294. //if (bSharedDevice)
  295. // return;
  296. Device.BeginInvokeOnMainThread(() => { RefreshScreen(); });
  297. }
  298. bool bBusy = false;
  299. async void ClockOnOff_Clicked(object sender, System.EventArgs e)
  300. {
  301. if (bBusy)
  302. return;
  303. bBusy = true;
  304. string chosenOption = "Continue";
  305. if (clockOnButton.Text == "CLOCK OFF")
  306. {
  307. chosenOption = await DisplayActionSheet("Clock off?", "Cancel", null, "Continue", "Cancel");
  308. }
  309. switch (chosenOption)
  310. {
  311. case "Continue":
  312. break;
  313. case "Cancel":
  314. bBusy = false;
  315. return;
  316. break;
  317. default:
  318. bBusy = false;
  319. return;
  320. break;
  321. }
  322. if (clockOnButton.Text == "CLOCK ON" && clockedOffInLast5Seconds)
  323. {
  324. bBusy = false;
  325. return;
  326. }
  327. try
  328. {
  329. using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Loading"))
  330. {
  331. InABox.Core.Location here = new InABox.Core.Location()
  332. {
  333. Latitude = App.GPS.Latitude,
  334. Longitude = App.GPS.Longitude,
  335. Timestamp = DateTime.Now
  336. };
  337. TimeSheet timesheet = App.Data.TimeSheets?.Rows.FirstOrDefault()?.ToObject<TimeSheet>();
  338. if (timesheet != null)
  339. {
  340. if (timesheet.ID != Guid.Empty)
  341. {
  342. if (ZeroLengthTimesheet())
  343. {
  344. bUpdatingTimesheet = true;
  345. new Client<TimeSheet>().Delete(timesheet, "Deleted due to zero duration timesheet");
  346. App.Data.TimeSheets.Rows.Clear();
  347. }
  348. else
  349. {
  350. FinishTimeSheet(timesheet, here);
  351. }
  352. }
  353. }
  354. else
  355. {
  356. Guid jobid = Guid.Empty;
  357. String jobnumber = "";
  358. String jobname = "";
  359. if (!App.Data.CanBypassGates)
  360. {
  361. CoreRow row = App.Data.Gates.Rows.FirstOrDefault(r => App.Bluetooth.Devices.Contains(r.Get<JobTracker, String>(c => c.TrackerLink.DeviceID)));
  362. if (row != null)
  363. {
  364. jobid = row.Get<JobTracker, Guid>(x => x.JobLink.ID);
  365. jobnumber = row.Get<JobTracker, String>(x => x.JobLink.JobNumber);
  366. jobname = row.Get<JobTracker, String>(x => x.JobLink.Name);
  367. }
  368. CreateTimeSheet(jobid, jobnumber, jobname, here, App.GPS.Address, "Clocking On");
  369. }
  370. else
  371. {
  372. if ((!App.GPS.Latitude.Equals(0.0F)) && (!App.GPS.Longitude.Equals(0.0F)))
  373. {
  374. ChooseNearbyJob(here);
  375. }
  376. }
  377. }
  378. RefreshScreen();
  379. }
  380. }
  381. catch (Exception e2)
  382. {
  383. }
  384. bBusy = false;
  385. }
  386. #endregion
  387. #region Bluetooth
  388. private async void UploadTiles()
  389. {
  390. try
  391. {
  392. if (App.GPS.Latitude.Equals(0.0F) && App.GPS.Longitude.Equals(0.0F))
  393. return;
  394. if (App.Bluetooth.DetectedBlueToothMACAddresses.Count == 0)
  395. return;
  396. if (bRecentlyUpdatedTiles)
  397. return;
  398. bRecentlyUpdatedTiles = true;
  399. await Task.Run(() =>
  400. {
  401. InABox.Core.Location curlocation = new InABox.Core.Location() { Latitude = App.GPS.Latitude, Longitude = App.GPS.Longitude };
  402. curlocation.Timestamp = DateTime.Now;
  403. List<GPSTrackerLocation> trackersToUpdate = new List<GPSTrackerLocation>();
  404. foreach (String id in App.Bluetooth.DetectedBlueToothMACAddresses)
  405. {
  406. GPSTracker tracker = GlobalVariables.GPSTrackerCache.Find(x => x.DeviceID.Equals(id));
  407. bool stale = tracker.Location.Timestamp < DateTime.Now.Subtract(new TimeSpan(0, 5, 0));
  408. bool moved = tracker.Location.DistanceTo(curlocation, UnitOfLength.Kilometers) > 0.1;
  409. if (stale || moved)
  410. {
  411. GlobalVariables.GPSTrackerCache.Remove(tracker);
  412. tracker.Location = curlocation;
  413. GlobalVariables.GPSTrackerCache.Add(tracker);
  414. //cache is updated
  415. GPSTrackerLocation gpsTrackerLocation = new GPSTrackerLocation();
  416. gpsTrackerLocation.DeviceID = tracker.DeviceID;
  417. gpsTrackerLocation.Location.Timestamp = tracker.Location.Timestamp;
  418. gpsTrackerLocation.Location = curlocation;
  419. trackersToUpdate.Add(gpsTrackerLocation);
  420. }
  421. }
  422. if (trackersToUpdate.Any())
  423. {
  424. if (ClientFactory.UserGuid != Guid.Empty)
  425. new Client<GPSTrackerLocation>().Save(trackersToUpdate, "Updating Bluetooth Device Locations");
  426. }
  427. App.Bluetooth.DetectedBlueToothMACAddresses.Clear();
  428. }
  429. );
  430. }
  431. catch (Exception e)
  432. {
  433. }
  434. //if ((master != null) && (master.Location.Timestamp < DateTime.Now.Subtract(new TimeSpan(0, 15, 0))))
  435. //{
  436. // GPSTrackerLocation device = new GPSTrackerLocation();
  437. // device.DeviceID = MobileUtils.GetDeviceID();
  438. // device.Location.Latitude = App.GPS.Latitude;
  439. // device.Location.Longitude = App.GPS.Longitude;
  440. // device.Location.Timestamp = DateTime.Now;
  441. // locations.Add(device);
  442. // //device.BatteryLevel = ((double)CrossBattery.Current.RemainingChargePercent);
  443. // //new Client<GPSTrackerLocation>().Save(device, "Updating Device Location"); //, SaveTrackerCallback);
  444. //}
  445. #region OLD
  446. //for (int i = 0; i < App.Bluetooth.Devices.Length; i++)
  447. //{
  448. // String id = App.Bluetooth.Devices[i];
  449. // int level = App.Bluetooth.BatteryLevels[i];
  450. // var btmaster = trackers.FirstOrDefault(x => x.DeviceID.Equals(id));
  451. // if ((btmaster != null) && (!locations.Any(x => x.DeviceID.Equals(btmaster.DeviceID))))
  452. // {
  453. // bool stale = btmaster.Location.Timestamp < DateTime.Now.Subtract(new TimeSpan(0, 15, 0));
  454. // bool moved = btmaster.Location.DistanceTo(curlocation, UnitOfLength.Kilometers) > 0.1;
  455. // if (stale || moved)
  456. // {
  457. // GPSTrackerLocation location = new GPSTrackerLocation();
  458. // location.DeviceID = id;
  459. // location.Location.Latitude = App.GPS.Latitude;
  460. // location.Location.Longitude = App.GPS.Longitude;
  461. // location.Location.Timestamp = DateTime.Now;
  462. // location.BatteryLevel = level;
  463. // locations.Add(location);
  464. // }
  465. // }
  466. // //new Client<GPSTrackerLocation>().Save(location, "Found Kontakt Device"); //, SaveTrackerCallback);
  467. //}
  468. //if (locations.Any())
  469. // new Client<GPSTrackerLocation>().Save(locations, "Updating Bluetooth Device Locations", (o, e) => { });
  470. #endregion
  471. }
  472. private void RecentlyUpdatedTilesTimer(object o)
  473. {
  474. bRecentlyUpdatedTiles = false;
  475. App.Data.Refresh(true);
  476. MainPageUtils.SearchForNewNotifications();
  477. }
  478. private void LocationFound(LocationServices sender)
  479. {
  480. //if (bSharedDevice)
  481. // return;
  482. if (App.Bluetooth.RecentlyScanned)
  483. UploadTiles();
  484. try
  485. {
  486. TimeSheet timesheet = App.Data.TimeSheets?.Rows.FirstOrDefault()?.ToObject<TimeSheet>();
  487. if (timesheet != null)
  488. {
  489. if (timesheet.StartLocation.Latitude.Equals(0.0F) && timesheet.StartLocation.Longitude.Equals(0.0F))
  490. {
  491. timesheet.StartLocation.Latitude = sender.Latitude;
  492. timesheet.StartLocation.Longitude = sender.Longitude;
  493. timesheet.StartLocation.Timestamp = sender.TimeStamp;
  494. timesheet.Address = sender.Address;
  495. new Client<TimeSheet>().Save(timesheet, "Updating Timesheet with GPS Coordinates", (o, e) => { });
  496. }
  497. }
  498. if (!string.IsNullOrWhiteSpace(matchedDeviceName))
  499. {
  500. InABox.Core.Location curlocation = new InABox.Core.Location() { Latitude = App.GPS.Latitude, Longitude = App.GPS.Longitude };
  501. curlocation.Timestamp = DateTime.Now;
  502. GPSTrackerLocation gpsTrackerLocation = new GPSTrackerLocation();
  503. gpsTrackerLocation.DeviceID = matchedDeviceName;
  504. gpsTrackerLocation.Location.Timestamp = curlocation.Timestamp;
  505. gpsTrackerLocation.Location = curlocation;
  506. new Client<GPSTrackerLocation>().Save(gpsTrackerLocation, "Updated company device location from Timebench");
  507. }
  508. Device.BeginInvokeOnMainThread(() =>
  509. {
  510. RefreshScreen();
  511. });
  512. }
  513. catch { }
  514. }
  515. private void LocationError(LocationServices sebder, Exception error)
  516. {
  517. }
  518. private void ScanFinished(Bluetooth sender)
  519. {
  520. try
  521. {
  522. //if (bSharedDevice)
  523. // return;
  524. Device.BeginInvokeOnMainThread(() =>
  525. {
  526. RefreshScreen();
  527. //if (Button2.BackgroundColor == Color.WhiteSmoke)
  528. // Button2.BackgroundColor = Color.Red;
  529. //else
  530. // Button2.BackgroundColor = Color.WhiteSmoke;
  531. });
  532. if (App.GPS.RecentlyLocated)
  533. UploadTiles();
  534. }
  535. catch { }
  536. }
  537. #endregion
  538. #region Utilities
  539. private void InitNotificationCentre()
  540. {
  541. LocalNotificationCenter.Current.NotificationActionTapped += (Plugin.LocalNotification.EventArgs.NotificationActionEventArgs e) =>
  542. {
  543. if (MainPageUtils.DetermineCorrectPage(e) != null)
  544. {
  545. Device.BeginInvokeOnMainThread(() =>
  546. {
  547. Navigation.PushAsync(MainPageUtils.DetermineCorrectPage(e));
  548. });
  549. }
  550. };
  551. MainPageUtils.OnMainPageNotificationsChanged += RefreshOnNotificationsChange;
  552. }
  553. private void RefreshOnNotificationsChange()
  554. {
  555. try
  556. {
  557. int index = toolEntries.FindIndex(x => x.Text.Equals("Notifications"));
  558. toolEntries.RemoveAt(index);
  559. string notificationsString = "";
  560. if (NumberOfNotfications != 0)
  561. {
  562. notificationsString = NumberOfNotfications.ToString();
  563. }
  564. ToolEntry Notifications = new ToolEntry(notificationsString)
  565. {
  566. Text = "Notifications",
  567. Image = "notifications"
  568. };
  569. Notifications.OnTapped += (async (object sender, EventArgs e) =>
  570. {
  571. using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Loading"))
  572. {
  573. NotificationList notificationList = new NotificationList();
  574. notificationList.NotificationsClosed += (n) =>
  575. {
  576. NumberOfNotfications = n;
  577. RefreshOnNotificationsChange();
  578. };
  579. Navigation.PushAsync(notificationList);
  580. }
  581. });
  582. toolEntries.Insert(index, Notifications);
  583. Device.BeginInvokeOnMainThread(() =>
  584. {
  585. flexLayout.Children.RemoveAt(index);
  586. flexLayout.Children.Insert(index, toolEntries[index]);
  587. });
  588. }
  589. catch { }
  590. }
  591. private void CheckNotificationsPushed(CoreTable table)
  592. {
  593. try
  594. {
  595. if (!Application.Current.Properties.ContainsKey("LastPushedNotifications"))
  596. {
  597. Application.Current.Properties.Add("LastPushedNotifications", DateTime.Now);
  598. }
  599. DateTime lastPushed = DateTime.Parse(Application.Current.Properties["LastPushedNotifications"].ToString());
  600. List<NotificationShell> toNotify = new List<NotificationShell>();
  601. foreach (CoreRow row in table.Rows)
  602. {
  603. List<object> list = row.Values;
  604. DateTime created = DateTime.Parse(list[3].ToString());
  605. if (created > new DateTime(2022, 8, 22)) // prevent spam from buildup of old notifications before this is released
  606. {
  607. if (created > lastPushed)
  608. {
  609. if (list[1] == null) list[1] = "";
  610. if (list[2] == null) list[2] = "";
  611. if (list[3] == null) list[3] = DateTime.MinValue;
  612. if (list[4] == null) list[4] = "";
  613. if (list[5] == null) list[5] = "";
  614. if (list[6] == null) list[6] = Guid.Empty;
  615. NotificationShell shell = new NotificationShell
  616. {
  617. ID = Guid.Parse(list[0].ToString()),
  618. Sender = list[1].ToString(),
  619. Title = list[2].ToString(),
  620. Created = DateTime.Parse(list[3].ToString()),
  621. EntityType = list[5].ToString(),
  622. EntityID = Guid.Parse(list[6].ToString())
  623. };
  624. toNotify.Add(shell); //add notification to be pushed
  625. }
  626. }
  627. }
  628. if (toNotify.Count > 0)
  629. PushNotificationsAsync(toNotify);
  630. }
  631. catch { }
  632. }
  633. private async Task PushNotificationsAsync(List<NotificationShell> shells)
  634. {
  635. try
  636. {
  637. int count = 1;
  638. foreach (NotificationShell shell in shells)
  639. {
  640. var notification = new NotificationRequest
  641. {
  642. BadgeNumber = 1,
  643. Description = shell.Title,
  644. Title = "New PRS Notification: ",
  645. ReturningData = shell.EntityID.ToString() + "$" + shell.EntityType,
  646. NotificationId = count,
  647. };
  648. count++;
  649. NotificationImage img = new NotificationImage();
  650. img.ResourceName = "icon16.png";
  651. notification.Image = img;
  652. await LocalNotificationCenter.Current.Show(notification);
  653. }
  654. Application.Current.Properties["LastPushedNotifications"] = DateTime.Now;
  655. }
  656. catch { }
  657. }
  658. private void StartMidnightTimeSheetTimer()
  659. {
  660. midnightTimerOn = true;
  661. int msUntilMidnight = (int)(oneSecondBeforeMidnight - DateTime.Now).TotalMilliseconds;
  662. Timer midnightTimer = new Timer(MidnightTimerCallback, null, msUntilMidnight, Timeout.Infinite);
  663. }
  664. private void MidnightTimerCallback(object o)
  665. {
  666. try
  667. {
  668. //if (bSharedDevice)
  669. // return;
  670. if (midnightTimerOn)
  671. {
  672. if (clockOnButton.Text == "CLOCK OFF")
  673. {
  674. InABox.Core.Location here = new InABox.Core.Location()
  675. {
  676. Latitude = App.GPS.Latitude,
  677. Longitude = App.GPS.Longitude,
  678. Timestamp = DateTime.Now
  679. };
  680. TimeSheet timesheet = App.Data.TimeSheets?.Rows.FirstOrDefault()?.ToObject<TimeSheet>();
  681. if (timesheet != null)
  682. {
  683. if (timesheet.ID != Guid.Empty)
  684. {
  685. if (ZeroLengthTimesheet())
  686. {
  687. bUpdatingTimesheet = true;
  688. new Client<TimeSheet>().Delete(timesheet, "Deleted due to zero duration timesheet");
  689. App.Data.TimeSheets.Rows.Clear();
  690. }
  691. else
  692. {
  693. timesheet.Finish = new TimeSpan(23, 59, 59);
  694. timesheet.FinishLocation = here;
  695. bUpdatingTimesheet = true;
  696. new Client<TimeSheet>().Save(timesheet, "Auto Close timesheet at Midnight");
  697. App.Data.TimeSheets.Rows.Clear();
  698. Guid jobid = Guid.Empty;
  699. String jobnumber = "";
  700. String jobname = "";
  701. if (!App.Data.CanBypassGates)
  702. {
  703. CoreRow row = App.Data.Gates.Rows.FirstOrDefault(r => App.Bluetooth.Devices.Contains(r.Get<JobTracker, String>(c => c.TrackerLink.DeviceID)));
  704. if (row != null)
  705. {
  706. jobid = row.Get<JobTracker, Guid>(x => x.JobLink.ID);
  707. jobnumber = row.Get<JobTracker, String>(x => x.JobLink.JobNumber);
  708. jobname = row.Get<JobTracker, String>(x => x.JobLink.Name);
  709. }
  710. CreateTimeSheet(jobid, jobnumber, jobname, here, App.GPS.Address, "Clocking On");
  711. }
  712. else
  713. {
  714. if ((!App.GPS.Latitude.Equals(0.0F)) && (!App.GPS.Longitude.Equals(0.0F)))
  715. {
  716. ChooseNearbyJob(here);
  717. }
  718. }
  719. }
  720. }
  721. }
  722. }
  723. }
  724. }
  725. catch { }
  726. }
  727. private void FinishTimeSheet(TimeSheet timesheet, InABox.Core.Location here)
  728. {
  729. try
  730. {
  731. TimeSpan tod = DateTime.Now - DateTime.Today;
  732. timesheet.Finish = new TimeSpan(tod.Hours, tod.Minutes, 0);
  733. timesheet.FinishLocation = here;
  734. bUpdatingTimesheet = true;
  735. new Client<TimeSheet>().Save(timesheet, "Clocking Off");
  736. App.Data.TimeSheets.Rows.Clear();
  737. midnightTimerOn = false;
  738. Timer last60Seconds = new Timer(Last60SecondsTimerCallBack, null, 5000, Timeout.Infinite);
  739. clockedOffInLast5Seconds = true;
  740. if (MainPageUtils.CurrentAssignment != null)
  741. {
  742. MainPageUtils.SaveCurrentAssignment("PRS Mobile - clocking off", true);
  743. MainPageUtils.CurrentAssignment = null;
  744. }
  745. }
  746. catch { }
  747. }
  748. private void Last60SecondsTimerCallBack(object o)
  749. {
  750. clockedOffInLast5Seconds = false;
  751. }
  752. private async void ChooseNearbyJob(InABox.Core.Location here)
  753. {
  754. try
  755. {
  756. JobShell selectedJob = new JobShell();
  757. Dictionary<string, JobShell> nearbyJobs = new Dictionary<string, JobShell>();
  758. foreach (CoreRow row in App.Data.Jobs.Rows)
  759. {
  760. InABox.Core.Location jobLocation = new InABox.Core.Location() { Latitude = row.Get<Job, double>(X => X.SiteAddress.Location.Latitude), Longitude = row.Get<Job, double>(X => X.SiteAddress.Location.Longitude) };
  761. double distance = here.DistanceTo(jobLocation, UnitOfLength.Kilometers);
  762. if (distance < 1.0F)
  763. {
  764. JobShell jobShell = new JobShell();
  765. jobShell.ID = row.Get<Job, Guid>(X => X.ID);
  766. jobShell.JobNumber = row.Get<Job, String>(x => x.JobNumber);
  767. jobShell.Name = row.Get<Job, String>(x => x.Name);
  768. jobShell.DisplayName = jobShell.JobNumber + " " + jobShell.Name;
  769. nearbyJobs.Add(jobShell.DisplayName, jobShell);
  770. }
  771. }
  772. if (nearbyJobs.Count > 1)
  773. {
  774. string[] array = nearbyJobs.Keys.ToArray();
  775. string chosenOption = await DisplayActionSheet("Choose job site", "Cancel", null, array);
  776. if (string.IsNullOrEmpty(chosenOption) || chosenOption.Equals("Cancel"))
  777. {
  778. CreateTimeSheet(selectedJob.ID, selectedJob.JobNumber, selectedJob.Name, here, App.GPS.Address, "Clocking On");
  779. return;
  780. }
  781. else
  782. {
  783. selectedJob = nearbyJobs[chosenOption];
  784. }
  785. }
  786. else if (nearbyJobs.Count == 1)
  787. {
  788. selectedJob = nearbyJobs.Values.First();
  789. }
  790. CreateTimeSheet(selectedJob.ID, selectedJob.JobNumber, selectedJob.Name, here, App.GPS.Address, "Clocking On");
  791. }
  792. catch { }
  793. }
  794. void AddNote_Tapped(System.Object sender, System.EventArgs e)
  795. {
  796. try
  797. {
  798. TimeSheet timesheet = App.Data.TimeSheets?.Rows.FirstOrDefault()?.ToObject<TimeSheet>();
  799. if (timesheet == null)
  800. return;
  801. var notepage = new NotePage(timesheet);
  802. Navigation.PushAsync(notepage);
  803. }
  804. catch { }
  805. }
  806. private void TaskBtn_Tapped(object sender, EventArgs e)
  807. {
  808. ListSelectionPage page = new ListSelectionPage(MainPageUtils.GetTasks());
  809. page.OnDictionaryItemTapped += (id, title) =>
  810. {
  811. MainPageUtils.OnTaskSelected(id, title);
  812. };
  813. Navigation.PushAsync(page);
  814. }
  815. private async void RequestUserInput(Guid taskID)
  816. {
  817. const string addtask = "Change current assignment task";
  818. const string newassignment = "Start a new assignment with this task";
  819. string chosenOption = await DisplayActionSheet("Choose an option", "Cancel", null, addtask, newassignment);
  820. switch (chosenOption)
  821. {
  822. case addtask:
  823. MainPageUtils.ChangeAssignmentTask(taskID);
  824. break;
  825. case newassignment:
  826. MainPageUtils.SaveCurrentAssignment("PRS Mobile main screen - saving assignment on task change", true);
  827. MainPageUtils.CreateNewAssignment(Guid.Empty, taskID);
  828. break;
  829. default:
  830. break;
  831. }
  832. }
  833. private void JobBtn_Tapped(object sender, EventArgs e)
  834. {
  835. try
  836. {
  837. JobSelectionPage jobSelectionPage = new JobSelectionPage();
  838. jobSelectionPage.OnItemSelected += (() =>
  839. {
  840. MainPageUtils.Job.ID = jobSelectionPage.Job.ID;
  841. MainPageUtils.Job.JobNumber = jobSelectionPage.Job.JobNumber;
  842. MainPageUtils.Job.Name = jobSelectionPage.Job.Name;
  843. RefreshScreen();
  844. JobPage_OnItemSelected(jobSelectionPage.Job);
  845. });
  846. Navigation.PushAsync(jobSelectionPage);
  847. }
  848. catch { }
  849. }
  850. private void JobPage_OnItemSelected(JobShell job)
  851. {
  852. //try
  853. //{
  854. // TimeSheet timesheet = App.Data.TimeSheets?.Rows.FirstOrDefault()?.ToObject<TimeSheet>();
  855. // if (timesheet == null)
  856. // return;
  857. // String auditmessage = String.Format("Changed Selected Job to: {0}: {1}", timesheet.JobLink.JobNumber, timesheet.JobLink.Name);
  858. // if (ZeroLengthTimesheet())
  859. // {
  860. // timesheet.JobLink.ID = job.ID;
  861. // timesheet.JobLink.JobNumber = job.JobNumber;
  862. // timesheet.JobLink.Name = job.Name;
  863. // bUpdatingTimesheet = true;
  864. // new Client<TimeSheet>().Save(timesheet, auditmessage);
  865. // Device.BeginInvokeOnMainThread(() =>
  866. // {
  867. // if (timesheet.JobLink.ID != Guid.Empty)
  868. // {
  869. // jobBtn.Text = "(" + timesheet.JobLink.JobNumber + ") " + timesheet.JobLink.Name;
  870. // }
  871. // else
  872. // {
  873. // jobBtn.Text = "No Job Selected";
  874. // }
  875. // });
  876. // }
  877. // else
  878. // {
  879. // InABox.Core.Location here = new InABox.Core.Location()
  880. // {
  881. // Latitude = App.GPS.Latitude,
  882. // Longitude = App.GPS.Longitude,
  883. // Timestamp = DateTime.Now
  884. // };
  885. // TimeSpan tod = DateTime.Now - DateTime.Today;
  886. // timesheet.Finish = new TimeSpan(tod.Hours, tod.Minutes, 0);
  887. // timesheet.FinishLocation = here;
  888. // new Client<TimeSheet>().Save(timesheet, "Changing Job");
  889. // CreateTimeSheet(
  890. // job.ID,
  891. // job.JobNumber,
  892. // job.Name,
  893. // here,
  894. // App.GPS.Address,
  895. // auditmessage
  896. // );
  897. // }
  898. // RefreshScreen();
  899. //}
  900. //catch { }
  901. }
  902. private bool CheckTimeSheetAgainstGates(TimeSheet timesheet)
  903. {
  904. DateTime now = DateTime.Now;
  905. //var timesheet = CurrentTimeSheet();
  906. //Can't confirm if there is no timesheet
  907. if (timesheet == null)
  908. return false;
  909. // Can't confirm if there are no devices
  910. if (App.Bluetooth.Devices.Length == 0)
  911. return false;
  912. if (App.Data.Gates == null)
  913. return false;
  914. long tsTicks = timesheet.Date.Add(timesheet.Start).Ticks;
  915. long btTicks = App.Bluetooth.TimeStamp.Ticks;
  916. if (Math.Abs(tsTicks - btTicks) > new TimeSpan(0, 2, 0).Ticks)
  917. return false;
  918. CoreRow firstgate = null;
  919. List<String> gates = new List<string>();
  920. // Scan every located d
  921. foreach (var device in App.Bluetooth.Devices)
  922. {
  923. CoreRow gate = App.Data.Gates?.Rows.FirstOrDefault(r => r.Get<JobTracker, String>(c => c.TrackerLink.DeviceID) == device);
  924. if (gate != null)
  925. {
  926. if ((gate.Get<JobTracker, bool>(x => x.IsJobSite) == true) && (firstgate == null))
  927. firstgate = gate;
  928. gates.Add(gate.Get<JobTracker, String>(x => x.Gate));
  929. }
  930. }
  931. if (gates.Any())
  932. {
  933. timesheet.Gate = String.Join(", ", gates.OrderBy(x => x));
  934. if (firstgate != null)
  935. {
  936. timesheet.JobLink.ID = firstgate.Get<JobTracker, Guid>(x => x.JobLink.ID);
  937. timesheet.JobLink.JobNumber = firstgate.Get<JobTracker, String>(x => x.JobLink.JobNumber);
  938. timesheet.JobLink.Name = firstgate.Get<JobTracker, String>(x => x.JobLink.Name);
  939. }
  940. return true;
  941. //new Client<TimeSheet>().Save(timesheet, "Confirmed Gate Entry by Bluetooth Tracker", (o, e) => { });
  942. }
  943. return false;
  944. }
  945. private bool ZeroLengthTimesheet()
  946. {
  947. try
  948. {
  949. if (App.Data.TimeSheets == null)
  950. return true;
  951. CoreRow row = App.Data.TimeSheets.Rows.FirstOrDefault();
  952. if (row == null)
  953. return true;
  954. String notes = row.Get<TimeSheet, String>(x => x.Notes);
  955. if (!String.IsNullOrWhiteSpace(notes))
  956. return false;
  957. DateTime date = row.Get<TimeSheet, DateTime>(x => x.Date);
  958. TimeSpan start = row.Get<TimeSheet, TimeSpan>(x => x.Start);
  959. if (date.Equals(DateTime.Today))
  960. {
  961. TimeSpan tod = DateTime.Now - DateTime.Today;
  962. var diff = (tod - start).TotalSeconds;
  963. if (Math.Abs(diff) < 120.0F)
  964. return true;
  965. }
  966. }
  967. catch { }
  968. return false;
  969. }
  970. private async void CreateTimeSheet(Guid jobid, string jobnumber, String jobname, InABox.Core.Location location, String address, String auditmessage)
  971. {
  972. try
  973. {
  974. var timesheet = new TimeSheet();
  975. using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Loading"))
  976. {
  977. timesheet.EmployeeLink.ID = GlobalVariables.EmpID;
  978. timesheet.Date = DateTime.Today;
  979. TimeSpan tod = DateTime.Now - DateTime.Today;
  980. tod = new TimeSpan(tod.Hours, tod.Minutes, 0);
  981. timesheet.Start = tod;
  982. timesheet.StartLocation = location;
  983. timesheet.JobLink.ID = jobid;
  984. timesheet.JobLink.JobNumber = jobnumber;
  985. timesheet.JobLink.Name = jobname;
  986. timesheet.Address = address;
  987. timesheet.SoftwareVersion = MobileUtils.AppVersion.InstalledVersionNumber + GlobalVariables.DeviceString;
  988. //if (ClientFactory.IsAllowed<AllowTimeSheetRollover>()) CheckTimeSheetAgainstGates(timesheet);
  989. bUpdatingTimesheet = true;
  990. new Client<TimeSheet>().Save(timesheet, auditmessage);
  991. if (timesheet.ID == Guid.Empty)
  992. {
  993. DisplayAlert("Error creating new timesheet", "Please check your connection and try again", "OK");
  994. return;
  995. }
  996. StartMidnightTimeSheetTimer();
  997. // Don't Save Completed Timesheets!
  998. App.Data.TimeSheets.Rows.Clear();
  999. if (timesheet.Finish.Ticks == 0L)
  1000. {
  1001. CoreRow row = App.Data.TimeSheets.NewRow();
  1002. App.Data.TimeSheets.LoadRow(row, timesheet);
  1003. App.Data.TimeSheets.Rows.Add(row);
  1004. }
  1005. }
  1006. Device.BeginInvokeOnMainThread(() =>
  1007. {
  1008. if (timesheet.JobLink.ID != Guid.Empty)
  1009. {
  1010. jobBtn.Text = "(" + timesheet.JobLink.JobNumber + ") " + timesheet.JobLink.Name;
  1011. }
  1012. else
  1013. {
  1014. jobBtn.Text = "No Job Selected";
  1015. }
  1016. });
  1017. }
  1018. catch { }
  1019. }
  1020. private bool CheckLocation()
  1021. {
  1022. try
  1023. {
  1024. if (App.Data.CanBypassGates)
  1025. {
  1026. if (App.GPS.TimeStamp > DateTime.Now.Subtract(new TimeSpan(0, 5, 0)))
  1027. return true;
  1028. else
  1029. return false;
  1030. }
  1031. if (App.Data.Gates == null)
  1032. return false;
  1033. if (App.Bluetooth.TimeStamp < DateTime.Now.Subtract(new TimeSpan(0, 2, 0)))
  1034. return false;
  1035. if (!App.Bluetooth.Devices.Any())
  1036. return false;
  1037. return App.Data.Gates.Rows.Any(r => App.Bluetooth.Devices.Contains(r.Get<JobTracker, String>(c => c.TrackerLink.DeviceID)));
  1038. }
  1039. catch
  1040. {
  1041. return true;
  1042. }
  1043. }
  1044. private String DisplayAddress()
  1045. {
  1046. try
  1047. {
  1048. bool PRSReady = App.Data.Employee != null; // && (TimeSheet != null); // && (Activities != null);
  1049. if (!PRSReady)
  1050. return "Retrieving Data";
  1051. if (App.Data.CanBypassGates)
  1052. {
  1053. if (App.GPS.TimeStamp < DateTime.Now.Subtract(new TimeSpan(0, 5, 0)))
  1054. {
  1055. App.GPS.GetLocation(true);
  1056. return "Searching for GPS";
  1057. }
  1058. else
  1059. return App.GPS.Address;
  1060. }
  1061. else
  1062. {
  1063. // Hmm.. this can/should be simplified
  1064. // if in range of a gate
  1065. // Show Gate Description
  1066. // else
  1067. // "Looking for Gate"
  1068. if ((App.Data.Gates != null) && (App.Bluetooth.TimeStamp > DateTime.Now.Subtract(new TimeSpan(0, 2, 0))))
  1069. {
  1070. CoreRow row = App.Data.Gates.Rows.FirstOrDefault(r => App.Bluetooth.Devices.Contains(r.Get<JobTracker, String>(c => c.TrackerLink.DeviceID)));
  1071. if (row != null)
  1072. return row.Get<JobTracker, String>(x => x.Gate);
  1073. //else if ((CurrentTimeSheet() != null) && (!GPS.TimeStamp.IsEmpty()))
  1074. // return GPS.Address;
  1075. else
  1076. return "Looking for Gate";
  1077. }
  1078. //else if ((CurrentTimeSheet() != null) && (GPS.TimeStamp > DateTime.Now.Subtract(new TimeSpan(0, 2, 0))))
  1079. // return GPS.Address;
  1080. else
  1081. return "Looking for Gate";
  1082. }
  1083. }
  1084. catch
  1085. {
  1086. return "Address error";
  1087. }
  1088. }
  1089. #region Background Loading
  1090. private void LoadCacheLists()
  1091. {
  1092. GlobalVariables.ProductsLoaded = false;
  1093. GlobalVariables.JobsLoaded = false;
  1094. GlobalVariables.GetXamarinWidth();
  1095. CacheLoader.LoadJobs();
  1096. LoadEmployeeShells();
  1097. //spread out loading
  1098. Task.Run(() =>
  1099. {
  1100. Thread.Sleep(1000);
  1101. LoadCompanyDevices();
  1102. LoadBlueToothAddresses();
  1103. Thread.Sleep(1000);
  1104. LoadProducts();
  1105. });
  1106. //LoadHRToDos(); to be uncommented when ready for roll out
  1107. }
  1108. private void LoadCompanyDevices()
  1109. {
  1110. Task.Run(() =>
  1111. {
  1112. if (!string.IsNullOrWhiteSpace(MainPageUtils.deviceName) && MainPageUtils.deviceName != "unknown")
  1113. {
  1114. List<Equipment> companyDevices = new List<Equipment>();
  1115. CoreTable table = new Client<Equipment>().Query
  1116. (
  1117. new Filter<Equipment>(x => x.GroupLink.Code).IsEqualTo("DEVICE"),
  1118. new Columns<Equipment>(
  1119. x => x.TrackerLink.DeviceID
  1120. )
  1121. );
  1122. if (table.Rows.Any())
  1123. {
  1124. foreach (CoreRow row in table.Rows)
  1125. {
  1126. List<object> list = row.Values;
  1127. if (list[0].ToString().Equals(MainPageUtils.deviceName))
  1128. {
  1129. matchedDeviceName = MainPageUtils.deviceName;
  1130. }
  1131. }
  1132. }
  1133. }
  1134. });
  1135. }
  1136. private void LoadEmployeeShells()
  1137. {
  1138. Task.Run(() =>
  1139. {
  1140. try
  1141. {
  1142. List<EmployeeShell> employeeShells = new List<EmployeeShell>();
  1143. List<EmployeeShell> teamEmployeeShells = new List<EmployeeShell>();
  1144. MultiQuery query = new MultiQuery();
  1145. query.Add<Employee>(
  1146. LookupFactory.DefineFilter<Employee>(),
  1147. new Columns<Employee>(x => x.ID)
  1148. .Add(x => x.Code)
  1149. .Add(x => x.Name),
  1150. LookupFactory.DefineSort<Employee>()
  1151. );
  1152. query.Add<Team>(
  1153. LookupFactory.DefineFilter<Team>(),
  1154. new Columns<Team>(x => x.Name),
  1155. new SortOrder<Team>(x => x.Name)
  1156. );
  1157. query.Add<EmployeeTeam>(
  1158. LookupFactory.DefineFilter<EmployeeTeam>(),
  1159. new Columns<EmployeeTeam>(x => x.EmployeeLink.ID)
  1160. .Add(x => x.EmployeeLink.Code)
  1161. .Add(x => x.EmployeeLink.Name)
  1162. .Add(x => x.TeamLink.Name),
  1163. new SortOrder<EmployeeTeam>(x => x.EmployeeLink.Name)
  1164. );
  1165. query.Query();
  1166. CoreTable emps = query.Get<Employee>();
  1167. foreach (var row in emps.Rows)
  1168. {
  1169. employeeShells.Add(
  1170. new EmployeeShell()
  1171. {
  1172. ID = row.Get<Employee, Guid>(x => x.ID),
  1173. Code = row.Get<Employee, String>(x => x.Code),
  1174. Name = row.Get<Employee, String>(x => x.Name),
  1175. TeamName = "All Staff"
  1176. }
  1177. );
  1178. }
  1179. GlobalVariables.TeamNames = query.Get<Team>().Rows.Select(r => r.Get<Team, String>(c => c.Name)).ToList();
  1180. CoreTable members = query.Get<EmployeeTeam>();
  1181. foreach (var row in members.Rows)
  1182. {
  1183. teamEmployeeShells.Add(
  1184. new EmployeeShell()
  1185. {
  1186. ID = row.Get<EmployeeTeam, Guid>(x => x.EmployeeLink.ID),
  1187. Code = row.Get<EmployeeTeam, String>(x => x.EmployeeLink.Code),
  1188. Name = row.Get<EmployeeTeam, String>(x => x.EmployeeLink.Name),
  1189. TeamName = row.Get<EmployeeTeam, String>(x => x.TeamLink.Name)
  1190. }
  1191. );
  1192. }
  1193. GlobalVariables.EmployeeShells = employeeShells;
  1194. GlobalVariables.TeamEmployeeShells = teamEmployeeShells;
  1195. }
  1196. catch (Exception e)
  1197. {
  1198. }
  1199. });
  1200. }
  1201. private async void LoadHRToDos()
  1202. {
  1203. try
  1204. {
  1205. await Task.Run(() =>
  1206. {
  1207. Thread.Sleep(10000);
  1208. if (GlobalVariables.UpdateHRItemsNeedingAttention())
  1209. {
  1210. string message = "You have HR Items needing attention. Open My HR now?";
  1211. Device.BeginInvokeOnMainThread(async () =>
  1212. {
  1213. string chosenOption = await DisplayActionSheet(message, "Cancel", null, "Yes", "No");
  1214. switch (chosenOption)
  1215. {
  1216. case "Cancel":
  1217. break;
  1218. case "No":
  1219. break;
  1220. default:
  1221. break;
  1222. case "Yes":
  1223. MyHRHome myHRHome = new MyHRHome();
  1224. Navigation.PushAsync(myHRHome);
  1225. break;
  1226. }
  1227. });
  1228. }
  1229. });
  1230. }
  1231. catch { }
  1232. }
  1233. private void LoadProducts()
  1234. {
  1235. try
  1236. {
  1237. Task.Run(() =>
  1238. {
  1239. ProductsLoader productsLoader = new ProductsLoader();
  1240. });
  1241. }
  1242. catch { }
  1243. }
  1244. private async void LoadBlueToothAddresses()
  1245. {
  1246. try
  1247. {
  1248. //if (bSharedDevice)
  1249. // return;
  1250. await Task.Run(() =>
  1251. {
  1252. GlobalVariables.GPSTrackerCache = new List<GPSTracker>();
  1253. CoreTable table = new Client<GPSTracker>().Query(new Filter<GPSTracker>(x => x.Type.Description).Contains("Kontakt"));
  1254. foreach (CoreRow row in table.Rows)
  1255. {
  1256. GPSTracker tracker = row.ToObject<GPSTracker>();
  1257. GlobalVariables.GPSTrackerCache.Add(tracker);
  1258. App.Bluetooth.KnownBlueToothMACAddresses.Add(tracker.DeviceID);
  1259. }
  1260. });
  1261. }
  1262. catch { }
  1263. }
  1264. #endregion
  1265. #endregion
  1266. #region Modules
  1267. public async void InitToolEntryList()
  1268. {
  1269. try
  1270. {
  1271. await Task.Run(() =>
  1272. {
  1273. //Assignments
  1274. ToolEntry Assignments = new ToolEntry
  1275. {
  1276. Text = "Assignments",
  1277. Image = "calendar"
  1278. };
  1279. Assignments.OnTapped += ((object sender, EventArgs e) =>
  1280. {
  1281. var assignment_form = new AssignmentList();
  1282. Navigation.PushAsync(assignment_form);
  1283. });
  1284. if (PRSSecurity.CanView<Assignment>())
  1285. toolEntries.Add(Assignments);
  1286. //Deliveries
  1287. ToolEntry Deliveries = new ToolEntry
  1288. {
  1289. Text = "Deliveries",
  1290. Image = "deliveries"
  1291. };
  1292. Deliveries.OnTapped += ((object sender, EventArgs e) =>
  1293. {
  1294. if (GlobalVariables.IsDeliveryDriver)
  1295. {
  1296. var delivery_form = new DeliveryList();
  1297. Navigation.PushAsync(delivery_form);
  1298. }
  1299. else
  1300. {
  1301. DataGridHost host = new DataGridHost(new DeliveryGrid());
  1302. host.SetActionButton("Add");
  1303. host.OnActionButtonClicked += ((list) =>
  1304. {
  1305. DeliveryDetails details = new DeliveryDetails(Guid.Empty);
  1306. details.OnDeliverySaved += () => { (host.DataGrid as DeliveryGrid).RefreshGrid(); };
  1307. Navigation.PushAsync(details);
  1308. });
  1309. Navigation.PushAsync(host);
  1310. }
  1311. });
  1312. if (PRSSecurity.CanView<Delivery>())
  1313. toolEntries.Add(Deliveries);
  1314. //Digital Forms
  1315. ToolEntry Forms = new ToolEntry
  1316. {
  1317. Text = "Forms",
  1318. Image = "forms"
  1319. };
  1320. Forms.OnTapped += ((object sender, EventArgs e) =>
  1321. {
  1322. var qaFormPicker = new DigitalFormsPicker();
  1323. Navigation.PushAsync(qaFormPicker);
  1324. });
  1325. if (PRSSecurity.CanView<DigitalForm>())
  1326. toolEntries.Add(Forms);
  1327. //Equipment
  1328. ToolEntry Equipment = new ToolEntry
  1329. {
  1330. Text = "Equipment",
  1331. Image = "digger"
  1332. };
  1333. Equipment.OnTapped += (async (object sender, EventArgs e) =>
  1334. {
  1335. using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Loading"))
  1336. {
  1337. var equipment = new EquipmentModule();
  1338. Navigation.PushAsync(equipment);
  1339. }
  1340. });
  1341. if (PRSSecurity.CanView<Equipment>())
  1342. toolEntries.Add(Equipment);
  1343. //InOut
  1344. ToolEntry InOut = new ToolEntry
  1345. {
  1346. Text = "In/Out",
  1347. Image = "inout"
  1348. };
  1349. InOut.OnTapped += ((object sender, EventArgs e) =>
  1350. {
  1351. var staff_form = new StaffStatusPage();
  1352. Navigation.PushAsync(staff_form);
  1353. });
  1354. if (PRSSecurity.IsAllowed<CanViewInOutBoard>())
  1355. toolEntries.Add(InOut);
  1356. //Manufacturing
  1357. ToolEntry Manufacturing = new ToolEntry
  1358. {
  1359. Text = "Manufacturing",
  1360. Image = "manufacturingg"
  1361. };
  1362. if (Device.RuntimePlatform.Equals(Device.iOS))
  1363. {
  1364. Manufacturing.Image = "Image";
  1365. }
  1366. Manufacturing.OnTapped += ((object sender, EventArgs e) =>
  1367. {
  1368. ManufacturingScreen manufacturingScreen = new ManufacturingScreen();
  1369. Navigation.PushAsync(manufacturingScreen);
  1370. });
  1371. if (PRSSecurity.IsAllowed<CanViewManufacturingOnMobile>())
  1372. toolEntries.Add(Manufacturing);
  1373. //My HR
  1374. ToolEntry MyHR = new ToolEntry
  1375. {
  1376. Text = "My HR",
  1377. Image = "myhr"
  1378. };
  1379. MyHR.OnTapped += ((object sender, EventArgs e) =>
  1380. {
  1381. MyHRHome myHRHome = new MyHRHome();
  1382. Navigation.PushAsync(myHRHome);
  1383. });
  1384. toolEntries.Add(MyHR);
  1385. //Notifications
  1386. ToolEntry Notifications = new ToolEntry()
  1387. {
  1388. Text = "Notifications",
  1389. Image = "notifications"
  1390. };
  1391. Notifications.OnTapped += (object sender, EventArgs e) =>
  1392. {
  1393. NotificationList notificationList = new NotificationList();
  1394. notificationList.NotificationsClosed += (n) =>
  1395. {
  1396. NumberOfNotfications = n;
  1397. RefreshOnNotificationsChange();
  1398. };
  1399. Navigation.PushAsync(notificationList);
  1400. };
  1401. toolEntries.Add(Notifications);
  1402. ToolEntry Products = new ToolEntry()
  1403. {
  1404. Text = "Products",
  1405. Image = "products"
  1406. };
  1407. Products.OnTapped += (object sender, EventArgs e) =>
  1408. {
  1409. var page = new DataGridHost(new ProductsGrid());
  1410. Navigation.PushAsync(page);
  1411. };
  1412. if (PRSSecurity.CanView(typeof(Product)))
  1413. toolEntries.Add(Products);
  1414. //Purchase Orders
  1415. ToolEntry PurchaseOrders = new ToolEntry()
  1416. {
  1417. Text = "Purchase Orders",
  1418. Image = "shoppingcart"
  1419. };
  1420. PurchaseOrders.OnTapped += ((object sender, EventArgs e) =>
  1421. {
  1422. PurchaseOrderModule page = new PurchaseOrderModule();
  1423. Navigation.PushAsync(page);
  1424. });
  1425. if (PRSSecurity.CanView<PurchaseOrder>())
  1426. toolEntries.Add(PurchaseOrders);
  1427. //Scanner
  1428. ToolEntry Scanner = new ToolEntry
  1429. {
  1430. Text = "Scanner",
  1431. Image = "scanner"
  1432. };
  1433. Scanner.OnTapped += ((object sender, EventArgs e) =>
  1434. {
  1435. ScannerPage scannerPage = new ScannerPage();
  1436. Navigation.PushAsync(scannerPage);
  1437. });
  1438. toolEntries.Add(Scanner);
  1439. //Site
  1440. ToolEntry Site = new ToolEntry
  1441. {
  1442. Text = "Site",
  1443. Image = "construction"
  1444. };
  1445. Site.OnTapped += ((object sender, EventArgs e) =>
  1446. {
  1447. Site site = new Site(new Job { ID = MainPageUtils.Job.ID, Name = MainPageUtils.Job.Name, JobNumber = MainPageUtils.Job.JobNumber });
  1448. Navigation.PushAsync(site);
  1449. });
  1450. toolEntries.Add(Site);
  1451. //Store Requis
  1452. ToolEntry StoreRequis = new ToolEntry
  1453. {
  1454. Text = "Store Requis",
  1455. Image = "storerequis"
  1456. };
  1457. StoreRequis.OnTapped += ((object sender, EventArgs e) =>
  1458. {
  1459. var storeRequisList = new StoreRequiList();
  1460. Navigation.PushAsync(storeRequisList);
  1461. });
  1462. if (PRSSecurity.CanView<Requisition>())
  1463. toolEntries.Add(StoreRequis);
  1464. //Tasks
  1465. ToolEntry Tasks = new ToolEntry
  1466. {
  1467. Text = "My Tasks",
  1468. Image = "tasks"
  1469. };
  1470. Tasks.OnTapped += ((object sender, EventArgs e) =>
  1471. {
  1472. var tasksForm = new TasksList();
  1473. Navigation.PushAsync(tasksForm);
  1474. });
  1475. if (PRSSecurity.IsAllowed<CanViewTasks>())
  1476. toolEntries.Add(Tasks);
  1477. //Warehousing
  1478. ToolEntry Warehousing = new ToolEntry
  1479. {
  1480. Text = "Warehousing",
  1481. Image = "newwarehousing"
  1482. };
  1483. Warehousing.OnTapped += ((object sender, EventArgs e) =>
  1484. {
  1485. Warehousing2 locations = new Warehousing2();
  1486. Navigation.PushAsync(locations);
  1487. });
  1488. if (PRSSecurity.CanView<StockWarehouse>())
  1489. toolEntries.Add(Warehousing);
  1490. AddChildren();
  1491. });
  1492. }
  1493. catch { }
  1494. }
  1495. private void AddChildren()
  1496. {
  1497. Device.BeginInvokeOnMainThread(() =>
  1498. {
  1499. foreach (ToolEntry toolEntry in toolEntries)
  1500. {
  1501. toolEntry.Margin = new Thickness(5, 0, 5, 0);
  1502. flexLayout.Children.Add(toolEntry);
  1503. }
  1504. MainPageUtils.SearchForNewNotifications();
  1505. AddBlanks();
  1506. });
  1507. }
  1508. private void AddBlanks()
  1509. {
  1510. for (int x = 0; x < 6; x++)
  1511. {
  1512. ToolEntry toolEntry = new ToolEntry(true);
  1513. toolEntry.Margin = new Thickness(5, 0, 5, 0);
  1514. flexLayout.Children.Add(toolEntry);
  1515. }
  1516. }
  1517. private void Settings_Tapped(object sender, EventArgs e)
  1518. {
  1519. try
  1520. {
  1521. Settings settingsform = new Settings();
  1522. settingsform.Disappearing += (object sender2, EventArgs e2) =>
  1523. {
  1524. settingsform = (Settings)sender2;
  1525. if (settingsform.SettingsChanged)
  1526. Navigation.PopModalAsync();
  1527. };
  1528. Navigation.PushAsync(settingsform);
  1529. }
  1530. catch { }
  1531. }
  1532. #endregion
  1533. }
  1534. }