Browse Source

avalonia: EmbeddedImage digital form fields are now editable

Kenric Nugteren 1 month ago
parent
commit
5fab98513f

+ 4 - 0
PRS.Avalonia/PRS.Avalonia/Components/FormsEditor/Fields/DFEmbeddedImageFieldControl.cs

@@ -44,6 +44,8 @@ class DFEmbeddedImageFieldControl : DFEmbeddedMediaFieldControl<DFLayoutEmbedded
             {
                 model.Data = _value.Data;
                 model.DeleteCommand = DeleteCommand;
+                model.CanEdit = Field.Properties.Editable;
+                model.SaveCommand = SaveCommand;
             });
         }
         else if(_value.ID != Guid.Empty)
@@ -57,6 +59,8 @@ class DFEmbeddedImageFieldControl : DFEmbeddedMediaFieldControl<DFLayoutEmbedded
                     {
                         model.Data = _value.Data;
                         model.DeleteCommand = DeleteCommand;
+                        model.CanEdit = Field.Properties.Editable;
+                        model.SaveCommand = SaveCommand;
                     });
                 });
         }

+ 7 - 0
PRS.Avalonia/PRS.Avalonia/Components/FormsEditor/Fields/DFEmbeddedMediaFieldControl.cs

@@ -131,6 +131,13 @@ abstract partial class DFEmbeddedMediaFieldControl<TField, TProperties, TValue>
         }
     }
 
+    [RelayCommand]
+    private void Save(byte[] data)
+    {
+        SetSerializedValue(new() { Data = data });
+        ChangeField();
+    }
+
     [RelayCommand]
     private async Task CameraClicked()
     {

+ 9 - 3
PRS.Avalonia/PRS.Avalonia/Components/ImageViewer/ImageViewerView.axaml

@@ -8,7 +8,13 @@
              mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
              x:Class="PRS.Avalonia.Components.ImageViewerView"
 			 x:DataType="prsComponents:ImageViewerViewModel">
-    <components:ZoomPanel>
-        <Image Name="Image" Source="{Binding Data,Converter={x:Static converters:ByteArrayToImageSourceConverter.Instance}}"/>
-    </components:ZoomPanel>
+    <Grid>
+        <components:ZoomPanel IsVisible="{Binding !IsEditing}">
+            <Image Name="Image" Source="{Binding Data,Converter={x:Static converters:ByteArrayToImageSourceConverter.Instance}}"/>
+        </components:ZoomPanel>
+        <components:ImageEditor Name="Editor"
+                                IsVisible="{Binding IsEditing}"
+                                Source="{Binding Data, Converter={x:Static converters:ByteArrayToImageSourceConverter.Instance}}"
+                                Changed="ImageEditor_Changed"/>
+    </Grid>
 </UserControl>

+ 26 - 0
PRS.Avalonia/PRS.Avalonia/Components/ImageViewer/ImageViewerView.axaml.cs

@@ -7,6 +7,8 @@ namespace PRS.Avalonia.Components;
 
 public partial class ImageViewerView : UserControl
 {
+    private ImageViewerViewModel? ViewModel;
+
     public ImageViewerView()
     {
         InitializeComponent();
@@ -20,4 +22,28 @@ public partial class ImageViewerView : UserControl
             }
         });
     }
+
+    protected override void OnDataContextChanged(EventArgs e)
+    {
+        base.OnDataContextChanged(e);
+
+        ViewModel = DataContext as ImageViewerViewModel;
+        if(ViewModel != null)
+        {
+            ViewModel.GetImage = GetImage;
+        }
+    }
+    
+    private byte[] GetImage()
+    {
+        return Editor.SaveImage();
+    }
+    
+    private void ImageEditor_Changed(object? sender, EventArgs e)
+    {
+        if(ViewModel != null)
+        {
+            ViewModel.ImageChanged = true;
+        }
+    }
 }

+ 42 - 0
PRS.Avalonia/PRS.Avalonia/Components/ImageViewer/ImageViewerViewModel.cs

@@ -1,5 +1,6 @@
 using CommunityToolkit.Mvvm.ComponentModel;
 using CommunityToolkit.Mvvm.Input;
+using DynamicData.Binding;
 using InABox.Avalonia;
 using InABox.Avalonia.Components;
 using PRS.Avalonia.Modules;
@@ -20,16 +21,57 @@ internal partial class ImageViewerViewModel : ModuleViewModel
     [ObservableProperty]
     private byte[] _data = null!;
 
+    [ObservableProperty]
+    private bool _canEdit = false;
+
+    [ObservableProperty]
+    private bool _isEditing;
+
+    [ObservableProperty]
+    private Func<byte[]>? _getImage;
+
+    [ObservableProperty]
+    private bool _imageChanged;
+
     [ObservableProperty]
     private IRelayCommand? _deleteCommand;
 
+    [ObservableProperty]
+    private IRelayCommand? _saveCommand;
+
     public ImageViewerViewModel()
     {
         _deleteButton = new AvaloniaMenuItem(Images.cross, Delete);
         _deleteButton.IsVisible = false;
+
+        var editButton = new AvaloniaMenuItem(Images.edit, Edit);
+        this.WhenValueChanged(x => x.CanEdit).Subscribe(x => editButton.IsVisible = ShowCanEdit());
+        this.WhenValueChanged(x => x.IsEditing).Subscribe(x => editButton.IsVisible = ShowCanEdit());
+
+        var saveButton = new AvaloniaMenuItem(Images.save, Save);
+        this.WhenValueChanged(x => x.IsEditing).Subscribe(x => saveButton.IsVisible = IsEditing && ImageChanged);
+        this.WhenValueChanged(x => x.ImageChanged).Subscribe(x => saveButton.IsVisible = IsEditing && ImageChanged);
+
+        PrimaryMenu.Items.Add(editButton);
+        PrimaryMenu.Items.Add(saveButton);
         PrimaryMenu.Items.Add(_deleteButton);
     }
 
+    private void Save()
+    {
+        Data = GetImage?.Invoke() ?? Data;
+        SaveCommand?.Execute(Data);
+        ImageChanged = false;
+        Navigation.Back();
+    }
+
+    private bool ShowCanEdit() => CanEdit && !IsEditing;
+
+    private void Edit()
+    {
+        IsEditing = true;
+    }
+
     partial void OnDeleteCommandChanged(IRelayCommand? value)
     {
         _deleteButton.IsVisible = value is not null;

+ 1 - 0
PRS.Avalonia/PRS.Avalonia/Images/Images.cs

@@ -43,6 +43,7 @@ public static class Images
     public static SvgImage? digitalform => LoadSVG("/Images/digitalform.svg");
     public static SvgImage? drawing => LoadSVG("/Images/drawing.svg");
     public static SvgImage? drill => LoadSVG("/Images/drill.svg");
+    public static SvgImage? edit => LoadSVG("/Images/edit.svg");
     public static SvgImage? factory => LoadSVG("/Images/factory.svg");
     public static SvgImage? holiday => LoadSVG("/Images/holiday.svg");
     public static SvgImage? key => LoadSVG("/Images/key.svg");

+ 1 - 0
PRS.Avalonia/PRS.Avalonia/Images/edit.svg

@@ -0,0 +1 @@
+<svg height="512" viewBox="0 0 32 32" width="512" xmlns="http://www.w3.org/2000/svg"><g id="Ikon"><rect fill="#eee" height="21" rx="2" width="21" x="3" y="8"/><path d="m7.1 24.419 7.098-1.815-4.815-4.815z" fill="#ffe082"/><path d="m28.4142 5.7071-2.1213-2.1213a2 2 0 0 0 -2.8284 0l-1.4145 1.4142 4.95 4.95 1.4142-1.4143a2 2 0 0 0 0-2.8286z" fill="#f44336"/><path d="m9.447 17.603-.064.186 4.815 4.815.199-.051 12.603-12.603-4.95-4.95z" fill="#f9a825"/></g><g id="Line"><path d="m29.1211 5-2.1211-2.1211a3.0022 3.0022 0 0 0 -4.2427 0l-4.1211 4.1211h-13.6362a3 3 0 0 0 -3 3v17a3 3 0 0 0 3 3h17a3 3 0 0 0 3-3v-13.6362l4.1211-4.1211a3.0031 3.0031 0 0 0 0-4.2427zm-19.3134 14.6275 2.4423 2.4425-3.6.9205zm4.4643 1.6362-3.5357-3.5357 11.3137-11.3139 3.5359 3.5359zm8.728 5.7363a1 1 0 0 1 -1 1h-17a1 1 0 0 1 -1-1v-17a1 1 0 0 1 1-1h11.6362l-7.8962 7.896a.9978.9978 0 0 0 -.2382.3813l-2.347 6.8155a1.0069 1.0069 0 0 0 1.1929 1.2944l7.2968-1.8657a1 1 0 0 0 .4595-.2617l7.896-7.896zm4.707-19.1714-.707.707-3.5356-3.5356.707-.707a1.0009 1.0009 0 0 1 1.4145 0l2.1211 2.1211a1.0018 1.0018 0 0 1 0 1.4145z"/></g></svg>

+ 4 - 0
PRS.Avalonia/PRS.Avalonia/PRS.Avalonia.csproj

@@ -18,6 +18,7 @@
         <None Remove="Images\arrow_white_right.svg" />
         <None Remove="Images\arrow_white_up.svg" />
         <None Remove="Images\badge.svg" />
+        <None Remove="Images\edit.svg" />
         <None Remove="Images\unlock.svg" />
         <AvaloniaResource Include="Images\arrow_white_down.svg">
           <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
@@ -119,6 +120,9 @@
             <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
         </AvaloniaResource>
         <None Remove="Images\factory.svg" />
+        <AvaloniaResource Include="Images\edit.svg">
+          <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+        </AvaloniaResource>
         <AvaloniaResource Include="Images\factory.svg">
             <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
         </AvaloniaResource>