|
@@ -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;
|
|
|
+ }
|
|
|
+}
|