| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560 | 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;using static comal.timesheets.CustomControls.JobShell;using static InABox.Mobile.LocationServices;using iText.Kernel.XMP.Impl;namespace comal.timesheets{    public delegate void MainPageNotificationsChanged();    public delegate void RefreshScreen();    public delegate void RequestUserInputForTask(Guid taskID);    public delegate void TaskTitleChanged(string title);    public static class MainPageUtils    {        public static event MainPageNotificationsChanged OnMainPageNotificationsChanged;        public static event RefreshScreen OnRefreshScreen;        public static event RequestUserInputForTask OnRequestUserInput;        public static event TaskTitleChanged OnTaskTitleChanged;        public static Assignment CurrentAssignment = null;        public static JobShell Job = new JobShell();        public static int NumberOfNotifications = 0;        public static string matchedDeviceName = "";        public static string deviceName = "";        public static bool bRecentlyUpdatedTiles = false;        public static TimeSheet _timesheet = null;        public static Employee _employee = null;        public static CoreTable _jobs = null;        public static bool firstLoad = true;        public static bool recentlyAskedToUpdate = true;        public static int updateCounter;        public static Kanban CurrentTask = null;        public static void Init()        {            InitEvents();            InitData();            InitTimers();        }        private static void InitEvents()        {            try            {                App.GPS.OnLocationFound += LocationFound;                App.GPS.OnLocationError += LocationError;                App.Bluetooth.OnScanFinished += ScanFinished;                App.Data.DataChanged += (s, t, e) => { OnRefreshScreen?.Invoke(); };                App.Data.DataRefreshed += () => { OnRefreshScreen?.Invoke(); };            }            catch { }        }        private static void InitData()        {            try            {                GlobalVariables.EmpID = GlobalVariables.GetEmployeeID();                GlobalVariables.EmpName = GlobalVariables.GetEmployeeName();                App.Data.Employee.ID = GlobalVariables.EmpID;                App.Data.Employee.Name = GlobalVariables.EmpName;            }            catch { }            try            {                _timesheet = App.Data.TimeSheets?.Rows.FirstOrDefault()?.ToObject<TimeSheet>();                _employee = App.Data.Employee;                _jobs = App.Data.Jobs;                deviceName = MobileUtils.GetDeviceID();                firstLoad = false;            }            catch { }        }        private static void InitTimers()        {            Timer t = new Timer(RecentlyAskedToUpdateTimer, null, 600000, 600000); //user is reminded to update when opening screen after timer of 10 minutes            updateCounter = 1; //user is forced to update after 3rd reminder            Timer t1 = new Timer(RecentlyUpdatedTilesTimer, null, 30000, 30000);            //bluetooth data is allowed to upload once every minute, notifications refreshing is piggybacked to this too        }        private static void RecentlyAskedToUpdateTimer(object o)        {            recentlyAskedToUpdate = false;        }        private static void RecentlyUpdatedTilesTimer(object o)        {            bRecentlyUpdatedTiles = false;            App.Data.Refresh(true);            SearchForNewNotifications();        }        #region Assignments        public static Assignment CheckCurrentAssignment()        {            Thread.Sleep(5000);            StartAssignmentTimer();            CoreTable table = new Client<Assignment>().Query(                     new Filter<Assignment>(x => x.EmployeeLink.ID).IsEqualTo(GlobalVariables.EmpID)                     .And(x => x.Date).IsEqualTo(DateTime.Today.Date)                     .And(x => x.Completed).IsEqualTo(null)                     .And(x => x.Booked.Finish).IsEqualTo(null),                     null,                     new SortOrder<Assignment>(x => x.Actual.Start, SortDirection.Ascending));            if (!table.Rows.Any())            {                Job.OnJobIDChanged += OnJobIDChanged;                return null;            }            else                return table.Rows.LastOrDefault().ToObject<Assignment>();        }        private static void StartAssignmentTimer()        {            Timer t = new Timer(AssignmentTimerCallback, null, 300000, 300000);        }        private static void AssignmentTimerCallback(object state)        {            try            {                if (CurrentAssignment != null)                    SaveCurrentAssignment("PRS Mobile main screen - Saving assignment on 5 minute timer");            }            catch            { }        }        public static void SaveCurrentAssignment(string auditnote, bool complete = false)        {            if (!complete)                CurrentAssignment.Booked.Finish = RoundToNearestInterval(DateTime.Now, new TimeSpan(0, 5, 0)).TimeOfDay;            else            {                CurrentAssignment.Actual.Finish = RoundToNearestInterval(DateTime.Now, new TimeSpan(0, 5, 0)).TimeOfDay;                CurrentAssignment.Completed = DateTime.Now;            }                          new Client<Assignment>().Save(CurrentAssignment, auditnote);        }        static DateTime RoundToNearestInterval(DateTime dt, TimeSpan d)        {            int f = 0;            double m = (double)(dt.Ticks % d.Ticks) / d.Ticks;            if (m >= 0.5)                f = 1;            return new DateTime(((dt.Ticks / d.Ticks) + f) * d.Ticks);        }        public static void UseCurrentAssignment(Assignment assgn)        {            try            {                CurrentAssignment = assgn;                SaveCurrentAssignment("PRS Mobile main screen - saving assignment on re-login to App");                if (CurrentAssignment.JobLink.ID != Guid.Empty)                {                    Job.ID = CurrentAssignment.JobLink.ID;                    var job = new Client<Job>().Query(new Filter<Job>(x => x.ID).IsEqualTo(Job.ID)).Rows.FirstOrDefault().ToObject<Job>();                    Job.JobNumber = job.JobNumber;                    Job.Name = job.Name;                    Job.OnJobIDChanged += OnJobIDChanged;                }                if (CurrentAssignment.Task.ID != Guid.Empty)                {                    var task = new Client<Kanban>().Query(new Filter<Kanban>(x => x.ID).IsEqualTo(CurrentAssignment.Task.ID)).Rows.FirstOrDefault().ToObject<Kanban>();                    OnTaskTitleChanged?.Invoke(task.Title);                }            }            catch { }        }        public static void OnJobIDChanged(Guid jobid)        {            if (CurrentAssignment == null)                CreateNewAssignment(jobid, Guid.Empty);            else            {                SaveCurrentAssignment("PRS Mobile main screen - saving assignment on job change", true);                CreateNewAssignment(jobid, Guid.Empty);            }        }        public static void CreateNewAssignment(Guid jobid, Guid taskID)        {            CurrentAssignment = new Assignment { Date = DateTime.Now.Date };            CurrentAssignment.EmployeeLink.ID = GlobalVariables.EmpID;            CurrentAssignment.Actual.Start = RoundToNearestInterval(DateTime.Now, new TimeSpan(0, 5, 0)).TimeOfDay;            CurrentAssignment.Booked.Start = CurrentAssignment.Actual.Start;            CurrentAssignment.Booked.Finish = RoundToNearestInterval(DateTime.Now, new TimeSpan(0, 5, 0)).TimeOfDay.Add(new TimeSpan(0, 5, 0));            if (jobid != Guid.Empty)                AddJobDetails(jobid);            if (taskID != Guid.Empty)                AddTaskDetails(taskID);        }        private static void AddJobDetails(Guid jobid)        {            CurrentAssignment.JobLink.ID = jobid;            var job = new Client<Job>().Query(new Filter<Job>(x => x.ID).IsEqualTo(jobid)).Rows.FirstOrDefault().ToObject<Job>();            CurrentAssignment.Title = "Clocking on to job " + job.Name + " (" + job.JobNumber + ") on PRS Mobile";            OnTaskTitleChanged?.Invoke("Task");            new Client<Assignment>().Save(CurrentAssignment, "Changed job on mobile - creating new assignment");        }        private static void AddTaskDetails(Guid taskID)        {            CurrentAssignment.Task.ID = taskID;            var task = new Client<Kanban>().Query(new Filter<Kanban>(x => x.ID).IsEqualTo(taskID)).Rows.FirstOrDefault().ToObject<Kanban>();            CurrentAssignment.Title = "Clocking on to task " + task.Title + " on PRS Mobile";            OnTaskTitleChanged?.Invoke(task.Title);            if (!string.IsNullOrWhiteSpace(task.JobLink.JobNumber))                Job.JobNumber = task.JobLink.JobNumber;            new Client<Assignment>().Save(CurrentAssignment, "Changed task on mobile - creating new assignment");        }        #endregion        #region Notifications        public static Page DetermineCorrectPage(Plugin.LocalNotification.EventArgs.NotificationActionEventArgs e)        {            string data = e.Request.ReturningData;            int index = data.IndexOf("$");            Guid ID = Guid.Parse(data.Remove(index));            string type = data.Substring(index + 1);            if (type == "Comal.Classes.Kanban")                return new AddEditTask(ID);            else if (type == "Comal.Classes.Delivery")                return new DeliveryDetails(ID);            else                return null;        }        public static async void SearchForNewNotifications()        {            //notifications poll reliably in the background for Anroid, unreliable for iOS due to difficulty with cross-platform plugins for notifications            try            {                await Task.Run(() =>                {                    if (ClientFactory.UserGuid != Guid.Empty)                    {                        CoreTable table = new Client<Notification>().Query                        (new Filter<Notification>(x => x.Employee.UserLink.ID).IsEqualTo(ClientFactory.UserGuid).And(X => X.Closed).IsEqualTo(DateTime.MinValue),                            new Columns<Notification>(                                   x => x.ID, //0                                   x => x.Sender.Name, //1                                      x => x.Title, //2                                   x => x.Created, //3                                   x => x.Description, //4                                   x => x.EntityType, //5                                   x => x.EntityID //6                                   )                        );                        if (NumberOfNotifications == table.Rows.Count()) //no new notifications or none present at all                            return;                        else //new notifications or previous notifications have now been dismissed                        {                            NumberOfNotifications = table.Rows.Count();                            OnMainPageNotificationsChanged?.Invoke();                            CheckNotificationsPushed(table);                        }                    }                });            }            catch { }        }        private static 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<NotificationShell> toNotify = new List<NotificationShell>();                foreach (CoreRow row in table.Rows)                {                    List<object> 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 static async Task PushNotificationsAsync(List<NotificationShell> 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 { }        }        #endregion        #region Location / Bluetooth        private static void LocationFound(LocationServices sender)        {            //if (bSharedDevice)            //    return;            if (App.Bluetooth.RecentlyScanned)                UploadTiles();            try            {                TimeSheet timesheet = App.Data.TimeSheets?.Rows.FirstOrDefault()?.ToObject<TimeSheet>();                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<TimeSheet>().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<GPSTrackerLocation>().Save(gpsTrackerLocation, "Updated company device location from Timebench");                }                OnRefreshScreen?.Invoke();            }            catch { }        }        private static 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<GPSTrackerLocation> trackersToUpdate = new List<GPSTrackerLocation>();                    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<GPSTrackerLocation>().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<GPSTrackerLocation>().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<GPSTrackerLocation>().Save(location, "Found Kontakt Device"); //, SaveTrackerCallback);            //}            //if (locations.Any())            //    new Client<GPSTrackerLocation>().Save(locations, "Updating Bluetooth Device Locations", (o, e) => { });            #endregion        }        private static void LocationError(LocationServices sebder, Exception error)        {        }        private static void ScanFinished(Bluetooth sender)        {            try            {                OnRefreshScreen?.Invoke();                if (App.GPS.RecentlyLocated)                    UploadTiles();            }            catch { }        }        #endregion        public static Dictionary<Guid, string> GetTasks()        {            Dictionary<Guid, string> dict = new Dictionary<Guid, string>();            CoreTable table = new Client<Kanban>().Query(                new Filter<Kanban>(x => x.EmployeeLink.ID).IsEqualTo(GlobalVariables.EmpID)                .And(x => x.Category).IsNotEqualTo("Complete"),                new Columns<Kanban>(x => x.ID, x => x.Title)                );            foreach (CoreRow row in table.Rows)            {                dict.Add                    (                        row.Get<Kanban, Guid>(x => x.ID),                        row.Get<Kanban, string>(x => x.Title)                    );            }            return dict;        }        public static void OnTaskSelected(Guid ID, string title)        {            if (CurrentAssignment != null)                OnRequestUserInput?.Invoke(ID);            else                CreateNewAssignment(Guid.Empty, ID);        }        public static void ChangeAssignmentTask(Guid taskID)        {            AddTaskDetails(taskID);        }    }}
 |