| 
					
				 | 
			
			
				@@ -0,0 +1,221 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using Avalonia.Controls; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using Avalonia.Layout; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using Avalonia.Media; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using Avalonia.Threading; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using CommunityToolkit.Mvvm.Input; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using InABox.Avalonia; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using InABox.Core; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using PRS.Avalonia.Components; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.Collections.Generic; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.Linq; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.Text; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.Threading.Tasks; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+namespace PRS.Avalonia.DigitalForms; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+abstract partial class DFEmbeddedMediaFieldControl<TField, TProperties, TValue> : DigitalFormFieldControl<TField, TProperties, TValue, DFLayoutEmbeddedMediaValue> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    where TField : DFLayoutField<TProperties>, new() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    where TProperties : DFLayoutFieldProperties<TValue, DFLayoutEmbeddedMediaValue>, new() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private Button Button = null!; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private Image Image = null!; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private StackPanel StackPanel = null!; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private ColumnDefinition ButtonColumn = null!; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private bool _isEmpty = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    protected DFLayoutEmbeddedMediaValue _value = new(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    protected abstract bool DisableLibrary { get; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    protected abstract bool IsVideo { get; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    protected override Control Create() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        var grid = new Grid(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        grid.Height = 250; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        grid.AddColumn(GridUnitType.Star); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ButtonColumn = grid.AddColumn(GridUnitType.Auto); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        grid.AddRow(GridUnitType.Auto); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        grid.AddRow(GridUnitType.Auto); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        grid.AddRow(GridUnitType.Star); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        grid.AddRow(GridUnitType.Auto); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Button = new Button 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Padding = new(5), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Command = ImageClickedCommand 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Button.Classes.Add("Standard"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Image = new Image 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Button.Content = Image; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        var cameraButton = new Button 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Content = new Image 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Source = IsVideo ? Images.camcorder : Images.camera, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Width = 25, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Height = 25, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Command = CameraClickedCommand 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        cameraButton.Classes.Add("Standard"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (!DisableLibrary) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var libraryButton = new Button 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Content = new Image 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Source = IsVideo ? Images.videolibrary : Images.photolibrary, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Width = 25, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Height = 25, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Command = LibraryClickedCommand 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            libraryButton.Classes.Add("Standard"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            grid.AddChild(libraryButton, 1, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        StackPanel = new StackPanel { Orientation = Orientation.Vertical }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        grid.AddChild(Button, 0, 0, rowSpan: 4); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        grid.AddChild(cameraButton, 0, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        grid.AddChild(StackPanel, 3, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return grid; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    protected void AddButton(IImage? image, Action action) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        var button = new Button 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Content = new Image 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Source = image, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Width = 25, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Height = 25, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            CommandParameter = action, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Command = ButtonClickedCommand 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        button.Classes.Add("Standard"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        StackPanel.Children.Add(button); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [RelayCommand] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private void ButtonClicked(Action action) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        action(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    protected abstract Task<MobileDocument> CaptureMedia(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    protected abstract Task<MobileDocument> SelectMedia(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [RelayCommand] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private void ImageClicked() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(_value.Thumbnail is null || _value.Thumbnail.Length == 0) return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(_value.Data is not null && _value.Data.Length > 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Navigation.Navigate<ImageViewerViewModel>(model => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                model.Data = _value.Data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                model.DeleteCommand = DeleteCommand; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        else if(_value.ID != Guid.Empty) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            DigitalFormDocumentFactory.LoadDocument( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _value.ID, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                data => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    _value.Data = data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Navigation.Navigate<ImageViewerViewModel>(model => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        model.Data = _value.Data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        model.DeleteCommand = DeleteCommand; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [RelayCommand] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private void Delete() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (!_isEmpty) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            SetSerializedValue(new DFLayoutEmbeddedMediaValue()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ChangeField(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [RelayCommand] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private async Task CameraClicked() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        var document = await CaptureMedia(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(document.Data is not null && document.Data.Length > 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            SetSerializedValue(new() { Data = document.Data }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ChangeField(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    [RelayCommand] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private async Task LibraryClicked() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        var document = await SelectMedia(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(document.Data is not null && document.Data.Length > 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            SetSerializedValue(new() { Data = document.Data }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ChangeField(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public override void SetBackground(IBrush brush, bool defaultColour) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Button.Background = brush; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public override void SetSerializedValue(DFLayoutEmbeddedMediaValue value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        _value = value; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        _value.Thumbnail = (_value.Data is not null && _value.Data.Length > 0) ? CreateThumbnail(_value.Data) : null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        UpdateUI(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    protected void UpdateUI() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        var data = (!IsVideo && _value.Data is not null && _value.Data.Length > 0) ? _value.Data : _value.Thumbnail; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        var image = ImageUtils.ImageFromBytes(data, false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Image.Source = image; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        _isEmpty = image is null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public override DFLayoutEmbeddedMediaValue GetSerializedValue() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (_value.Data is not null && _value.Data.Length != 0 && _value.ID == Guid.Empty) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _value.ID = DigitalFormDocumentFactory.SaveDocument(_value.Data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return _value; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    protected abstract byte[] CreateThumbnail(byte[] data, int maxWidth = 256, int maxHeight = 256); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    protected override bool IsEmpty() => _isEmpty; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public override void SetEnabled(bool enabled) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ButtonColumn.Width = enabled ? GridLength.Auto : new(0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Button.IsEnabled = enabled; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |