using System; using System.Collections; using System.Collections.ObjectModel; using InABox.Clients; using InABox.Core; using Comal.Classes; using Xamarin.Forms; using System.Linq; using System.Threading.Tasks; using InABox.Configuration; using InABox.Mobile; using Syncfusion.SfSchedule.XForms; using XF.Material.Forms; using XF.Material.Forms.UI.Dialogs; using XF.Material.Forms.UI.Dialogs.Configurations; namespace PRS.Mobile { public enum AssignmentViewType { Day, TimeLine } public enum AssignmentLookupType { ActiveJobs, UnbookedJobs, Tasks } public class SelectedColorConverter : AbstractConverter { public Color SelectedColor { get; set; } public Color UnselectedColor { get; set; } protected override Color Convert(ILookupShell value, object? parameter = null) { return (value?.Parent as ICoreRepository)?.IsSelected(value) == true ? SelectedColor : UnselectedColor; } } public partial class AssignmentList { private AssignmentModel DataModel { get; set; } private Guid[] _employeeids; private readonly AssignmentModuleSettings _settings; private AssignmentViewType _view; private AssignmentLookupType _lookuptype; private String _teamname; private DateTime _currentdate; public AssignmentList() { InitializeComponent(); DataModel = new AssignmentModel(App.Data, GetFilter); BindingContext = DataModel; _settings = new LocalConfiguration().Load(); _currentdate = _settings.Date.IsEmpty() ? DateTime.Today : _settings.Date; _view = _settings.View; _employeeids = _settings.Employees ?? new[] { App.Data.Me.ID }; _lookuptype = _settings.LookupType; LookupType.Text = CoreUtils.Neatify(_lookuptype.ToString()); _teamname = String.IsNullOrWhiteSpace(_settings.TeamName) ? App.Data.Me.Name : _settings.TeamName; ShowHideSources.IsVisible = Security.IsAllowed(); } protected override void OnAppearing() { base.OnAppearing(); Task[] tasks = new Task[] { Task.Run(() => App.Data.Employees.Refresh(false)), Task.Run(() => App.Data.Jobs.Refresh(false)), }; Task.WaitAll(tasks); RefreshLookups(); Reload(); } private void RefreshLookups(bool reset = false) { var items = _lookuptype switch { AssignmentLookupType.Tasks => App.Data.Kanbans, AssignmentLookupType.ActiveJobs => App.Data.Jobs.Search(x => true), _ => App.Data.Jobs.Search(x => x.OpenAssignments == 0) }; if (reset) items.SelectNone(); Device.BeginInvokeOnMainThread(() => { Lookups.ItemsSource = null; Lookups.ItemsSource = items.Items; }); } private void Reload() { DayView.DataSource = null; TimeLineView.DataSource = null; ScheduleType.Text = _teamname; if (_view == AssignmentViewType.Day) { TimelineFrame.IsVisible = false; DayFrame.IsVisible = true; DayView.DayViewSettings.DayLabelSettings.TimeFormat = "HH:mm"; } else { DayFrame.IsVisible = false; TimelineFrame.IsVisible = true; TimeLineView.ResourceViewSettings.VisibleResourceCount = Math.Max(1, Math.Min(16, _employeeids.Length)); TimeLineView.TimelineViewSettings.AppointmentHeight = (this.Height / TimeLineView.ResourceViewSettings.VisibleResourceCount) + 100; var resources = new ObservableCollection(); foreach (var empid in _employeeids) { var emp = App.Data.Employees.Items.FirstOrDefault(x => x.ID == empid); var empname = emp?.Name ?? emp?.Code ?? empid.ToString(); if (_employeeids.Length > 10) empname = String.Join("", empname.Split(' ').Select(x => x.Substring(0, 1))); else if (_employeeids.Length > 6) { var comps = empname.Split(' ').ToArray(); empname = $"{comps.First()} {String.Join("", comps.Skip(1).Select(x => x.Substring(0, 1)))}"; } resources.Add( new ScheduleResource() { Name = empname, Id = empid, Color = Color.Transparent, Image = "" } ); } TimeLineView.ScheduleResources = resources; TimeLineView.ShowResourceView = true; } RefreshData(); } private Filter GetFilter() => new Filter(x => x.Date).IsEqualTo(_currentdate) .And(x => x.EmployeeLink.ID).InList(_employeeids); private void RefreshData() { DataModel.Refresh(true, () => Device.BeginInvokeOnMainThread(UpdateScreen)); } private void UpdateScreen() { Title = $"{_currentdate:dd MMMM yyyy}"; if (_view == AssignmentViewType.Day) { DayView.DataSource = new ObservableCollection(DataModel.Items); DayView.MoveToDate = ShowRelevantTime(); } else { TimeLineView.DataSource = new ObservableCollection(DataModel.Items); TimeLineView.MoveToDate = ShowRelevantTime(); } } private DateTime ShowRelevantTime() { return (DataModel.Items.Count > 0 ? DataModel.Items.First().StartTime : DateTime.Now).AddMinutes(-30); } private void Lookups_OnItemTapped(object sender, ItemTappedEventArgs e) { } private void Lookups_Clicked(object sender, EventArgs e) { var item = (sender as MobileCard)?.BindingContext; ICoreRepository model = _lookuptype == AssignmentLookupType.Tasks ? App.Data.Kanbans : App.Data.Jobs as ICoreRepository; model.SelectNone(); model.SelectItem(item); } private void LookupsType_Tapped(object sender, EventArgs e) { _lookuptype = _lookuptype == AssignmentLookupType.Tasks ? AssignmentLookupType.ActiveJobs : _lookuptype == AssignmentLookupType.ActiveJobs ? AssignmentLookupType.UnbookedJobs : AssignmentLookupType.Tasks; _settings.LookupType = _lookuptype; LookupType.Text = CoreUtils.Neatify(_lookuptype.ToString()); new LocalConfiguration().Save(_settings); RefreshLookups(true); } private void Schedule_OnCellTapped(object sender, CellTappedEventArgs e) { if (e.Appointment is AssignmentShell item) { if (item.DeliveryID != Guid.Empty) { ProgressVisible = true; DeliveryEdit editor = null; Task.Run(() => { editor = DeliveryEdit.Load(item.DeliveryID); }).Wait(); ProgressVisible = false; if (editor != null) Navigation.PushAsync(editor); else DisplayAlert("Error", "Cannot Load Delivery!", "OK"); } else { var editor = new AssignmentEdit(){ Item = item }; Navigation.PushAsync(editor); } } } private async void Schedule_OnCellLongPressed(object sender, CellTappedEventArgs e) { if (e.Appointment == null) { if (Security.CanEdit()) { CreateAssignment( e.Datetime, e.Resource as ScheduleResource ); } } else if (Security.CanDelete() && e.Appointment is AssignmentShell assignment) { await DeleteAssignment(assignment.ID); } } private void CreateAssignment(DateTime date, ScheduleResource resource) { var shell = DataModel.AddItem(); shell.Date = date.Date; shell.Title = "New Assignment"; shell.BookedStart = new TimeSpan(date.TimeOfDay.Hours, 0, 0); shell.BookedFinish = date.TimeOfDay.Add(new TimeSpan(1, 0, 0)); shell.BookedDuration = new TimeSpan(1, 0, 0); shell.EmployeeID = (resource is { } sr) ? (Guid)sr.Id : App.Data.Me.ID; var job = (_lookuptype == AssignmentLookupType.ActiveJobs) || (_lookuptype == AssignmentLookupType.UnbookedJobs) ? App.Data.Jobs.SelectedItems.FirstOrDefault() : null; if (job != null) { shell.JobID = job.ID; shell.JobNumber = job.JobNumber; shell.JobName = job.Name; shell.Description = String.Join("\n",job.Notes); shell.Title = job.DisplayName; } var task = _lookuptype == AssignmentLookupType.Tasks ? App.Data.Kanbans.SelectedItems.FirstOrDefault() : null; if (task != null) { shell.TaskID = task.ID; shell.TaskNumber = task.Number; shell.TaskName = task.Description; shell.Title = task.Title; shell.Description = task.Description; App.Data.Kanbans.SelectNone(); } var editor = new AssignmentEdit() { Item = shell }; Navigation.PushAsync(editor); } private async Task DeleteAssignment(Guid id) { var confirm = await MaterialDialog.Instance.ConfirmAsync( "Are you sure you wish to delete this assignment?", "Confirm Deletion", "Yes, Delete", "Cancel", new MaterialAlertDialogConfiguration() { ButtonFontFamily = Material.FontFamily.Body2 } ); if (confirm == true) { using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Deleting Assignment")) { var assignment = new Assignment() { ID = id }; new Client().Delete(assignment, "Deleted on Mobile Device"); } RefreshData(); } } private void SelectDate_OnClicked(object sender, EventArgs e) { var selector = new MobileDateSelector(); selector.Date = _currentdate; selector.Changed += (o, args) => { ChangeDate(args.Date); DismissPopup(); }; ShowPopup(() => selector); } private void ChangeDate(DateTime date) { if (_employeeids.Any()) { _currentdate = date; _settings.Date = date; new LocalConfiguration().Save(_settings); } DayView.MoveToDate = date; TimeLineView.MoveToDate = date; RefreshData(); } private void SelectEmployees_OnClicked(object sender, EventArgs e) { ShowPopup(() => CreateTeamSelection("Select Employees", (team) => { if (team == null) { _view = AssignmentViewType.Day; _employeeids = new[] { App.Data.Me.ID }; _teamname = App.Data.Me.Name; } else { _view = AssignmentViewType.TimeLine; _employeeids = App.Data.EmployeeTeams.Where(x => x.TeamID == team.ID) .Select(x => x.ID).Distinct().ToArray(); _teamname = team.Name; } _settings.Employees = _employeeids; _settings.View = _view; _settings.TeamName = _teamname; new LocalConfiguration().Save(_settings); Dispatcher.BeginInvokeOnMainThread(Reload); })); } private View CreateTeamSelection(String caption, Action selected) { SelectionView selection = new SelectionView { VerticalOptions = LayoutOptions.Fill, HorizontalOptions = LayoutOptions.Fill }; selection.Configure += (sender, args) => { args.Columns .BeginUpdate() .Clear() .Add(new MobileGridTextColumn() { Column = x=>x.Name, Width = GridLength.Star, Caption = caption, Alignment = TextAlignment.Start}) .EndUpdate(); }; selection.Refresh += (sender, args) => { App.Data.EmployeeTeams.Refresh(false); return App.Data.EmployeeTeams.AvailableTeams; }; selection.SelectionChanged += (sender, args) => { selected(args.SelectedItems.FirstOrDefault() as EmployeeTeamSummary); DismissPopup(); }; selection.AddButton("Only Me", () => { selected(null); DismissPopup(); }); selection.Load(); return selection; } private bool _sidebarvisible; private void ShowHideSources_OnClicked(object sender, EventArgs e) { _sidebarvisible = !_sidebarvisible; ShowHideSources.Source = _sidebarvisible ? ImageSource.FromFile("arrow_white_right") : ImageSource.FromFile("arrow_white_down"); JobColumn.Width = _sidebarvisible ? new GridLength(150, GridUnitType.Absolute) : new GridLength(0, GridUnitType.Absolute); } private void NextDay_OnClicked(object sender, MobileButtonClickEventArgs args) { ChangeDate(_currentdate.AddDays(1)); } private void PrevDay_OnClicked(object sender, MobileButtonClickEventArgs args) { ChangeDate(_currentdate.AddDays(-1)); } } }