using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Xamarin.Forms; using InABox.Core; using InABox.Configuration; using InABox.Clients; using InABox.Mobile; using Comal.Classes; using XF.Material.Forms.UI.Dialogs; using comal.timesheets.CustomControls; using comal.timesheets.StoreRequis; using PRSSecurity = InABox.Core.Security; using Plugin.LocalNotification; using comal.timesheets.Tasks; using System.IO; namespace comal.timesheets { public partial class MainPage : ContentPage { #region Fields List toolEntries = new List(); public bool SettingsChanged { get; private set; } bool bUpdatingTimesheet = false; public static ConnectionSettings connectionSettings = null; bool midnightTimerOn = false; DateTime oneSecondBeforeMidnight = DateTime.Today.AddSeconds(864399); bool clockedOffInLast5Seconds = false; bool bRecentlyUpdatedTiles = false; bool bSharedDeviceFirstLoad = true; bool bSharedDevice = false; int NumberOfNotfications = 0; string matchedDeviceName = ""; int notCount = 1; #endregion #region Constructor public MainPage() { InitializeComponent(); try { InitItems(); LoadCacheLists(); //if (GlobalVariables.EmpID == Guid.Parse("40f6ccd9-5272-4b1a-99bf-de7542205aac")) RunCustomScript(); } catch (Exception e) { } } private void RunCustomScript() { } private void InitItems() { NavigationPage.SetHasBackButton(this, false); MainPageUtils.Init(); InitNotificationCentre(); MainPageUtils.OnRefreshScreen += () => { Device.BeginInvokeOnMainThread(() => { RefreshScreen(); }); }; MessagingCenter.Subscribe(this, App.MessageOnResume, (o) => { if (!App.GPS.RecentlyLocated) App.GPS.GetLocation(); RefreshScreen(); } ); InitToolEntryList(); CheckCurrentAssignment(); NotifyChanges(); } private void CheckCurrentAssignment() { Task.Run(() => { try { var assgn = MainPageUtils.CheckCurrentAssignment(); MainPageUtils.OnRequestUserInput += (taskID) => { RequestUserInput(taskID); }; MainPageUtils.OnTaskTitleChanged += (title) => { taskBtn.Text = title; }; MainPageUtils.Job.OnJobIDChanged += MainPageUtils.OnJobIDChanged; MainPageUtils.Job.OnJobNumberChanged += Job_OnJobNumberChanged; if (assgn == null) return; MainPageUtils.UseCurrentAssignment(assgn); RefreshJobBtn(); } catch { } }); } private void NotifyChanges() { Task.Run(() => { string changes = NotifyMobileChanges.Notifiy(); if (!string.IsNullOrWhiteSpace(changes)) Device.BeginInvokeOnMainThread(() => { DisplayAlert("Latest changes", changes, "OK"); }); }); } #endregion #region OnAppearing and Display protected override void OnAppearing() { if (!App.IsUserLoggedIn) { Navigation.PopAsync(); return; } //if (Application.Current.Properties.ContainsKey("IsSharedDevice")) //{ // if (Application.Current.Properties["IsSharedDevice"].Equals("True")) // { // bSharedDevice = true; // if (!bSharedDeviceFirstLoad) // { // App.LogoutUser(); // Navigation.PopToRootAsync(); // } // else // { // bSharedDeviceFirstLoad = false; // clockOnButton.IsEnabled = false; // clockOnButton.Text = "Shared Device"; // clockOnButton.BackgroundColor = Color.CornflowerBlue; // CurrentLocation.IsVisible = false; // jobBtn.IsVisible = false; // addNoteBtn.IsVisible = false; // Grid.SetRowSpan(flexLayoutScrollView, 3); // Grid.SetRow(flexLayoutScrollView, 1); // Timer t = new Timer(AutoLogoutUser, null, 600000, Timeout.Infinite); // } // } // else // bSharedDevice = false; //} //getting strange results from .IsAllowed //if (!PRSSecurity.IsAllowed()) //{ // clockOnButton.IsVisible = false; // jobBtn.IsVisible = false; // addNoteBtn.IsVisible = false; // CurrentLocation.IsVisible = false; // row0.Height = 0; // row1.Height = 0; // row2.Height = 0; // ForceLayout(); //} if (!MainPageUtils.firstLoad) RefreshScreen(); Task.Run(async () => { bool isLatest = true; try { isLatest = await MobileUtils.AppVersion.IsUsingLatestVersion(); } catch (Exception eLatest) { if (!MainPageUtils.recentlyAskedToUpdate) { Device.BeginInvokeOnMainThread(() => { }); MainPageUtils.recentlyAskedToUpdate = true; } string s = eLatest.Message; } if (!isLatest) { if (!MainPageUtils.recentlyAskedToUpdate) { string latestVersionNumber = await MobileUtils.AppVersion.GetLatestVersionNumber(); if (MainPageUtils.updateCounter < 3) { Device.BeginInvokeOnMainThread(async () => { string chosenOption = await DisplayActionSheet(String.Format("Version {0} Available. Update now?", latestVersionNumber), "You will be reminded again in 10 minutes.", null, "Yes", "No"); switch (chosenOption) { case "No": break; case "Cancel": break; case "Yes": Dispatcher.BeginInvokeOnMainThread(() => { MobileUtils.AppVersion.OpenAppInStore(); }); break; default: break; } }); } else if (MainPageUtils.updateCounter >= 3) { Device.BeginInvokeOnMainThread(() => { DisplayAlert(String.Format("Version {0} Available", latestVersionNumber), "Please update your software to the latest version.", "OK") .ContinueWith((Task task) => { Dispatcher.BeginInvokeOnMainThread(() => { MobileUtils.AppVersion.OpenAppInStore(); }); }); }); } MainPageUtils.recentlyAskedToUpdate = true; MainPageUtils.updateCounter++; } } }); base.OnAppearing(); } private void AutoLogoutUser(object o) { App.LogoutUser(); Navigation.PopToRootAsync(); } private void RefreshScreen() { //if (bSharedDevice) // return; try { Device.BeginInvokeOnMainThread(() => { homeScreenGrid.RaiseChild(CurrentLocation); bBusy = true; if (GlobalVariables.EmpID == Guid.Empty) { GlobalVariables.EmpID = GlobalVariables.GetEmployeeID(); GlobalVariables.EmpName = GlobalVariables.GetEmployeeName(); } clockOnButton.IsEnabled = false; bool PRSReady = (App.Data.Employee != null) && (App.Data.TimeSheets != null) && (GlobalVariables.EmpID != Guid.Empty); bool GateReady = CheckLocation(); CurrentLocation.Text = DisplayAddress(); if (CurrentLocation.Text.Contains("ERROR")) CurrentLocation.Text = "Unknown Address"; Title = null; Title = App.Data.Employee != null ? App.Data.Employee.Name : ""; CoreRow timesheet = App.Data.TimeSheets?.Rows.FirstOrDefault(); clockOnButton.Text = PRSReady && GateReady ? timesheet == null ? "CLOCK ON" : "CLOCK OFF" : "PLEASE WAIT"; clockOnButton.IsEnabled = PRSReady && GateReady; clockOnButton.BackgroundColor = PRSReady && GateReady ? timesheet == null ? Color.FromHex("#e6e6fa") : Color.FromHex("#15C7C1") : Color.Gainsboro; clockOnButton.BorderColor = PRSReady && GateReady ? timesheet == null ? Color.Black : Color.FromHex("#15C7C1") : Color.Gainsboro; if (clockOnButton.Text == "CLOCK OFF") { addNoteBtn.IsEnabled = true; taskBtn.IsEnabled = true; if (GlobalVariables.JobsLoaded) jobBtn.IsEnabled = true; } else { addNoteBtn.IsEnabled = false; jobBtn.IsEnabled = false; taskBtn.IsEnabled = false; } //if (firstLoad) // RefreshJobFromTimeSheet(timesheet); RefreshJobBtn(); homeScreenGrid.RaiseChild(CurrentLocation); MainPageUtils.firstLoad = false; bBusy = false; }); } catch (Exception e) { } //CurrentLocation.IsEnabled = PRSReady && GateReady; } private void Job_OnJobNumberChanged(string jobnumber) { jobBtn.Text = "Job: " + jobnumber; } private void RefreshJobBtn() { if (MainPageUtils.Job.ID == Guid.Empty) jobBtn.Text = "No Job Selected"; else if (!string.IsNullOrWhiteSpace(MainPageUtils.Job.JobNumber)) jobBtn.Text = "Job: " + MainPageUtils.Job.JobNumber; } private void RefreshJobFromTimeSheet(CoreRow timesheet) { Guid jobid = timesheet == null ? Guid.Empty : timesheet.Get(x => x.JobLink.ID); if (!jobid.Equals(Guid.Empty)) { jobBtn.Text = String.Format("{0}: {1}", timesheet.Get(x => x.JobLink.JobNumber), timesheet.Get(x => x.JobLink.Name)); MainPageUtils.Job.ID = timesheet == null ? Guid.Empty : timesheet.Get(x => x.JobLink.ID); MainPageUtils.Job.JobNumber = timesheet == null ? String.Empty : timesheet.Get(x => x.JobLink.JobNumber); MainPageUtils.Job.Name = timesheet == null ? String.Empty : timesheet.Get(x => x.JobLink.Name); } else { jobBtn.Text = "No Job Selected"; MainPageUtils.Job = new JobShell(); } } #endregion #region Clock on/off private void DataChanged(object sender, Type type, Exception e) { RefreshScreen(); } private void DataRefreshed() { //if (bSharedDevice) // return; Device.BeginInvokeOnMainThread(() => { RefreshScreen(); }); } bool bBusy = false; async void ClockOnOff_Clicked(object sender, System.EventArgs e) { if (bBusy) return; bBusy = true; string chosenOption = "Continue"; if (clockOnButton.Text == "CLOCK OFF") { chosenOption = await DisplayActionSheet("Clock off?", "Cancel", null, "Continue", "Cancel"); } switch (chosenOption) { case "Continue": break; case "Cancel": bBusy = false; return; break; default: bBusy = false; return; break; } if (clockOnButton.Text == "CLOCK ON" && clockedOffInLast5Seconds) { bBusy = false; return; } try { using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Loading")) { InABox.Core.Location here = new InABox.Core.Location() { Latitude = App.GPS.Latitude, Longitude = App.GPS.Longitude, Timestamp = DateTime.Now }; TimeSheet timesheet = App.Data.TimeSheets?.Rows.FirstOrDefault()?.ToObject(); if (timesheet != null) { if (timesheet.ID != Guid.Empty) { if (ZeroLengthTimesheet()) { bUpdatingTimesheet = true; new Client().Delete(timesheet, "Deleted due to zero duration timesheet"); App.Data.TimeSheets.Rows.Clear(); } else { FinishTimeSheet(timesheet, here); } } } else { Guid jobid = Guid.Empty; String jobnumber = ""; String jobname = ""; if (!App.Data.CanBypassGates) { CoreRow row = App.Data.Gates.Rows.FirstOrDefault(r => App.Bluetooth.Devices.Contains(r.Get(c => c.TrackerLink.DeviceID))); if (row != null) { jobid = row.Get(x => x.JobLink.ID); jobnumber = row.Get(x => x.JobLink.JobNumber); jobname = row.Get(x => x.JobLink.Name); } CreateTimeSheet(jobid, jobnumber, jobname, here, App.GPS.Address, "Clocking On"); } else { if ((!App.GPS.Latitude.Equals(0.0F)) && (!App.GPS.Longitude.Equals(0.0F))) { ChooseNearbyJob(here); } } } RefreshScreen(); } } catch (Exception e2) { } bBusy = false; } #endregion #region Bluetooth private async void UploadTiles() { try { if (App.GPS.Latitude.Equals(0.0F) && App.GPS.Longitude.Equals(0.0F)) return; if (App.Bluetooth.DetectedBlueToothMACAddresses.Count == 0) return; if (bRecentlyUpdatedTiles) return; bRecentlyUpdatedTiles = true; await Task.Run(() => { InABox.Core.Location curlocation = new InABox.Core.Location() { Latitude = App.GPS.Latitude, Longitude = App.GPS.Longitude }; curlocation.Timestamp = DateTime.Now; List trackersToUpdate = new List(); foreach (String id in App.Bluetooth.DetectedBlueToothMACAddresses) { GPSTracker tracker = GlobalVariables.GPSTrackerCache.Find(x => x.DeviceID.Equals(id)); bool stale = tracker.Location.Timestamp < DateTime.Now.Subtract(new TimeSpan(0, 5, 0)); bool moved = tracker.Location.DistanceTo(curlocation, UnitOfLength.Kilometers) > 0.1; if (stale || moved) { GlobalVariables.GPSTrackerCache.Remove(tracker); tracker.Location = curlocation; GlobalVariables.GPSTrackerCache.Add(tracker); //cache is updated GPSTrackerLocation gpsTrackerLocation = new GPSTrackerLocation(); gpsTrackerLocation.DeviceID = tracker.DeviceID; gpsTrackerLocation.Location.Timestamp = tracker.Location.Timestamp; gpsTrackerLocation.Location = curlocation; trackersToUpdate.Add(gpsTrackerLocation); } } if (trackersToUpdate.Any()) { if (ClientFactory.UserGuid != Guid.Empty) new Client().Save(trackersToUpdate, "Updating Bluetooth Device Locations"); } App.Bluetooth.DetectedBlueToothMACAddresses.Clear(); } ); } catch (Exception e) { } //if ((master != null) && (master.Location.Timestamp < DateTime.Now.Subtract(new TimeSpan(0, 15, 0)))) //{ // GPSTrackerLocation device = new GPSTrackerLocation(); // device.DeviceID = MobileUtils.GetDeviceID(); // device.Location.Latitude = App.GPS.Latitude; // device.Location.Longitude = App.GPS.Longitude; // device.Location.Timestamp = DateTime.Now; // locations.Add(device); // //device.BatteryLevel = ((double)CrossBattery.Current.RemainingChargePercent); // //new Client().Save(device, "Updating Device Location"); //, SaveTrackerCallback); //} #region OLD //for (int i = 0; i < App.Bluetooth.Devices.Length; i++) //{ // String id = App.Bluetooth.Devices[i]; // int level = App.Bluetooth.BatteryLevels[i]; // var btmaster = trackers.FirstOrDefault(x => x.DeviceID.Equals(id)); // if ((btmaster != null) && (!locations.Any(x => x.DeviceID.Equals(btmaster.DeviceID)))) // { // bool stale = btmaster.Location.Timestamp < DateTime.Now.Subtract(new TimeSpan(0, 15, 0)); // bool moved = btmaster.Location.DistanceTo(curlocation, UnitOfLength.Kilometers) > 0.1; // if (stale || moved) // { // GPSTrackerLocation location = new GPSTrackerLocation(); // location.DeviceID = id; // location.Location.Latitude = App.GPS.Latitude; // location.Location.Longitude = App.GPS.Longitude; // location.Location.Timestamp = DateTime.Now; // location.BatteryLevel = level; // locations.Add(location); // } // } // //new Client().Save(location, "Found Kontakt Device"); //, SaveTrackerCallback); //} //if (locations.Any()) // new Client().Save(locations, "Updating Bluetooth Device Locations", (o, e) => { }); #endregion } private void RecentlyUpdatedTilesTimer(object o) { bRecentlyUpdatedTiles = false; App.Data.Refresh(true); MainPageUtils.SearchForNewNotifications(); } private void LocationFound(LocationServices sender) { //if (bSharedDevice) // return; if (App.Bluetooth.RecentlyScanned) UploadTiles(); try { TimeSheet timesheet = App.Data.TimeSheets?.Rows.FirstOrDefault()?.ToObject(); if (timesheet != null) { if (timesheet.StartLocation.Latitude.Equals(0.0F) && timesheet.StartLocation.Longitude.Equals(0.0F)) { timesheet.StartLocation.Latitude = sender.Latitude; timesheet.StartLocation.Longitude = sender.Longitude; timesheet.StartLocation.Timestamp = sender.TimeStamp; timesheet.Address = sender.Address; new Client().Save(timesheet, "Updating Timesheet with GPS Coordinates", (o, e) => { }); } } if (!string.IsNullOrWhiteSpace(matchedDeviceName)) { InABox.Core.Location curlocation = new InABox.Core.Location() { Latitude = App.GPS.Latitude, Longitude = App.GPS.Longitude }; curlocation.Timestamp = DateTime.Now; GPSTrackerLocation gpsTrackerLocation = new GPSTrackerLocation(); gpsTrackerLocation.DeviceID = matchedDeviceName; gpsTrackerLocation.Location.Timestamp = curlocation.Timestamp; gpsTrackerLocation.Location = curlocation; new Client().Save(gpsTrackerLocation, "Updated company device location from Timebench"); } Device.BeginInvokeOnMainThread(() => { RefreshScreen(); }); } catch { } } private void LocationError(LocationServices sebder, Exception error) { } private void ScanFinished(Bluetooth sender) { try { //if (bSharedDevice) // return; Device.BeginInvokeOnMainThread(() => { RefreshScreen(); //if (Button2.BackgroundColor == Color.WhiteSmoke) // Button2.BackgroundColor = Color.Red; //else // Button2.BackgroundColor = Color.WhiteSmoke; }); if (App.GPS.RecentlyLocated) UploadTiles(); } catch { } } #endregion #region Utilities private void InitNotificationCentre() { LocalNotificationCenter.Current.NotificationActionTapped += (Plugin.LocalNotification.EventArgs.NotificationActionEventArgs e) => { if (MainPageUtils.DetermineCorrectPage(e) != null) { Device.BeginInvokeOnMainThread(() => { Navigation.PushAsync(MainPageUtils.DetermineCorrectPage(e)); }); } }; MainPageUtils.OnMainPageNotificationsChanged += RefreshOnNotificationsChange; } private void RefreshOnNotificationsChange() { try { int index = toolEntries.FindIndex(x => x.Text.Equals("Notifications")); toolEntries.RemoveAt(index); string notificationsString = ""; if (NumberOfNotfications != 0) { notificationsString = NumberOfNotfications.ToString(); } ToolEntry Notifications = new ToolEntry(notificationsString) { Text = "Notifications", Image = "notifications" }; Notifications.OnTapped += (async (object sender, EventArgs e) => { using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Loading")) { NotificationList notificationList = new NotificationList(); notificationList.NotificationsClosed += (n) => { NumberOfNotfications = n; RefreshOnNotificationsChange(); }; Navigation.PushAsync(notificationList); } }); toolEntries.Insert(index, Notifications); Device.BeginInvokeOnMainThread(() => { flexLayout.Children.RemoveAt(index); flexLayout.Children.Insert(index, toolEntries[index]); }); } catch { } } private void CheckNotificationsPushed(CoreTable table) { try { if (!Application.Current.Properties.ContainsKey("LastPushedNotifications")) { Application.Current.Properties.Add("LastPushedNotifications", DateTime.Now); } DateTime lastPushed = DateTime.Parse(Application.Current.Properties["LastPushedNotifications"].ToString()); List toNotify = new List(); foreach (CoreRow row in table.Rows) { List list = row.Values; DateTime created = DateTime.Parse(list[3].ToString()); if (created > new DateTime(2022, 8, 22)) // prevent spam from buildup of old notifications before this is released { if (created > lastPushed) { if (list[1] == null) list[1] = ""; if (list[2] == null) list[2] = ""; if (list[3] == null) list[3] = DateTime.MinValue; if (list[4] == null) list[4] = ""; if (list[5] == null) list[5] = ""; if (list[6] == null) list[6] = Guid.Empty; NotificationShell shell = new NotificationShell { ID = Guid.Parse(list[0].ToString()), Sender = list[1].ToString(), Title = list[2].ToString(), Created = DateTime.Parse(list[3].ToString()), EntityType = list[5].ToString(), EntityID = Guid.Parse(list[6].ToString()) }; toNotify.Add(shell); //add notification to be pushed } } } if (toNotify.Count > 0) PushNotificationsAsync(toNotify); } catch { } } private async Task PushNotificationsAsync(List shells) { try { int count = 1; foreach (NotificationShell shell in shells) { var notification = new NotificationRequest { BadgeNumber = 1, Description = shell.Title, Title = "New PRS Notification: ", ReturningData = shell.EntityID.ToString() + "$" + shell.EntityType, NotificationId = count, }; count++; NotificationImage img = new NotificationImage(); img.ResourceName = "icon16.png"; notification.Image = img; await LocalNotificationCenter.Current.Show(notification); } Application.Current.Properties["LastPushedNotifications"] = DateTime.Now; } catch { } } private void StartMidnightTimeSheetTimer() { midnightTimerOn = true; int msUntilMidnight = (int)(oneSecondBeforeMidnight - DateTime.Now).TotalMilliseconds; Timer midnightTimer = new Timer(MidnightTimerCallback, null, msUntilMidnight, Timeout.Infinite); } private void MidnightTimerCallback(object o) { try { //if (bSharedDevice) // return; if (midnightTimerOn) { if (clockOnButton.Text == "CLOCK OFF") { InABox.Core.Location here = new InABox.Core.Location() { Latitude = App.GPS.Latitude, Longitude = App.GPS.Longitude, Timestamp = DateTime.Now }; TimeSheet timesheet = App.Data.TimeSheets?.Rows.FirstOrDefault()?.ToObject(); if (timesheet != null) { if (timesheet.ID != Guid.Empty) { if (ZeroLengthTimesheet()) { bUpdatingTimesheet = true; new Client().Delete(timesheet, "Deleted due to zero duration timesheet"); App.Data.TimeSheets.Rows.Clear(); } else { timesheet.Finish = new TimeSpan(23, 59, 59); timesheet.FinishLocation = here; bUpdatingTimesheet = true; new Client().Save(timesheet, "Auto Close timesheet at Midnight"); App.Data.TimeSheets.Rows.Clear(); Guid jobid = Guid.Empty; String jobnumber = ""; String jobname = ""; if (!App.Data.CanBypassGates) { CoreRow row = App.Data.Gates.Rows.FirstOrDefault(r => App.Bluetooth.Devices.Contains(r.Get(c => c.TrackerLink.DeviceID))); if (row != null) { jobid = row.Get(x => x.JobLink.ID); jobnumber = row.Get(x => x.JobLink.JobNumber); jobname = row.Get(x => x.JobLink.Name); } CreateTimeSheet(jobid, jobnumber, jobname, here, App.GPS.Address, "Clocking On"); } else { if ((!App.GPS.Latitude.Equals(0.0F)) && (!App.GPS.Longitude.Equals(0.0F))) { ChooseNearbyJob(here); } } } } } } } } catch { } } private void FinishTimeSheet(TimeSheet timesheet, InABox.Core.Location here) { try { TimeSpan tod = DateTime.Now - DateTime.Today; timesheet.Finish = new TimeSpan(tod.Hours, tod.Minutes, 0); timesheet.FinishLocation = here; bUpdatingTimesheet = true; new Client().Save(timesheet, "Clocking Off"); App.Data.TimeSheets.Rows.Clear(); midnightTimerOn = false; Timer last60Seconds = new Timer(Last60SecondsTimerCallBack, null, 5000, Timeout.Infinite); clockedOffInLast5Seconds = true; if (MainPageUtils.CurrentAssignment != null) { MainPageUtils.SaveCurrentAssignment("PRS Mobile - clocking off", true); MainPageUtils.CurrentAssignment = null; } } catch { } } private void Last60SecondsTimerCallBack(object o) { clockedOffInLast5Seconds = false; } private async void ChooseNearbyJob(InABox.Core.Location here) { try { JobShell selectedJob = new JobShell(); Dictionary nearbyJobs = new Dictionary(); foreach (CoreRow row in App.Data.Jobs.Rows) { InABox.Core.Location jobLocation = new InABox.Core.Location() { Latitude = row.Get(X => X.SiteAddress.Location.Latitude), Longitude = row.Get(X => X.SiteAddress.Location.Longitude) }; double distance = here.DistanceTo(jobLocation, UnitOfLength.Kilometers); if (distance < 1.0F) { JobShell jobShell = new JobShell(); jobShell.ID = row.Get(X => X.ID); jobShell.JobNumber = row.Get(x => x.JobNumber); jobShell.Name = row.Get(x => x.Name); jobShell.DisplayName = jobShell.JobNumber + " " + jobShell.Name; nearbyJobs.Add(jobShell.DisplayName, jobShell); } } if (nearbyJobs.Count > 1) { string[] array = nearbyJobs.Keys.ToArray(); string chosenOption = await DisplayActionSheet("Choose job site", "Cancel", null, array); if (string.IsNullOrEmpty(chosenOption) || chosenOption.Equals("Cancel")) { CreateTimeSheet(selectedJob.ID, selectedJob.JobNumber, selectedJob.Name, here, App.GPS.Address, "Clocking On"); return; } else { selectedJob = nearbyJobs[chosenOption]; } } else if (nearbyJobs.Count == 1) { selectedJob = nearbyJobs.Values.First(); } CreateTimeSheet(selectedJob.ID, selectedJob.JobNumber, selectedJob.Name, here, App.GPS.Address, "Clocking On"); } catch { } } void AddNote_Tapped(System.Object sender, System.EventArgs e) { try { TimeSheet timesheet = App.Data.TimeSheets?.Rows.FirstOrDefault()?.ToObject(); if (timesheet == null) return; var notepage = new NotePage(timesheet); Navigation.PushAsync(notepage); } catch { } } private void TaskBtn_Tapped(object sender, EventArgs e) { ListSelectionPage page = new ListSelectionPage(MainPageUtils.GetTasks()); page.OnDictionaryItemTapped += (id, title) => { MainPageUtils.OnTaskSelected(id, title); }; Navigation.PushAsync(page); } private async void RequestUserInput(Guid taskID) { const string addtask = "Change current assignment task"; const string newassignment = "Start a new assignment with this task"; string chosenOption = await DisplayActionSheet("Choose an option", "Cancel", null, addtask, newassignment); switch (chosenOption) { case addtask: MainPageUtils.ChangeAssignmentTask(taskID); break; case newassignment: MainPageUtils.SaveCurrentAssignment("PRS Mobile main screen - saving assignment on task change", true); MainPageUtils.CreateNewAssignment(Guid.Empty, taskID); break; default: break; } } private void JobBtn_Tapped(object sender, EventArgs e) { try { JobSelectionPage jobSelectionPage = new JobSelectionPage(); jobSelectionPage.OnItemSelected += (() => { MainPageUtils.Job.ID = jobSelectionPage.Job.ID; MainPageUtils.Job.JobNumber = jobSelectionPage.Job.JobNumber; MainPageUtils.Job.Name = jobSelectionPage.Job.Name; RefreshScreen(); JobPage_OnItemSelected(jobSelectionPage.Job); }); Navigation.PushAsync(jobSelectionPage); } catch { } } private void JobPage_OnItemSelected(JobShell job) { //try //{ // TimeSheet timesheet = App.Data.TimeSheets?.Rows.FirstOrDefault()?.ToObject(); // if (timesheet == null) // return; // String auditmessage = String.Format("Changed Selected Job to: {0}: {1}", timesheet.JobLink.JobNumber, timesheet.JobLink.Name); // if (ZeroLengthTimesheet()) // { // timesheet.JobLink.ID = job.ID; // timesheet.JobLink.JobNumber = job.JobNumber; // timesheet.JobLink.Name = job.Name; // bUpdatingTimesheet = true; // new Client().Save(timesheet, auditmessage); // Device.BeginInvokeOnMainThread(() => // { // if (timesheet.JobLink.ID != Guid.Empty) // { // jobBtn.Text = "(" + timesheet.JobLink.JobNumber + ") " + timesheet.JobLink.Name; // } // else // { // jobBtn.Text = "No Job Selected"; // } // }); // } // else // { // InABox.Core.Location here = new InABox.Core.Location() // { // Latitude = App.GPS.Latitude, // Longitude = App.GPS.Longitude, // Timestamp = DateTime.Now // }; // TimeSpan tod = DateTime.Now - DateTime.Today; // timesheet.Finish = new TimeSpan(tod.Hours, tod.Minutes, 0); // timesheet.FinishLocation = here; // new Client().Save(timesheet, "Changing Job"); // CreateTimeSheet( // job.ID, // job.JobNumber, // job.Name, // here, // App.GPS.Address, // auditmessage // ); // } // RefreshScreen(); //} //catch { } } private bool CheckTimeSheetAgainstGates(TimeSheet timesheet) { DateTime now = DateTime.Now; //var timesheet = CurrentTimeSheet(); //Can't confirm if there is no timesheet if (timesheet == null) return false; // Can't confirm if there are no devices if (App.Bluetooth.Devices.Length == 0) return false; if (App.Data.Gates == null) return false; long tsTicks = timesheet.Date.Add(timesheet.Start).Ticks; long btTicks = App.Bluetooth.TimeStamp.Ticks; if (Math.Abs(tsTicks - btTicks) > new TimeSpan(0, 2, 0).Ticks) return false; CoreRow firstgate = null; List gates = new List(); // Scan every located d foreach (var device in App.Bluetooth.Devices) { CoreRow gate = App.Data.Gates?.Rows.FirstOrDefault(r => r.Get(c => c.TrackerLink.DeviceID) == device); if (gate != null) { if ((gate.Get(x => x.IsJobSite) == true) && (firstgate == null)) firstgate = gate; gates.Add(gate.Get(x => x.Gate)); } } if (gates.Any()) { timesheet.Gate = String.Join(", ", gates.OrderBy(x => x)); if (firstgate != null) { timesheet.JobLink.ID = firstgate.Get(x => x.JobLink.ID); timesheet.JobLink.JobNumber = firstgate.Get(x => x.JobLink.JobNumber); timesheet.JobLink.Name = firstgate.Get(x => x.JobLink.Name); } return true; //new Client().Save(timesheet, "Confirmed Gate Entry by Bluetooth Tracker", (o, e) => { }); } return false; } private bool ZeroLengthTimesheet() { try { if (App.Data.TimeSheets == null) return true; CoreRow row = App.Data.TimeSheets.Rows.FirstOrDefault(); if (row == null) return true; String notes = row.Get(x => x.Notes); if (!String.IsNullOrWhiteSpace(notes)) return false; DateTime date = row.Get(x => x.Date); TimeSpan start = row.Get(x => x.Start); if (date.Equals(DateTime.Today)) { TimeSpan tod = DateTime.Now - DateTime.Today; var diff = (tod - start).TotalSeconds; if (Math.Abs(diff) < 120.0F) return true; } } catch { } return false; } private async void CreateTimeSheet(Guid jobid, string jobnumber, String jobname, InABox.Core.Location location, String address, String auditmessage) { try { var timesheet = new TimeSheet(); using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Loading")) { timesheet.EmployeeLink.ID = GlobalVariables.EmpID; timesheet.Date = DateTime.Today; TimeSpan tod = DateTime.Now - DateTime.Today; tod = new TimeSpan(tod.Hours, tod.Minutes, 0); timesheet.Start = tod; timesheet.StartLocation = location; timesheet.JobLink.ID = jobid; timesheet.JobLink.JobNumber = jobnumber; timesheet.JobLink.Name = jobname; timesheet.Address = address; timesheet.SoftwareVersion = MobileUtils.AppVersion.InstalledVersionNumber + GlobalVariables.DeviceString; //if (ClientFactory.IsAllowed()) CheckTimeSheetAgainstGates(timesheet); bUpdatingTimesheet = true; new Client().Save(timesheet, auditmessage); if (timesheet.ID == Guid.Empty) { DisplayAlert("Error creating new timesheet", "Please check your connection and try again", "OK"); return; } StartMidnightTimeSheetTimer(); // Don't Save Completed Timesheets! App.Data.TimeSheets.Rows.Clear(); if (timesheet.Finish.Ticks == 0L) { CoreRow row = App.Data.TimeSheets.NewRow(); App.Data.TimeSheets.LoadRow(row, timesheet); App.Data.TimeSheets.Rows.Add(row); } } Device.BeginInvokeOnMainThread(() => { if (timesheet.JobLink.ID != Guid.Empty) { jobBtn.Text = "(" + timesheet.JobLink.JobNumber + ") " + timesheet.JobLink.Name; } else { jobBtn.Text = "No Job Selected"; } }); } catch { } } private bool CheckLocation() { try { if (App.Data.CanBypassGates) { if (App.GPS.TimeStamp > DateTime.Now.Subtract(new TimeSpan(0, 5, 0))) return true; else return false; } if (App.Data.Gates == null) return false; if (App.Bluetooth.TimeStamp < DateTime.Now.Subtract(new TimeSpan(0, 2, 0))) return false; if (!App.Bluetooth.Devices.Any()) return false; return App.Data.Gates.Rows.Any(r => App.Bluetooth.Devices.Contains(r.Get(c => c.TrackerLink.DeviceID))); } catch { return true; } } private String DisplayAddress() { try { bool PRSReady = App.Data.Employee != null; // && (TimeSheet != null); // && (Activities != null); if (!PRSReady) return "Retrieving Data"; if (App.Data.CanBypassGates) { if (App.GPS.TimeStamp < DateTime.Now.Subtract(new TimeSpan(0, 5, 0))) { App.GPS.GetLocation(true); return "Searching for GPS"; } else return App.GPS.Address; } else { // Hmm.. this can/should be simplified // if in range of a gate // Show Gate Description // else // "Looking for Gate" if ((App.Data.Gates != null) && (App.Bluetooth.TimeStamp > DateTime.Now.Subtract(new TimeSpan(0, 2, 0)))) { CoreRow row = App.Data.Gates.Rows.FirstOrDefault(r => App.Bluetooth.Devices.Contains(r.Get(c => c.TrackerLink.DeviceID))); if (row != null) return row.Get(x => x.Gate); //else if ((CurrentTimeSheet() != null) && (!GPS.TimeStamp.IsEmpty())) // return GPS.Address; else return "Looking for Gate"; } //else if ((CurrentTimeSheet() != null) && (GPS.TimeStamp > DateTime.Now.Subtract(new TimeSpan(0, 2, 0)))) // return GPS.Address; else return "Looking for Gate"; } } catch { return "Address error"; } } #region Background Loading private async Task LoadCacheLists() { GlobalVariables.ProductsLoaded = false; GlobalVariables.JobsLoaded = false; GlobalVariables.GetXamarinWidth(); await CacheLoader.LoadJobs(); LoadEmployeeShells(); LoadProducts(); LoadCompanyDevices(); LoadBlueToothAddresses(); //LoadHRToDos(); to be uncommented when ready for roll out } private void LoadCompanyDevices() { Task.Run(() => { if (!string.IsNullOrWhiteSpace(MainPageUtils.deviceName) && MainPageUtils.deviceName != "unknown") { List companyDevices = new List(); CoreTable table = new Client().Query ( new Filter(x => x.GroupLink.Code).IsEqualTo("DEVICE"), new Columns( x => x.TrackerLink.DeviceID ) ); if (table.Rows.Any()) { foreach (CoreRow row in table.Rows) { List list = row.Values; if (list[0].ToString().Equals(MainPageUtils.deviceName)) { matchedDeviceName = MainPageUtils.deviceName; } } } } }); } private async void LoadEmployeeShells() { await Task.Run(() => { try { List employeeShells = new List(); List teamEmployeeShells = new List(); MultiQuery query = new MultiQuery(); query.Add( LookupFactory.DefineFilter(), new Columns(x => x.ID) .Add(x => x.Code) .Add(x => x.Name), LookupFactory.DefineSort() ); query.Add( LookupFactory.DefineFilter(), new Columns(x => x.Name), new SortOrder(x => x.Name) ); query.Add( LookupFactory.DefineFilter(), new Columns(x => x.EmployeeLink.ID) .Add(x => x.EmployeeLink.Code) .Add(x => x.EmployeeLink.Name) .Add(x => x.TeamLink.Name), new SortOrder(x => x.EmployeeLink.Name) ); query.Query(); CoreTable emps = query.Get(); foreach (var row in emps.Rows) { employeeShells.Add( new EmployeeShell() { ID = row.Get(x => x.ID), Code = row.Get(x => x.Code), Name = row.Get(x => x.Name), TeamName = "All Staff" } ); } GlobalVariables.TeamNames = query.Get().Rows.Select(r => r.Get(c => c.Name)).ToList(); CoreTable members = query.Get(); foreach (var row in members.Rows) { teamEmployeeShells.Add( new EmployeeShell() { ID = row.Get(x => x.EmployeeLink.ID), Code = row.Get(x => x.EmployeeLink.Code), Name = row.Get(x => x.EmployeeLink.Name), TeamName = row.Get(x => x.TeamLink.Name) } ); } GlobalVariables.EmployeeShells = employeeShells; GlobalVariables.TeamEmployeeShells = teamEmployeeShells; } catch { } }); } private async void LoadHRToDos() { try { await Task.Run(() => { Thread.Sleep(10000); if (GlobalVariables.UpdateHRItemsNeedingAttention()) { string message = "You have HR Items needing attention. Open My HR now?"; Device.BeginInvokeOnMainThread(async () => { string chosenOption = await DisplayActionSheet(message, "Cancel", null, "Yes", "No"); switch (chosenOption) { case "Cancel": break; case "No": break; default: break; case "Yes": MyHRHome myHRHome = new MyHRHome(); Navigation.PushAsync(myHRHome); break; } }); } }); } catch { } } private async void LoadProducts() { try { await Task.Run(() => { ProductsLoader productsLoader = new ProductsLoader(); //if (ClientFactory.IsAllowed()) //{ //} }); } catch { } } private async void LoadBlueToothAddresses() { try { //if (bSharedDevice) // return; await Task.Run(() => { GlobalVariables.GPSTrackerCache = new List(); CoreTable table = new Client().Query(new Filter(x => x.Type.Description).Contains("Kontakt")); foreach (CoreRow row in table.Rows) { GPSTracker tracker = row.ToObject(); GlobalVariables.GPSTrackerCache.Add(tracker); App.Bluetooth.KnownBlueToothMACAddresses.Add(tracker.DeviceID); } }); } catch { } } #endregion #endregion #region Modules public async void InitToolEntryList() { try { await Task.Run(() => { //Assignments ToolEntry Assignments = new ToolEntry { Text = "Assignments", Image = "calendar" }; Assignments.IsVisible = PRSSecurity.CanView(); Assignments.OnTapped += ((object sender, EventArgs e) => { var assignment_form = new AssignmentList(); Navigation.PushAsync(assignment_form); }); toolEntries.Add(Assignments); //Deliveries ToolEntry Deliveries = new ToolEntry { Text = "Deliveries", Image = "deliveries" }; Deliveries.IsVisible = PRSSecurity.CanView(); Deliveries.OnTapped += ((object sender, EventArgs e) => { var delivery_form = new DeliveryList(); Navigation.PushAsync(delivery_form); }); toolEntries.Add(Deliveries); //Digital Forms ToolEntry Forms = new ToolEntry { Text = "Forms", Image = "forms" }; Forms.IsVisible = PRSSecurity.CanView(); Forms.OnTapped += ((object sender, EventArgs e) => { var qaFormPicker = new DigitalFormsPicker(); Navigation.PushAsync(qaFormPicker); }); toolEntries.Add(Forms); //Equipment ToolEntry Equipment = new ToolEntry { Text = "Equipment", Image = "digger" }; Equipment.IsVisible = PRSSecurity.CanView(); Equipment.OnTapped += (async (object sender, EventArgs e) => { using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Loading")) { var equipment = new EquipmentModule(); Navigation.PushAsync(equipment); } }); toolEntries.Add(Equipment); //InOut ToolEntry InOut = new ToolEntry { Text = "In/Out", Image = "inout" }; InOut.IsVisible = PRSSecurity.IsAllowed(); InOut.OnTapped += ((object sender, EventArgs e) => { var staff_form = new StaffStatusPage(); Navigation.PushAsync(staff_form); }); toolEntries.Add(InOut); //Manufacturing ToolEntry Manufacturing = new ToolEntry { Text = "Manufacturing", Image = "manufacturingg" }; if (Device.RuntimePlatform.Equals(Device.iOS)) { Manufacturing.Image = "Image"; } Manufacturing.IsVisible = PRSSecurity.IsAllowed(); Manufacturing.OnTapped += ((object sender, EventArgs e) => { ManufacturingScreen manufacturingScreen = new ManufacturingScreen(); Navigation.PushAsync(manufacturingScreen); }); toolEntries.Add(Manufacturing); //My HR ToolEntry MyHR = new ToolEntry { Text = "My HR", Image = "myhr" }; MyHR.OnTapped += ((object sender, EventArgs e) => { MyHRHome myHRHome = new MyHRHome(); Navigation.PushAsync(myHRHome); }); toolEntries.Add(MyHR); //Notifications ToolEntry Notifications = new ToolEntry() { Text = "Notifications", Image = "notifications" }; Notifications.OnTapped += (object sender, EventArgs e) => { NotificationList notificationList = new NotificationList(); notificationList.NotificationsClosed += (n) => { NumberOfNotfications = n; RefreshOnNotificationsChange(); }; Navigation.PushAsync(notificationList); }; toolEntries.Add(Notifications); ToolEntry Products = new ToolEntry() { Text = "Products", Image = "products" }; Products.OnTapped += ((object sender, EventArgs e) => { //if (GlobalVariables.ProductsLoaded) //{ // ProductList products = new ProductList(GlobalVariables.ProductShells); // Navigation.PushAsync(products); //} //else //{ // ProductList products = new ProductList(); // Navigation.PushAsync(products); //} var page = new DataGridHost(new ProductsGrid()); Navigation.PushAsync(page); }); toolEntries.Add(Products); //Purchase Orders ToolEntry PurchaseOrders = new ToolEntry() { Text = "Purchase Orders", Image = "shoppingcart" }; PurchaseOrders.IsVisible = PRSSecurity.CanView(); PurchaseOrders.OnTapped += ((object sender, EventArgs e) => { PurchaseOrderModule page = new PurchaseOrderModule(); Navigation.PushAsync(page); }); toolEntries.Add(PurchaseOrders); //Scanner ToolEntry Scanner = new ToolEntry { Text = "Scanner", Image = "scanner" }; Scanner.OnTapped += ((object sender, EventArgs e) => { ScannerPage scannerPage = new ScannerPage(); Navigation.PushAsync(scannerPage); }); toolEntries.Add(Scanner); //Site ToolEntry Site = new ToolEntry { Text = "Site", Image = "construction" }; Site.OnTapped += ((object sender, EventArgs e) => { Site site = new Site(new Job { ID = MainPageUtils.Job.ID, Name = MainPageUtils.Job.Name, JobNumber = MainPageUtils.Job.JobNumber }); Navigation.PushAsync(site); //if (_job.ID == Guid.Empty) //{ // JobSelectionPage jobSelectionPage = new JobSelectionPage(true); // jobSelectionPage.OnItemSelected += (async () => // { // if (jobSelectionPage.Job.ID != Guid.Empty) // { // Job selectedJob = new Job(); // selectedJob.ID = jobSelectionPage.Job.ID; // selectedJob.JobNumber = jobSelectionPage.Job.JobNumber; // selectedJob.Name = jobSelectionPage.Job.Name; // Site site = new Site(selectedJob); // var previousPage = Navigation.NavigationStack.LastOrDefault(); // await Navigation.PushAsync(site); // Navigation.RemovePage(previousPage); // } // }); // Navigation.PushAsync(jobSelectionPage); //} }); toolEntries.Add(Site); //Store Requis ToolEntry StoreRequis = new ToolEntry { Text = "Store Requis", Image = "storerequis" }; StoreRequis.IsVisible = PRSSecurity.CanView(); StoreRequis.OnTapped += ((object sender, EventArgs e) => { var storeRequisList = new StoreRequiList(); Navigation.PushAsync(storeRequisList); }); toolEntries.Add(StoreRequis); //Tasks ToolEntry Tasks = new ToolEntry { Text = "Tasks", Image = "tasks" }; Tasks.IsVisible = PRSSecurity.IsAllowed(); Tasks.OnTapped += ((object sender, EventArgs e) => { var tasksForm = new TasksList(); Navigation.PushAsync(tasksForm); }); toolEntries.Add(Tasks); //Warehousing ToolEntry Warehousing = new ToolEntry { Text = "Warehousing", Image = "newwarehousing" }; Warehousing.IsVisible = PRSSecurity.CanView(); Warehousing.OnTapped += ((object sender, EventArgs e) => { Warehousing2 locations = new Warehousing2(); Navigation.PushAsync(locations); }); toolEntries.Add(Warehousing); AddChildren(); }); } catch { } } private void AddChildren() { Device.BeginInvokeOnMainThread(() => { foreach (ToolEntry toolEntry in toolEntries) { toolEntry.Margin = new Thickness(5, 0, 5, 0); flexLayout.Children.Add(toolEntry); } MainPageUtils.SearchForNewNotifications(); AddBlanks(); }); } private void AddBlanks() { for (int x = 0; x < 6; x++) { ToolEntry toolEntry = new ToolEntry(true); toolEntry.Margin = new Thickness(5, 0, 5, 0); flexLayout.Children.Add(toolEntry); } } private void Settings_Tapped(object sender, EventArgs e) { try { Settings settingsform = new Settings(); settingsform.Disappearing += (object sender2, EventArgs e2) => { settingsform = (Settings)sender2; if (settingsform.SettingsChanged) Navigation.PopModalAsync(); }; Navigation.PushAsync(settingsform); } catch { } } #endregion } }