Переглянути джерело

Updates to Assignments Module

Frank van den Bos 2 роки тому
батько
коміт
47a7be3cd6

+ 1 - 1
prs.classes/Entities/Job/Job.cs

@@ -103,7 +103,7 @@ namespace Comal.Classes
         public TimeSpan LabourHours { get; set; }
 
         [NullEditor]
-        [Obsolete("Why does this even exist?", true)]
+        [Obsolete("Why does this even exist?")]
         public ProductStyleLink Style { get; set; }
 
         [NullEditor]

+ 10 - 6
prs.mobile/comal.timesheets/Assignments/AssignmentDetails.xaml

@@ -18,6 +18,7 @@
                 <RowDefinition Height="Auto"/>
                 <RowDefinition Height="Auto"/>
                 <RowDefinition Height="Auto"/>
+                <RowDefinition Height="Auto"/>
                 <RowDefinition Height="*"/>
                 <RowDefinition Height="Auto"/>
             </Grid.RowDefinitions>
@@ -26,21 +27,24 @@
             <Entry Grid.Row="0" Grid.Column="1" x:Name="Subject" Text="{Binding Item.Subject}" TextChanged="Subject_OnTextChanged"/>
         
             <Label Grid.Row="1" Grid.Column="0" Text="From" VerticalOptions="Fill" VerticalTextAlignment="Center"/>
-            <TimePicker Grid.Row="1" Grid.Column="1" x:Name="Start" Time="{Binding Item.Start}"/>
+            <TimePicker Grid.Row="1" Grid.Column="1" x:Name="Start" Time="{Binding Item.Start}" Unfocused="Start_OnUnfocused"/>
             
             <Label Grid.Row="2" Grid.Column="0" Text="To" VerticalOptions="Fill" VerticalTextAlignment="Center"/>
             <TimePicker Grid.Row="2" Grid.Column="1" x:Name="Finish" Time="{Binding Item.Finish}" Unfocused="Finish_OnUnfocused" />
             
             <Label Grid.Row="3" Grid.Column="0" Text="Job" VerticalOptions="Fill" VerticalTextAlignment="Center"/>
             <ui:MaterialButton Grid.Row="3" Grid.Column="1" x:Name="Job" Text="{Binding Item.JobDisplay}" Clicked="Job_Clicked" Margin="-5"/>
+            
+            <Label Grid.Row="4" Grid.Column="0" Text="Task" VerticalOptions="Fill" VerticalTextAlignment="Center"/>
+            <ui:MaterialButton Grid.Row="4" Grid.Column="1" x:Name="Task" Text="{Binding Item.TaskDisplay}" Clicked="Task_Clicked" Margin="-5"/>
 
-            <Label Grid.Row="4" Grid.Column="0" Text="Activity" VerticalOptions="Fill" VerticalTextAlignment="Center"/>
-            <ui:MaterialButton Grid.Row="4" Grid.Column="1" x:Name="Activity" Text="{Binding Item.ActivityDisplay}" Clicked="Activity_Clicked" Margin="-5"/>  
+            <Label Grid.Row="5" Grid.Column="0" Text="Activity" VerticalOptions="Fill" VerticalTextAlignment="Center"/>
+            <ui:MaterialButton Grid.Row="5" Grid.Column="1" x:Name="Activity" Text="{Binding Item.ActivityDisplay}" Clicked="Activity_Clicked" Margin="-5"/>  
 
-            <Label Grid.Row="5" Grid.Column="0" Text="Notes"/>
-            <Editor Grid.Row="5" Grid.Column="1" x:Name="Description" Text="{Binding Item.Description}" TextChanged="Description_OnTextChanged"/>
+            <Label Grid.Row="6" Grid.Column="0" Text="Notes"/>
+            <Editor Grid.Row="6" Grid.Column="1" x:Name="Description" Text="{Binding Item.Description}" TextChanged="Description_OnTextChanged"/>
             
-            <ui:MaterialButton Grid.Row="6" Grid.Column="1" x:Name="Completed" Text="Complete" Clicked="Complete_Clicked" Margin="-5"/>  
+            <ui:MaterialButton Grid.Row="7" Grid.Column="1" x:Name="Completed" Text="Complete" Clicked="Complete_Clicked" Margin="-5"/>  
         </Grid>
     </ScrollView>
 

+ 35 - 2
prs.mobile/comal.timesheets/Assignments/AssignmentDetails.xaml.cs

@@ -51,6 +51,7 @@ namespace comal.timesheets
             Start.IsEnabled = open && InABox.Core.Security.CanEdit<Assignment>();
             Finish.IsEnabled = open && InABox.Core.Security.CanEdit<Assignment>();
             Job.IsEnabled = open && InABox.Core.Security.CanEdit<Assignment>();
+            Task.IsEnabled = open && InABox.Core.Security.CanEdit<Assignment>();
             Activity.IsEnabled = open && InABox.Core.Security.CanEdit<Assignment>();
             Description.IsEnabled = open && InABox.Core.Security.CanEdit<Assignment>();
             Completed.IsEnabled = open || InABox.Core.Security.CanEdit<Assignment>();
@@ -123,6 +124,39 @@ namespace comal.timesheets
             catch
             {
                 
+            }            
+        }        
+        
+        private void Task_Clicked(object sender, EventArgs e)
+        {
+            try
+            {
+                GenericSelectionPage page = new GenericSelectionPage(
+                    "Select Task",
+                    new SelectionViewModel<Kanban>(
+                        new Filter<Kanban>(x => x.Completed).IsEqualTo(DateTime.MinValue),
+                        new Expression<Func<Kanban, object>>[]
+                            { x => x.Number, x => x.Title },
+                        new Expression<Func<Kanban, object>>[] { x => x.ID},
+                        new SortOrder<Kanban>(x => x.Number, SortDirection.Descending)
+                    )
+                );
+                page.OnItemSelected += (row) =>
+                {
+                    Device.BeginInvokeOnMainThread(() =>
+                    {
+                        DataModel.Item.TaskID = row.Get<Kanban, Guid>(c => c.ID);
+                        DataModel.Item.TaskNumber = row.Get<Kanban, int>(c => c.Number);
+                        DataModel.Item.TaskName = row.Get<Kanban, String>(c => c.Title);
+                        OnDetailsChanged?.Invoke(this,new AssignmentDetailsChangedArgs("Task"));
+                    });
+                };
+                Navigation.PushAsync(page);
+
+            }
+            catch
+            {
+                
             }            
         }
 
@@ -169,8 +203,7 @@ namespace comal.timesheets
             if (Description.IsFocused)
                 OnDetailsChanged?.Invoke(this, new AssignmentDetailsChangedArgs("Description"));
         }
-
-
+        
         private void Subject_OnTextChanged(object sender, TextChangedEventArgs e)
         {
             if (Subject.IsFocused)

+ 5 - 1
prs.mobile/comal.timesheets/Assignments/AssignmentEdit.xaml.cs

@@ -39,7 +39,11 @@ namespace comal.timesheets
                 Map.Load();
                 
                 Forms.Load();
-                
+
+                NavigationPage.SetHasBackButton(this, DataModel.Item.ID != Guid.Empty);
+                Cancel.IsVisible = DataModel.Item.ID == Guid.Empty;
+                Save.IsVisible = DataModel.Item.ID == Guid.Empty;
+
             });
         }
         

+ 0 - 144
prs.mobile/comal.timesheets/Assignments/AssignmentEditDataModelItem.cs

@@ -1,144 +0,0 @@
-using System;
-using System.ComponentModel;
-using System.Linq.Expressions;
-using System.Runtime.CompilerServices;
-using Comal.Classes;
-using InABox.Core;
-
-namespace comal.timesheets
-{
-    public class AssignmentEditDataModelItem : SingleDataModelItem<Assignment>
-    {
-        
-        public Guid ID => GetValue(x => x.ID);
-        
-        public Guid EmployeeID 
-        {
-            get => GetValue(c => c.EmployeeLink.ID);
-            set => UpdateValue(c => c.EmployeeLink.ID, value);
-        }  
-
-        public int Number
-        {
-            get => GetValue(c => c.Number);
-            set => UpdateValue(c=>c.Number,value);
-        }
-        
-        public String Subject
-        {
-            get => GetValue(c => c.Title);
-            set => UpdateValue(c=>c.Title,value);
-        }
-
-        public String Description
-        {
-            get => GetValue(c => c.Description);
-            set => UpdateValue(c => c.Description, value);
-        }
-        
-        public DateTime Date 
-        {
-            get => GetValue(c => c.Date);
-            set => UpdateValue(c => c.Date, value);
-        }
-
-        public TimeSpan Start
-        {
-            get => GetValue(c => c.Start);
-            set => UpdateValue(c => c.Start, value);
-        }
-
-        public TimeSpan Duration
-        {
-            get => GetValue(c => c.Duration);
-            set => UpdateValue(c => c.Duration, value);
-        }
-        
-        public TimeSpan Finish 
-        {
-            get => GetValue(c => c.Finish);
-            set => UpdateValue(c => c.Finish, value);
-        }
-        
-        public Guid JobID 
-        {
-            get => GetValue(c => c.JobLink.ID);
-            set => UpdateValue(c => c.JobLink.ID, value);
-        }        
-        
-        public String JobNumber 
-        {
-            get => GetValue(c => c.JobLink.JobNumber);
-            set
-            {
-                UpdateValue(c => c.JobLink.JobNumber, value, false);
-                DoPropertyChanged(nameof(JobDisplay));
-            }
-        }           
-        
-        public String JobName 
-        {
-            get => GetValue(c => c.JobLink.Name);
-            set
-            {
-                UpdateValue(c => c.JobLink.Name, value, false);
-                DoPropertyChanged(nameof(JobDisplay));
-            }
-        }    
-        
-        public String JobDisplay => JobID != Guid.Empty
-            ? String.Format("{0}: {1}", JobNumber, JobName )
-            : "(No Job Selected)";
-        
-        public Guid ActivityID 
-        {
-            get => GetValue(c => c.ActivityLink.ID);
-            set => UpdateValue(c => c.ActivityLink.ID, value);
-        }        
-        
-        public String ActivityCode 
-        {
-            get => GetValue(c => c.ActivityLink.Code);
-            set
-            {
-                UpdateValue(c => c.ActivityLink.Code, value, false);
-                DoPropertyChanged(nameof(ActivityDisplay));
-            }
-        }           
-        
-        public String ActivityDescription
-        {
-            get => GetValue(c => c.ActivityLink.Description);
-            set
-            {
-                UpdateValue(c => c.ActivityLink.Description, value, false);
-                DoPropertyChanged(nameof(ActivityDisplay));
-            }
-        }
-        
-        public String ActivityColor
-        {
-            get => GetValue(c => c.ActivityLink.Color);
-            set
-            {
-                UpdateValue(c => c.ActivityLink.Color, value, false);
-                DoPropertyChanged(nameof(ActivityColor));
-            }
-        }
-
-        public String ActivityDisplay => ActivityID != Guid.Empty
-            ? String.Format("{0}: {1}", ActivityCode, ActivityDescription)
-            : "(No Activity Selected)";
-
-        public DateTime Completed
-        {
-            get => GetValue(c => c.Completed);
-            set
-            {
-                UpdateValue(c => c.Completed, value);
-                DoPropertyChanged(nameof(Completed));
-            }
-        }
-        
-    }
-}

+ 78 - 3
prs.mobile/comal.timesheets/Assignments/AssignmentList.xaml

@@ -121,12 +121,36 @@
             <Grid.ColumnDefinitions>
                 <ColumnDefinition Width="*" x:Name="DayViewColumn"/>
                 <ColumnDefinition Width="0" x:Name="TimeLineViewColumn"/>
+                <ColumnDefinition Width="150" x:Name="JobColumn" />
             </Grid.ColumnDefinitions>
             <Grid.RowDefinitions>
+                <RowDefinition Height="40"/>
                 <RowDefinition Height="*"/>
             </Grid.RowDefinitions>
-
-            <schedule:SfSchedule  x:Name="DayView"
+            
+            <Frame 
+                Grid.Row="0"
+                Grid.Column="0"
+                Grid.ColumnSpan="2"
+                CornerRadius="2"
+                BorderColor="Silver"
+                BackgroundColor="WhiteSmoke"
+                HasShadow="False"
+                Margin="0"
+                Padding="2"
+                >
+                <Label 
+                    x:Name="ScheduleType" 
+                    HorizontalOptions="Fill" 
+                    VerticalOptions="Fill" 
+                    VerticalTextAlignment="Center" 
+                    HorizontalTextAlignment="Center"
+                    FontSize="Micro"/>
+            </Frame>
+            
+            <schedule:SfSchedule  
+                x:Name="DayView"
+                Grid.Row="1"
                 Grid.Column="0"
                 ScheduleView="DayView" 
                 HeaderHeight="0"
@@ -138,6 +162,7 @@
                 ShowResourceView="False"
                 ResourceViewMode="Absolute"
                 TimeIntervalHeight="150"
+                AllowAppointmentDrag="True"
                 AppointmentMapping="{StaticResource AppointmentMapping}"
                 AppointmentTemplate="{StaticResource DayViewAppointments}"
                 CellTapped="Schedule_OnCellTapped"
@@ -150,7 +175,9 @@
                 
             </schedule:SfSchedule>
             
-            <schedule:SfSchedule x:Name="TimeLineView"
+            <schedule:SfSchedule 
+                x:Name="TimeLineView"
+                Grid.Row="1"
                 Grid.Column="1"
                 ScheduleView="TimelineView" 
                 HeaderHeight="0"
@@ -162,6 +189,7 @@
                 ResourceViewHeight="50"
                 ResourceViewMode="Absolute"
                 TimeIntervalHeight="150"
+                AllowAppointmentDrag="True"
                 AppointmentMapping="{StaticResource AppointmentMapping}"
                 AppointmentTemplate="{StaticResource DayViewAppointments}"
                 CellTapped="Schedule_OnCellTapped"
@@ -188,6 +216,53 @@
                 </schedule:SfSchedule.ResourceItemTemplate>
                 
             </schedule:SfSchedule>
+            
+            <Frame 
+                Grid.Row="0"
+                Grid.Column="2"
+                CornerRadius="2"
+                BorderColor="Silver"
+                BackgroundColor="WhiteSmoke"
+                HasShadow="False"
+                Margin="0"
+                Padding="2"
+                >
+                <Frame.GestureRecognizers>
+                    <TapGestureRecognizer Tapped="LookupsType_Tapped" />
+                </Frame.GestureRecognizers>
+                <Label 
+                    x:Name="LookupType" 
+                    HorizontalOptions="Fill" 
+                    VerticalOptions="Fill" 
+                    VerticalTextAlignment="Center" 
+                    HorizontalTextAlignment="Center"
+                    FontSize="Micro"/>
+            </Frame>
+            
+            <ListView 
+                x:Name="Lookups" 
+                Grid.Row="1"
+                Grid.Column="2" 
+                HasUnevenRows="True" 
+                ItemTapped="Lookups_OnItemTapped">
+                <ListView.ItemTemplate>
+                    <DataTemplate>
+                        <ViewCell>
+                            <Frame BorderColor="Silver" CornerRadius="2" HasShadow="False" VerticalOptions="FillAndExpand" BackgroundColor="{Binding Colour}" Margin="0,0,2,2">
+                                <Grid VerticalOptions="FillAndExpand">
+                                    <Grid.RowDefinitions>
+                                        <RowDefinition Height="Auto"/>
+                                        <RowDefinition Height="Auto"/>
+                                    </Grid.RowDefinitions>
+                                    <Label Text="{Binding Number}" Grid.Row="0" VerticalOptions="FillAndExpand" HorizontalTextAlignment="Center" FontSize="Micro"/>
+                                    <Label Text="{Binding Name}" Grid.Row="1" VerticalOptions="FillAndExpand" HorizontalTextAlignment="Center" FontSize="Micro"/>
+                                </Grid>
+                            </Frame>
+                        </ViewCell>
+                    </DataTemplate>
+                </ListView.ItemTemplate>
+            </ListView>
+            
         </Grid>
     </ContentPage.Content>
 </ContentPage>

+ 194 - 53
prs.mobile/comal.timesheets/Assignments/AssignmentList.xaml.cs

@@ -7,12 +7,11 @@ using Comal.Classes;
 using Xamarin.Forms;
 using System.Linq;
 using System.Threading.Tasks;
-using comal.timesheets.CustomControls;
-using comal.timesheets.iOS.Assignments;
+using System.Windows.Input;
+using ARKit;
 using InABox.Configuration;
-using Syncfusion.Office;
 using Syncfusion.SfSchedule.XForms;
-using Xamarin.Forms.Xaml;
+using WebSocketSharp;
 using XF.Material.Forms;
 using XF.Material.Forms.UI.Dialogs;
 using XF.Material.Forms.UI.Dialogs.Configurations;
@@ -25,6 +24,13 @@ namespace comal.timesheets
         Day,
         TimeLine
     }
+
+    public enum AssignmentLookupType
+    {
+        ActiveJobs,
+        UnbookedJobs,
+        Tasks
+    }
     
     public partial class AssignmentList : ContentPage
     {
@@ -37,11 +43,21 @@ namespace comal.timesheets
 
         private AssignmentView _view = AssignmentView.Day;
 
+        private AssignmentLookupType _lookuptype = AssignmentLookupType.UnbookedJobs;
+
+        private String _teamname = "";
+
+        private AssignmentJobDataModel _jobs = null;
+        private AssignmentKanbanDataModel _kanbans = null;
+
         public AssignmentList()
         {
             InitializeComponent();
             _settings = new LocalConfiguration<AssignmentModuleSettings>().Load();
 
+            _jobs = new AssignmentJobDataModel();
+            _kanbans = new AssignmentKanbanDataModel();
+            
             DatePicker.Date = _settings.Date.IsEmpty() ? DateTime.Today : _settings.Date;
             
             _view = _settings.View;
@@ -49,22 +65,61 @@ namespace comal.timesheets
             _employeeids = (_settings.Employees != null)
                 ? _settings.Employees
                 : new Guid[] { App.Data.Employee.ID };
-            
+
+            _lookuptype = _settings.LookupType;
+            LookupType.Text = CoreUtils.Neatify(_lookuptype.ToString());
+
+            _teamname = _settings.TeamName;
+
         }
         
-        
         protected override void OnAppearing()
         {
             base.OnAppearing();
+            RefreshLookups();
             Reload();
         }
         
+        private void RefreshLookups()
+        {
+            if (_lookuptype == AssignmentLookupType.Tasks)
+            {
+                _kanbans.Load(
+                    new Filter<Kanban>(x=>x.Completed).IsEqualTo(DateTime.MinValue),
+                    () => Dispatcher.BeginInvokeOnMainThread(() =>
+                    {
+                        Lookups.ItemsSource = new ObservableCollection<AssignmentKanbanItem>(_kanbans.Items);
+                    }));
+            }
+            else if (_lookuptype == AssignmentLookupType.ActiveJobs)
+            {
+                _jobs.Load(
+                    new Filter<Job>(x=>x.JobStatus.Active).IsEqualTo(true),
+                    () => Dispatcher.BeginInvokeOnMainThread(() =>
+                    {
+                        Lookups.ItemsSource = new ObservableCollection<AssignmentJobItem>(_jobs.Items);
+                    }));               
+            }
+            else if (_lookuptype == AssignmentLookupType.UnbookedJobs)
+            {
+                _jobs.Load(
+                    new Filter<Job>(x=>x.JobStatus.Active).IsEqualTo(true)
+                        .And(x=>x.OpenAssignments).IsEqualTo(0),
+                    () => Dispatcher.BeginInvokeOnMainThread(() =>
+                    {
+                        Lookups.ItemsSource = new ObservableCollection<AssignmentJobItem>(_jobs.Items);
+                    }));                 
+            }            
+        }
+        
         private void Reload()
         {
 
             DayView.DataSource = null;         
             TimeLineView.DataSource = null;    
             
+            ScheduleType.Text = _teamname;
+            
             if (_view == AssignmentView.Day)
             {
                 DayViewColumn.Width = new GridLength(1, GridUnitType.Star);
@@ -76,7 +131,7 @@ namespace comal.timesheets
                 DayViewColumn.Width = new GridLength(0, GridUnitType.Absolute);
                 TimeLineViewColumn.Width = new GridLength(1, GridUnitType.Star);
 
-                TimeLineView.ResourceViewSettings.VisibleResourceCount = Math.Max(1,Math.Min(8, _employeeids.Length));
+                TimeLineView.ResourceViewSettings.VisibleResourceCount = Math.Max(1,Math.Min(16, _employeeids.Length));
                 TimeLineView.TimelineViewSettings.AppointmentHeight =
                     (this.Height / TimeLineView.ResourceViewSettings.VisibleResourceCount) + 100;
                 
@@ -84,29 +139,37 @@ namespace comal.timesheets
                 foreach (var empid in _employeeids)
                 {
                     var empname = GlobalVariables.EmployeeShells.FirstOrDefault(x => x.ID == empid)?.Name ?? 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, //String.Join("", empname.Split(' ').Select(x=>x.Substring(0,1))),
+                            Name = empname,
                             Id = empid,
-                            Color = Color.Red,
+                            Color = Color.Transparent,
                             Image = ""
                         }
                     );
                 }
                 TimeLineView.ScheduleResources = resources;
                 TimeLineView.ShowResourceView = true;
-
-            }
-            
+                
 
 
+            }
             Refresh();
         }
         
         private void Refresh()
         {
             Title.Text = $"{DatePicker.Date:dd MMMM yyyy}";
+            
             DataModel.Load(
                 new Filter<Assignment>(x => x.Date).IsEqualTo(DatePicker.Date).And(x => x.EmployeeLink.ID).InList(_employeeids),
                 () =>
@@ -123,11 +186,6 @@ namespace comal.timesheets
 
        }
         
-        private void BackButton_OnClicked(object sender, EventArgs e)
-        {
-            Navigation.PopAsync();
-        }
-        
         private void SelectedDate_Tapped(object sender, EventArgs e)
         {
             DatePicker.Focus();
@@ -152,8 +210,9 @@ namespace comal.timesheets
         {
 
             var actions = new List<string>() { "Only Me" };
-            actions.AddRange(GlobalVariables.TeamEmployeeShells.Where(x=>x.ID == App.Data.Employee.ID).Select(x=>x.TeamName).Distinct());
-            
+            //actions.AddRange(GlobalVariables.TeamEmployeeShells.Where(x=>x.ID == App.Data.Employee.ID).Select(x=>x.TeamName).Distinct());
+            actions.AddRange(GlobalVariables.TeamEmployeeShells.Select(x=>x.TeamName).Distinct());
+
             var result = await MaterialDialog.Instance.SelectActionAsync(title: "Select a Team", 
                 actions: actions);
 
@@ -161,16 +220,19 @@ namespace comal.timesheets
             {
                 _view = AssignmentView.Day;
                 _employeeids = new Guid[] { App.Data.Employee.ID };
+                _teamname = App.Data.Employee.Name;
             }
             else if (result > 0)
             {
                 _view = AssignmentView.TimeLine;
                 _employeeids = GlobalVariables.TeamEmployeeShells.Where(x => String.Equals(x.TeamName, actions[result]))
                     .Select(x => x.ID).Distinct().ToArray();
+                _teamname = actions[result];
             }
 
             _settings.Employees = _employeeids;
             _settings.View = _view;
+            _settings.TeamName = _teamname;
             new LocalConfiguration<AssignmentModuleSettings>().Save(_settings);
             
             Dispatcher.BeginInvokeOnMainThread(()=>
@@ -179,6 +241,39 @@ namespace comal.timesheets
             });
         }
         
+        private void Lookups_OnItemTapped(object sender, ItemTappedEventArgs e)
+        {
+            if (e.Item is AssignmentLookupItem lookup)
+            {
+                if (lookup.Selected)
+                    lookup.Selected = false;
+                else
+                {
+                    IList<AssignmentLookupItem> lookups = _lookuptype == AssignmentLookupType.Tasks
+                        ? _kanbans.Items.ToArray<AssignmentLookupItem>()
+                        : _jobs.Items.ToArray<AssignmentLookupItem>();
+                    {
+                        foreach (var other in lookups.Where(x => x.Selected).ToArray())
+                            other.Selected = false;
+                    }
+                    lookup.Selected = true;
+                }
+            }
+        }
+
+        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<AssignmentModuleSettings>().Save(_settings);  
+            RefreshLookups();
+        }
+        
         private async void Schedule_OnCellTapped(object sender, CellTappedEventArgs e)
         {
             if (e.Appointment is AssignmentListDataModelItem item)
@@ -192,47 +287,93 @@ namespace comal.timesheets
         {
             if (e.Appointment == null)
             {
+
                 if (InABox.Core.Security.CanEdit<Assignment>())
                 {
-                    var assignment = new Assignment()
-                    {
-                        Date = e.Datetime.Date,
-                        Start = new TimeSpan(e.Datetime.TimeOfDay.Hours,0,0),
-                        Finish = e.Datetime.TimeOfDay.Add(new TimeSpan(1, 0, 0)),
-                        Duration = new TimeSpan(1, 0, 0),
-                        Title = "New Assignment"
-                    };
-                    assignment.EmployeeLink.ID = (e.Resource is ScheduleResource sr)
-                        ? (Guid)sr.Id
-                        : App.Data.Employee.ID;
-                    
-                    var editor = new AssignmentEdit(assignment);
-                    Navigation.PushAsync(editor);
+                    CreateAssignment(
+                        e.Datetime,
+                        e.Resource as ScheduleResource
+                    );
                 }
             }
-            else if (InABox.Core.Security.CanDelete<Assignment>())
-            {
-                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)
+            else if (InABox.Core.Security.CanDelete<Assignment>() 
+                     && e.Appointment is AssignmentListDataModelItem assignment)
+            {
+                await DeleteAssignment(assignment.Id);
+            }
+        }
+
+        private void CreateAssignment(DateTime date, ScheduleResource resource)
+        {
+            
+            var assignment = new Assignment()
+            {
+                Date = date.Date,
+                Start = new TimeSpan(date.TimeOfDay.Hours, 0, 0),
+                Finish = date.TimeOfDay.Add(new TimeSpan(1, 0, 0)),
+                Duration = new TimeSpan(1, 0, 0),
+                Title = "New Assignment",
+            };
+            
+            assignment.EmployeeLink.ID = (resource is ScheduleResource sr)
+                ? (Guid)sr.Id
+                : App.Data.Employee.ID;
+            
+            var job = (_lookuptype == AssignmentLookupType.ActiveJobs) || (_lookuptype == AssignmentLookupType.UnbookedJobs)
+                ? _jobs.Items.FirstOrDefault(x => x.Selected)
+                : null;
+            if (job != null)
+            {
+                assignment.JobLink.ID = job.Id;
+                assignment.JobLink.JobNumber = job.Number;
+                assignment.JobLink.Name = job.Name;
+                assignment.Description = job.Description;
+                assignment.Title = job.Name;
+                job.Selected = false;
+            }
+            
+            var task = _lookuptype == AssignmentLookupType.Tasks
+                ? _kanbans.Items.FirstOrDefault(x => x.Selected)
+                : null;  
+            if (task != null)
+            {
+                assignment.Task.ID = task.Id;
+                assignment.Task.Number = int.Parse(task.Number);
+                assignment.Task.Title = task.Name;
+                assignment.Title = task.Name;
+                assignment.Description = task.Description;
+                task.Selected = false;
+            }            
+            
+            var editor = new AssignmentEdit(assignment);
+            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()
                 {
-                    using(await MaterialDialog.Instance.LoadingDialogAsync(message: "Deleting Assignment"))
-                    {
-                        var assignment = new Assignment() { ID = (e.Appointment as AssignmentListDataModelItem).Id };
-                        new Client<Assignment>().Delete(assignment, "Deleted on Mobile Device");
-                    }
-                    Refresh();
+                    ButtonFontFamily = Material.FontFamily.Body2
+                }
+            );
+            if (confirm == true)
+            {
+                using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Deleting Assignment"))
+                {
+                    var assignment = new Assignment() { ID = id };
+                    new Client<Assignment>().Delete(assignment, "Deleted on Mobile Device");
                 }
+
+                Refresh();
             }
         }
-        
+
     }
 }

+ 0 - 25
prs.mobile/comal.timesheets/Assignments/AssignmentListDataModel.cs

@@ -1,25 +0,0 @@
-using System;
-using Comal.Classes;
-using InABox.Core;
-using Xamarin.Forms;
-
-namespace comal.timesheets
-{
-    public class AssignmentListDataModel : ListDataModel<Assignment, AssignmentListDataModelItem>
-    {
-        public override Columns<Assignment> Columns => new Columns<Assignment>(x => x.ID)
-            .Add(x=>x.Number)
-            .Add(x=>x.Title)
-            .Add(x=>x.Description)
-            .Add(x=>x.Date)
-            .Add(x=>x.Start)
-            .Add(x=>x.Finish)
-            .Add(x=>x.ActivityLink.Color)
-            .Add(x=>x.EmployeeLink.ID)
-            .Add(x=>x.JobLink.ID)
-            .Add(x=>x.JobLink.JobNumber)
-            .Add(x=>x.Completed);
-
-    }
-    
-}

+ 2 - 0
prs.mobile/comal.timesheets/Assignments/AssignmentModuleSettings.cs

@@ -8,5 +8,7 @@ namespace comal.timesheets
         public DateTime Date { get; set; }
         public AssignmentView View { get; set; }
         public Guid[] Employees { get; set; }
+        public String TeamName { get; set; }
+        public AssignmentLookupType LookupType { get; set; }
     }
 }

+ 168 - 0
prs.mobile/comal.timesheets/Assignments/AssignmentEditDataModel.cs → prs.mobile/comal.timesheets/Assignments/DataModels/AssignmentEditDataModel.cs

@@ -82,6 +82,9 @@ namespace comal.timesheets
             .Add(c => c.ActivityLink.Description)
             .Add(c => c.EmployeeLink.ID)
             .Add(c => c.ActivityLink.Color)
+            .Add(c => c.Task.ID)
+            .Add(c => c.Task.Number)
+            .Add(c => c.Task.Title)
             .Add(c => c.Completed);
 
         public override void BeforeLoad(MultiQuery query, Guid id)
@@ -149,4 +152,169 @@ namespace comal.timesheets
         }
 
     }
+    
+    public class AssignmentEditDataModelItem : SingleDataModelItem<Assignment>
+    {
+        
+        public Guid ID => GetValue(x => x.ID);
+        
+        public Guid EmployeeID 
+        {
+            get => GetValue(c => c.EmployeeLink.ID);
+            set => UpdateValue(c => c.EmployeeLink.ID, value);
+        }  
+
+        public int Number
+        {
+            get => GetValue(c => c.Number);
+            set => UpdateValue(c=>c.Number,value);
+        }
+        
+        public String Subject
+        {
+            get => GetValue(c => c.Title);
+            set => UpdateValue(c=>c.Title,value);
+        }
+
+        public String Description
+        {
+            get => GetValue(c => c.Description);
+            set => UpdateValue(c => c.Description, value);
+        }
+        
+        public DateTime Date 
+        {
+            get => GetValue(c => c.Date);
+            set => UpdateValue(c => c.Date, value);
+        }
+
+        public TimeSpan Start
+        {
+            get => GetValue(c => c.Start);
+            set => UpdateValue(c => c.Start, value);
+        }
+
+        public TimeSpan Duration
+        {
+            get => GetValue(c => c.Duration);
+            set => UpdateValue(c => c.Duration, value);
+        }
+        
+        public TimeSpan Finish 
+        {
+            get => GetValue(c => c.Finish);
+            set => UpdateValue(c => c.Finish, value);
+        }
+        
+        public Guid JobID 
+        {
+            get => GetValue(c => c.JobLink.ID);
+            set => UpdateValue(c => c.JobLink.ID, value);
+        }        
+        
+        public String JobNumber 
+        {
+            get => GetValue(c => c.JobLink.JobNumber);
+            set
+            {
+                UpdateValue(c => c.JobLink.JobNumber, value, false);
+                DoPropertyChanged(nameof(JobDisplay));
+            }
+        }           
+        
+        public String JobName 
+        {
+            get => GetValue(c => c.JobLink.Name);
+            set
+            {
+                UpdateValue(c => c.JobLink.Name, value, false);
+                DoPropertyChanged(nameof(JobDisplay));
+            }
+        } 
+        
+        public String JobDisplay => JobID != Guid.Empty
+            ? String.Format("{0}: {1}", JobNumber, JobName )
+            : "(No Job Selected)";
+        
+        public Guid TaskID 
+        {
+            get => GetValue(c => c.Task.ID);
+            set => UpdateValue(c => c.Task.ID, value);
+        }        
+        
+        public int TaskNumber 
+        {
+            get => GetValue(c => c.Task.Number);
+            set
+            {
+                UpdateValue(c => c.Task.Number, value, false);
+                DoPropertyChanged(nameof(TaskDisplay));
+            }
+        }           
+        
+        public String TaskName 
+        {
+            get => GetValue(c => c.Task.Title);
+            set
+            {
+                UpdateValue(c => c.Task.Title, value, false);
+                DoPropertyChanged(nameof(TaskDisplay));
+            }
+        }    
+        
+        public String TaskDisplay => TaskID != Guid.Empty
+            ? String.Format("{0}: {1}", TaskNumber, TaskName )
+            : "(No Task Selected)";
+        
+        public Guid ActivityID 
+        {
+            get => GetValue(c => c.ActivityLink.ID);
+            set => UpdateValue(c => c.ActivityLink.ID, value);
+        }        
+        
+        public String ActivityCode 
+        {
+            get => GetValue(c => c.ActivityLink.Code);
+            set
+            {
+                UpdateValue(c => c.ActivityLink.Code, value, false);
+                DoPropertyChanged(nameof(ActivityDisplay));
+            }
+        }           
+        
+        public String ActivityDescription
+        {
+            get => GetValue(c => c.ActivityLink.Description);
+            set
+            {
+                UpdateValue(c => c.ActivityLink.Description, value, false);
+                DoPropertyChanged(nameof(ActivityDisplay));
+            }
+        }
+        
+        public String ActivityColor
+        {
+            get => GetValue(c => c.ActivityLink.Color);
+            set
+            {
+                UpdateValue(c => c.ActivityLink.Color, value, false);
+                DoPropertyChanged(nameof(ActivityColor));
+            }
+        }
+
+        public String ActivityDisplay => ActivityID != Guid.Empty
+            ? String.Format("{0}: {1}", ActivityCode, ActivityDescription)
+            : "(No Activity Selected)";
+
+        public DateTime Completed
+        {
+            get => GetValue(c => c.Completed);
+            set
+            {
+                UpdateValue(c => c.Completed, value);
+                DoPropertyChanged(nameof(Completed));
+            }
+        }
+        
+    }
 }

+ 34 - 1
prs.mobile/comal.timesheets/Assignments/AssignmentListDataModelItem.cs → prs.mobile/comal.timesheets/Assignments/DataModels/AssignmentListDataModel.cs

@@ -1,11 +1,38 @@
 using System;
+using System.Collections.Generic;
 using System.Collections.ObjectModel;
+using System.Linq;
 using Comal.Classes;
 using InABox.Core;
 using Xamarin.Forms;
 
 namespace comal.timesheets
 {
+
+
+    public class AssignmentListDataModel : ListDataModel<Assignment, AssignmentListDataModelItem>
+    {
+        public override Columns<Assignment> Columns => new Columns<Assignment>(x => x.ID)
+            .Add(x=>x.Number)
+            .Add(x=>x.Title)
+            .Add(x=>x.Description)
+            .Add(x=>x.Date)
+            .Add(x=>x.Start)
+            .Add(x=>x.Finish)
+            .Add(x=>x.ActivityLink.Color)
+            .Add(x=>x.EmployeeLink.ID)
+            .Add(x=>x.JobLink.ID)
+            .Add(x=>x.JobLink.JobNumber)
+            .Add(x=>x.JobLink.Name)
+            .Add(x=>x.Task.ID)
+            .Add(x=>x.Task.Number)
+            .Add(x=>x.Task.Title)
+            .Add(x=>x.Completed);
+        
+        
+        
+    }
+    
     public class AssignmentListDataModelItem : CoreDataModelItem
     {
         
@@ -17,7 +44,12 @@ namespace comal.timesheets
         
         public Guid JobID => Row.Get<Assignment, Guid>(c => c.JobLink.ID);
         public string JobNumber => Row.Get<Assignment, String>(c => c.JobLink.JobNumber);
-
+        public string JobName => Row.Get<Assignment, String>(c => c.JobLink.Name);
+        
+        public Guid TaskID => Row.Get<Assignment, Guid>(c => c.Task.ID);
+        public int TaskNumber => Row.Get<Assignment, int>(c => c.Task.Number);
+        public string TaskName => Row.Get<Assignment, String>(c => c.Task.Title);
+        
         public String Subject => string.Format("{0}{1} {2}",
             Row.Get<Assignment, int>(c => c.Number), 
             Row.Get<Assignment,Guid>(c=>c.JobLink.ID) != Guid.Empty
@@ -52,4 +84,5 @@ namespace comal.timesheets
         public ObservableCollection<object> ResourceIds => new ObservableCollection<object>() { Row.Get<Assignment, Guid>(c => c.EmployeeLink.ID) };
 
     }
+
 }

+ 23 - 0
prs.mobile/comal.timesheets/Assignments/DataModels/Lookups/AssignmentJobDataModel.cs

@@ -0,0 +1,23 @@
+using System;
+using System.Drawing;
+using Comal.Classes;
+using InABox.Core;
+
+namespace comal.timesheets
+{
+    public class AssignmentJobDataModel : AssignmentLookupDataModel<Job, AssignmentJobItem>
+    {
+        public override Columns<Job> Columns => new Columns<Job>(x => x.ID)
+            .Add(x => x.JobNumber)
+            .Add(x => x.Name)
+            .Add(x => x.Notes);
+    }
+    
+    public class AssignmentJobItem : AssignmentLookupItem
+    {
+        public override Guid Id => Row.Get<Job, Guid>(c => c.ID);
+        public override String Number => Row.Get<Job, String>(c => c.JobNumber);
+        public override String Name => Row.Get<Job, String>(c => c.Name);
+        public override String Description => String.Join("\n",Row.Get<Job, String[]>(c => c.Notes));
+    }
+}

+ 26 - 0
prs.mobile/comal.timesheets/Assignments/DataModels/Lookups/AssignmentKanbanDataModel.cs

@@ -0,0 +1,26 @@
+using System;
+using System.Drawing;
+using Comal.Classes;
+using InABox.Core;
+
+namespace comal.timesheets
+{
+
+    
+    public class AssignmentKanbanDataModel : AssignmentLookupDataModel<Kanban, AssignmentKanbanItem>
+    {
+        public override Columns<Kanban> Columns => new Columns<Kanban>(x => x.ID)
+            .Add(x => x.Number)
+            .Add(x => x.Title)
+            .Add(x=>x.Description);
+    }
+    
+    public class AssignmentKanbanItem : AssignmentLookupItem
+    {
+        public override Guid Id => Row.Get<Kanban, Guid>(c => c.ID);
+        public override String Number => Row.Get<Kanban, int>(c => c.Number).ToString();
+        public override String Name => Row.Get<Kanban, String>(c => c.Title);
+        public override String Description => CoreUtils.StripHTML(Row.Get<Kanban, String>(c => c.Description));
+    }
+    
+}

+ 45 - 0
prs.mobile/comal.timesheets/Assignments/DataModels/Lookups/AssignmentLookupDataModel.cs

@@ -0,0 +1,45 @@
+using System;
+using System.Collections;
+using System.Drawing;
+using InABox.Core;
+using Xamarin.Essentials;
+
+namespace comal.timesheets
+{
+
+    public interface IAssignmentLookupDataModel
+    {
+        IEnumerable Items { get; }
+    }
+    
+    public abstract class AssignmentLookupDataModel<TEntity, TShell> : ListDataModel<TEntity, TShell>, IAssignmentLookupDataModel
+        where TEntity : Entity, IRemotable, IPersistent, new()
+        where TShell : AssignmentLookupItem, new()
+    {
+        IEnumerable IAssignmentLookupDataModel.Items => Items;
+
+        public void Clear()
+        {
+            foreach (var item in Items)
+                item.Selected = false;
+        }
+
+        public void Select(Guid id)
+        {
+            foreach (var item in Items)
+                item.Selected = item.Id == id;
+        }
+        
+    }
+    
+    public abstract class AssignmentLookupItem : CoreDataModelItem
+    {
+        public abstract Guid Id { get; }
+        public abstract String Number { get; }
+        public abstract String Name { get; }
+        public abstract String Description { get; }
+        
+        public bool Selected { get; set; }
+        public Color Colour => Selected ? Color.LightPink : Color.White;
+    }
+}

+ 6 - 4
prs.mobile/comal.timesheets/Data Models/ListDataModel.cs

@@ -5,6 +5,8 @@ using InABox.Core;
 
 namespace comal.timesheets
 {
+    
+    
     public abstract class ListDataModel<TEntity, TItem> : CoreDataModel<TEntity>, IListDataModel<TEntity, TItem>
         where TEntity : Entity, IRemotable, IPersistent, new() 
         where TItem : CoreDataModelItem, new()
@@ -13,7 +15,7 @@ namespace comal.timesheets
         
         private IEnumerable<TItem> _allitems;
         
-        private IList<TItem> _items = new List<TItem>();
+        protected IList<TItem> _items = new List<TItem>();
         public IList<TItem> Items
         {
             get => _items;
@@ -52,7 +54,7 @@ namespace comal.timesheets
             query.Query(
                 (q) =>
                 {
-                    _allitems = new List<TItem>(q.Get<TEntity>().Rows.Select(row => CreateItem(row)));
+                    _allitems = new List<TItem>(q.Get<TEntity>().Rows.Select(row => CreateItem<TItem>(row)));
                     
                     Search(null);
                     AfterLoad(q, filter);
@@ -61,9 +63,9 @@ namespace comal.timesheets
                 });
         }
 
-        private TItem CreateItem(CoreRow row)
+        protected T CreateItem<T>(CoreRow row) where T : CoreDataModelItem, new()
         {
-            var result = new TItem() { Row = row, Parent = this };
+            var result = new T() { Row = row, Parent = this };
             result.PropertyChanged += (sender, args) => DoPropertyChanged(result, args);
             return result;
         }

+ 5 - 4
prs.mobile/comal.timesheets/comal.timesheets.projitems

@@ -139,8 +139,6 @@
       <DependentUpon>AssignmentEdit.xaml</DependentUpon>
       <SubType>Code</SubType>
     </Compile>
-    <Compile Include="$(MSBuildThisFileDirectory)Assignments\AssignmentEditDataModel.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)Assignments\AssignmentEditDataModelItem.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Assignments\AssignmentForms.xaml.cs">
       <DependentUpon>AssignmentForms.xaml</DependentUpon>
     </Compile>
@@ -148,8 +146,6 @@
       <DependentUpon>AssignmentList.xaml</DependentUpon>
       <SubType>Code</SubType>
     </Compile>
-    <Compile Include="$(MSBuildThisFileDirectory)Assignments\AssignmentListDataModel.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)Assignments\AssignmentListDataModelItem.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Assignments\AssignmentMap.xaml.cs">
       <DependentUpon>AssignmentMap2.xaml</DependentUpon>
     </Compile>
@@ -157,6 +153,11 @@
     <Compile Include="$(MSBuildThisFileDirectory)Assignments\AssignmentSummary.xaml.cs">
       <DependentUpon>AssignmentSummary.xaml</DependentUpon>
     </Compile>
+    <Compile Include="$(MSBuildThisFileDirectory)Assignments\DataModels\AssignmentEditDataModel.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)Assignments\DataModels\AssignmentListDataModel.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)Assignments\DataModels\Lookups\AssignmentJobDataModel.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)Assignments\DataModels\Lookups\AssignmentKanbanDataModel.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)Assignments\DataModels\Lookups\AssignmentLookupDataModel.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Assignments\IAssignmentPage.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)DigitalForms\CustomUserControls\DigitalFormsHeader.xaml.cs">
       <DependentUpon>DigitalFormsHeader.xaml</DependentUpon>