Browse Source

avalonia: started work on Equipment details

Kenric Nugteren 4 months ago
parent
commit
31bdb4290b

+ 69 - 13
PRS.Avalonia/PRS.Avalonia/Modules/EquipmentModule/EquipmentDetails/EquipmentDetailsView.axaml

@@ -3,20 +3,76 @@
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
              xmlns:modules="clr-namespace:PRS.Avalonia.Modules"
+			 xmlns:prs="using:PRS.Avalonia"
+			 xmlns:components="using:InABox.Avalonia.Components"
+			 xmlns:prsComponents="using:PRS.Avalonia.Components"
+			 xmlns:mapsui="using:Mapsui.UI.Avalonia"
              mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
              x:Class="PRS.Avalonia.Modules.EquipmentDetailsView"
              x:DataType="modules:EquipmentDetailsViewModel">
-    <Grid>
-        <Grid.RowDefinitions>
-            <RowDefinition Height="*" />
-            <RowDefinition Height="Auto" />
-        </Grid.RowDefinitions>
-        
-        <Button Classes="Alert,Standard"
-            Grid.Row="1"
-            Padding="20"
-            Content="Unlock Device"
-            IsVisible="{Binding CanDisplayUnlockCode}"
-            Command="{Binding DisplayUnlockCodeCommand}"/>
-    </Grid>
+	<TabControl Classes="Standard"
+				TabStripPlacement="Bottom"
+				SelectedIndex="1">
+		<TabItem Header="Tasks">
+			<Grid>
+				<Grid.RowDefinitions>
+					<RowDefinition Height="*"/>
+					<RowDefinition Height="Auto"/>
+				</Grid.RowDefinitions>
+				<ScrollViewer>
+					<ItemsControl ItemsSource="{Binding OpenKanbans}">
+						<ItemsControl.ItemTemplate>
+							<DataTemplate DataType="prs:EquipmentKanbanShell">
+								<Button Classes="Standard"
+										Background="Orange"
+										Command="{Binding $parent[modules:EquipmentDetailsView].((modules:EquipmentDetailsViewModel)DataContext).EditOpenTaskCommand}"
+										CommandParameter="{Binding .}"
+										Content="{Binding Title}"/>
+							</DataTemplate>
+						</ItemsControl.ItemTemplate>
+					</ItemsControl>
+				</ScrollViewer>
+				<Button Classes="Standard" Grid.Row="1"
+						Content="{Binding Kanbans.ItemCount,StringFormat='All Tasks ({0})'}"
+						Command="{Binding ViewTasksCommand}"/>
+			</Grid>
+		</TabItem>
+		<TabItem Header="Notes">
+			<TextBox Watermark="Notes"
+					 IsReadOnly="True"
+					 Focusable="False"
+					 VerticalContentAlignment="Top"
+					 Text="{Binding Shell.Notes}"/>
+		</TabItem>
+		<TabItem Header="Specs">
+			<Grid>
+				<Label VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
+					   VerticalContentAlignment="Center" HorizontalContentAlignment="Center"
+					   Content="No Image Available"
+					   Foreground="Gray" IsVisible="{Binding !HasDocument}"/>
+			</Grid>
+		</TabItem>
+		<TabItem Header="Map">
+			<Grid>
+				<mapsui:MapControl x:Name="Map" IsVisible="{Binding HasMap}"/>
+				<Label VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
+					   VerticalContentAlignment="Center" HorizontalContentAlignment="Center"
+					   Content="No Map Available"
+					   Foreground="Gray" IsVisible="{Binding !HasMap}"/>
+			</Grid>
+		</TabItem>
+		<TabItem Header="Docs">
+			<prsComponents:DocumentList Repository="{Binding Documents}"/>
+		</TabItem>
+		<TabItem Header="Key" IsVisible="{Binding CanDisplayUnlockCode}">
+			<Button Classes="Standard"
+					Width="100" Height="100" CornerRadius="50"
+					Padding="20"
+					VerticalContentAlignment="Center"
+					HorizontalContentAlignment="Center"
+					Command="{Binding DisplayUnlockCodeCommand}">
+				<Image Source="{SvgImage /Images/key.svg}"/>
+			</Button>
+		</TabItem>
+	</TabControl>
 </UserControl>

+ 89 - 0
PRS.Avalonia/PRS.Avalonia/Modules/EquipmentModule/EquipmentDetails/EquipmentDetailsView.axaml.cs

@@ -1,13 +1,102 @@
 using Avalonia;
 using Avalonia.Controls;
 using Avalonia.Markup.Xaml;
+using DynamicData.Binding;
+using Mapsui.Layers;
+using Mapsui.Projections;
+using Mapsui.Styles;
+using Mapsui.Widgets.InfoWidgets;
+using System;
+using System.Linq;
 
 namespace PRS.Avalonia.Modules;
 
 public partial class EquipmentDetailsView : UserControl
 {
+    private readonly MemoryLayer _layer;
+
     public EquipmentDetailsView()
     {
         InitializeComponent();
+
+        _layer = new MemoryLayer
+        {
+            Name = "Layer",
+            Style = new SymbolStyle
+            {
+                SymbolScale = 1.0,
+                SymbolType = SymbolType.Ellipse,
+                Fill = new Mapsui.Styles.Brush(Color.LightGreen),
+            }
+        };
+
+        Map.Map.Layers.Add(Mapsui.Tiling.OpenStreetMap.CreateTileLayer());
+        Map.Map.Layers.Add(_layer);
+
+        var logging = Map.Map.Widgets.OfType<LoggingWidget>().FirstOrDefault();
+        if(logging is not null)
+        {
+            logging.Enabled = false;
+        }
+        var performance = Map.Map.Widgets.OfType<PerformanceWidget>().FirstOrDefault();
+        if(performance is not null)
+        {
+            performance.Enabled = false;
+        }
+    }
+
+    protected override void OnDataContextChanged(EventArgs e)
+    {
+        base.OnDataContextChanged(e);
+
+        var model = DataContext as EquipmentDetailsViewModel;
+        if (model is null) return;
+
+        model.WhenPropertyChanged(x => x.Shell).Subscribe(x =>
+        {
+            if (x.Value is null)
+            {
+                model.HasMap = false;
+                return;
+            }
+
+            var coordinates = new Point(x.Value.Longitude, x.Value.Latitude);
+            if (coordinates.Equals(default))
+            {
+                model.HasMap = false;
+            }
+            else
+            {
+                model.HasMap = true;
+
+                var point = SphericalMercator.FromLonLat(coordinates.X, coordinates.Y);
+
+                Map.Map.Navigator.CenterOn(point.x, point.y);
+                Map.Map.Navigator.ZoomToLevel(15);
+
+                _layer.Features = [
+                    new PointFeature(point.x, point.y)
+                    {
+                        ["Label"] = x.Value.Code,
+                        Styles =
+                        {
+                            new LabelStyle
+                            {
+                                Text = x.Value.Code,
+                                Offset = new(20, 0),
+                                HorizontalAlignment = LabelStyle.HorizontalAlignmentEnum.Left,
+                                ForeColor = new(Color.DarkBlue),
+                                Font = new Font
+                                {
+                                    Bold = true,
+                                    Size = 20
+                                },
+                                BackColor = new(Color.Transparent)
+                            }
+                        }
+                    }
+                    ];
+            }
+        });
     }
 }

+ 66 - 1
PRS.Avalonia/PRS.Avalonia/Modules/EquipmentModule/EquipmentDetails/EquipmentDetailsViewModel.cs

@@ -5,6 +5,7 @@ using Comal.Classes;
 using Comal.Classes.SecurityDescriptors;
 using CommunityToolkit.Mvvm.ComponentModel;
 using CommunityToolkit.Mvvm.Input;
+using InABox.Avalonia;
 using InABox.Avalonia.Dialogs;
 using InABox.Clients;
 using InABox.Core;
@@ -15,12 +16,76 @@ public partial class EquipmentDetailsViewModel : ModuleViewModel
 {
     public override string Title => "Equipment Details";
     
-    
     [ObservableProperty] 
     private EquipmentShell? _shell;
 
+    [ObservableProperty]
+    private EquipmentDocumentModel _documents;
+
+    [ObservableProperty]
+    private DocumentModel _specificationSheet;
+
+    [ObservableProperty]
+    private EquipmentKanbanModel _kanbans;
+
+    [ObservableProperty]
+    private CoreObservableCollection<EquipmentKanbanShell> _openKanbans;
+
+    [ObservableProperty]
+    private bool _hasDocument;
+
+    [ObservableProperty]
+    private bool _hasMap;
+
     public bool CanDisplayUnlockCode => Security.IsAllowed<UnlockMobileEquipmentDigitalKeys>();
 
+    public EquipmentDetailsViewModel()
+    {
+        Documents = new EquipmentDocumentModel(DataAccess,
+            () => new Filter<EquipmentDocument>(x => x.EntityLink.ID).IsEqualTo(_shell?.ID ?? CoreUtils.FullGuid),
+            () => DefaultCacheFileName<EquipmentDocumentShell>(_shell?.ID));
+        SpecificationSheet = new DocumentModel(DataAccess,
+            () => new Filter<Document>(x => x.ID).IsEqualTo(_shell?.SpecificationSheetID ?? CoreUtils.FullGuid),
+            () => DefaultCacheFileName<DocumentShell>(_shell?.SpecificationSheetID ?? CoreUtils.FullGuid));
+        Kanbans = new EquipmentKanbanModel(DataAccess,
+            () => new Filter<Kanban>(x => x.Equipment.ID).IsEqualTo(_shell?.ID ?? CoreUtils.FullGuid),
+            () => DefaultCacheFileName<EquipmentKanbanShell>(_shell?.ID, "Equipment"));
+        Kanbans.Changed += (sender, args) => OpenKanbans.ReplaceRange(Kanbans.Where(x => x.Completed.IsEmpty()));
+        Kanbans.ItemAdded += (o, args) =>
+        {
+            args.Item.EquipmentID = Shell?.ID ?? Guid.Empty;
+            args.Item.EquipmentDescription = Shell?.Description ?? "";
+        };
+        OpenKanbans = new CoreObservableCollection<EquipmentKanbanShell>();
+    }
+
+    protected override async Task<TimeSpan> OnRefresh()
+    {
+        await Task.WhenAll(
+            Documents.RefreshAsync(true),
+            SpecificationSheet.RefreshAsync(true),
+            Kanbans.RefreshAsync(true));
+        return TimeSpan.Zero;
+    }
+
+    [RelayCommand]
+    private void ViewTasks()
+    {
+        if (Shell is null) return;
+
+        Navigation.Navigate<MyTasksViewModel>(model =>
+        {
+            model.Model = Kanbans;
+            model.TasksTitle = $"Tasks: {Shell.Description}";
+        });
+    }
+
+    [RelayCommand]
+    private async Task EditOpenTask(EquipmentKanbanShell task)
+    {
+        await MessageDialog.ShowMessage("Not implemented");
+    }
+
     [RelayCommand]
     private async Task DisplayUnlockCode()
     {

+ 2 - 1
PRS.Avalonia/PRS.Avalonia/Modules/EquipmentModule/EquipmentMaps/EquipmentMapsView.axaml.cs

@@ -5,6 +5,7 @@ using Mapsui;
 using Mapsui.Layers;
 using Mapsui.Projections;
 using Mapsui.Styles;
+using Mapsui.Widgets.InfoWidgets;
 using System.Collections.ObjectModel;
 using System.Collections.Specialized;
 using System.Linq;
@@ -117,7 +118,7 @@ public partial class EquipmentMapsView : UserControl
 
         _jobLayer = CreateJobLayer();
         _equipmentLayer = CreateEquipmentLayer();
-
+        
         Map.Map.Layers.Add(Mapsui.Tiling.OpenStreetMap.CreateTileLayer());
         Map.Map.Layers.Add(_jobLayer);
         Map.Map.Layers.Add(_equipmentLayer);

+ 11 - 2
PRS.Avalonia/PRS.Avalonia/Modules/MyTasks/MyTasksViewModel.cs

@@ -1,6 +1,15 @@
+using CommunityToolkit.Mvvm.ComponentModel;
+using InABox.Avalonia;
+
 namespace PRS.Avalonia.Modules;
 
-public class MyTasksViewModel : ModuleViewModel
+public partial class MyTasksViewModel : ModuleViewModel
 {
-    public override string Title => "My Tasks";
+    public override string Title => TasksTitle;
+
+    [ObservableProperty]
+    private string _tasksTitle = "My Tasks";
+
+    [ObservableProperty]
+    private ICoreRepository _model;
 }

+ 1 - 1
PRS.Avalonia/PRS.Avalonia/Repositories/EquipmentKanban/EquipmentKanbanModel.cs

@@ -7,7 +7,7 @@ namespace PRS.Avalonia;
 
 public class EquipmentKanbanModel : BaseKanbanModel<EquipmentKanbanModel, EquipmentKanbanShell>
 {
-    public EquipmentKanbanModel(IModelHost host, Func<Filter<Kanban>> filter) : base(host, filter)
+    public EquipmentKanbanModel(IModelHost host, Func<Filter<Kanban>> filter, Func<string>? filename = null) : base(host, filter, filename)
     {
     }
 }