Browse Source

avalonia: FormEditor now asks for confirmation when cancelling; Task "Add Form" now functional

Kenric Nugteren 1 tháng trước cách đây
mục cha
commit
e64b22df66

+ 5 - 0
PRS.Avalonia/PRS.Avalonia/Components/FormsEditor/DigitalFormViewer.axaml.cs

@@ -46,6 +46,8 @@ public partial class DigitalFormViewer : UserControl, IDFRenderer
 
     public bool ReadOnly { get; set; }
 
+    public bool IsChanged => _isChanged;
+
     private DFLoadStorage RetainedData { get; set; } = new();
 
     private bool _changing;
@@ -59,6 +61,8 @@ public partial class DigitalFormViewer : UserControl, IDFRenderer
 
     private static double RowMinHeight = 35;
 
+    public event Action<string>? FieldChanged;
+
     public DigitalFormViewer()
     {
         InitializeComponent();
@@ -145,6 +149,7 @@ public partial class DigitalFormViewer : UserControl, IDFRenderer
 
     private void DoChanged(string fieldName)
     {
+        FieldChanged?.Invoke(fieldName);
     }
 
     private void Initialise()

+ 2 - 1
PRS.Avalonia/PRS.Avalonia/Components/FormsEditor/DigitalFormsHostView.axaml

@@ -11,7 +11,8 @@
 			<ScrollViewer>
 				<forms:DigitalFormViewer Name="Viewer"
 										 Entity="{Binding Parent}"
-										 Form="{Binding Form}"/>
+										 Form="{Binding Form}"
+										 FieldChanged="FormViewer_FieldChanged"/>
 			</ScrollViewer>
 		</TabItem>
 		<TabItem Header="Documents"/>

+ 6 - 0
PRS.Avalonia/PRS.Avalonia/Components/FormsEditor/DigitalFormsHostView.axaml.cs

@@ -44,4 +44,10 @@ public partial class DigitalFormsHostView : UserControl
             }
         };
     }
+
+    private void FormViewer_FieldChanged(string fieldName)
+    {
+        if (DataContext is not IDigitalFormsHostViewModel model) return;
+        model.FieldChanged(fieldName);
+    }
 }

+ 69 - 20
PRS.Avalonia/PRS.Avalonia/Components/FormsEditor/DigitalFormsHostViewModel.cs

@@ -49,6 +49,8 @@ public interface IDigitalFormsHostViewModel : INotifyPropertyChanged
     Func<DFSaveStorage> SaveValues { set; }
 
     Func<List<string>?> Validate { set; }
+
+    void FieldChanged(string fieldName);
 }
 
 public partial class DigitalFormsHostViewModel<TModel, TShell, TParent, TParentLink, TForm> : ModuleViewModel, IDigitalFormsHostViewModel
@@ -118,6 +120,8 @@ public partial class DigitalFormsHostViewModel<TModel, TShell, TParent, TParentL
 
     DFLayout IDigitalFormsHostViewModel.Layout => Layout;
 
+    private bool _isChanged = false;
+
     public DigitalFormsHostViewModel()
     {
         PrimaryMenu.Add(new(Images.save, SaveForm));
@@ -125,6 +129,24 @@ public partial class DigitalFormsHostViewModel<TModel, TShell, TParent, TParentL
         ProgressVisible = true;
     }
 
+    public override bool OnBackButtonPressed()
+    {
+        return ConfirmChanges(_isChanged, result =>
+        {
+            switch (result)
+            {
+                case ConfirmChangesResult.Cancel:
+                    Navigation.Back();
+                    return;
+                case ConfirmChangesResult.Save:
+                    SaveForm(SaveOption.Save).Wait();
+                    break;
+                case ConfirmChangesResult.KeepEditing:
+                    return;
+            }
+        });
+    }
+
     private void BaseConfigure()
     {
         Model = DigitalFormModel.CreateModel(DataAccess, Parent.GetType().Name);
@@ -218,6 +240,7 @@ public partial class DigitalFormsHostViewModel<TModel, TShell, TParent, TParentL
 
         NewForm = Form.FormData.IsNullOrWhiteSpace();
         ReadOnly = Form.FormCompleted != DateTime.MinValue;
+        _isChanged = NewForm;
 
         TimeStarted = DateTime.Now;
 
@@ -225,26 +248,24 @@ public partial class DigitalFormsHostViewModel<TModel, TShell, TParent, TParentL
         return TimeSpan.Zero;
     }
 
-    private async Task<bool> SaveForm()
+    public void FieldChanged(string fieldName)
     {
-        string[] options;
-        if(DigitalForm.AppliesTo.Equals(nameof(Kanban)) || DigitalForm.AppliesTo.Equals(nameof(Job)))
-        {
-            options = ["Save Progress", "Complete Form", "Complete and Duplicate", "Delete Form"];
-        }
-        else
-        {
-            options = ["Save Progress", "Complete Form", "Delete Form"];
-        }
-        var chosenOption = await OptionDialog.Execute("Select Option", options);
-        if(chosenOption is null)
-        {
-            return true;
-        }
+        _isChanged = true;
+    }
 
-        var completeDuplicate = chosenOption == "Complete and Duplicate";
-        var complete = chosenOption == "Complete Form" || completeDuplicate;
-        var delete = chosenOption == "Delete Form";
+    private enum SaveOption
+    {
+        Save,
+        Complete,
+        CompleteDuplicate,
+        Delete
+    }
+
+    private async Task SaveForm(SaveOption chosenOption)
+    {
+        var completeDuplicate = chosenOption == SaveOption.CompleteDuplicate;
+        var complete = chosenOption == SaveOption.Complete || completeDuplicate;
+        var delete = chosenOption == SaveOption.Delete;
 
         if(complete)
         {
@@ -252,12 +273,13 @@ public partial class DigitalFormsHostViewModel<TModel, TShell, TParent, TParentL
             if(errors is not null)
             {
                 await MessageDialog.ShowMessage($"Could not save form:\n - {string.Join("\n - ", errors)}\nPlease address these issues and try again.");
-                return true;
+                return;
             }
         }
 
         ProgressVisible = true;
-        DigitalForm.SerializeFormData(Form, Variables, SaveValues());
+        var values = Dispatcher.UIThread.Invoke(SaveValues);
+        DigitalForm.SerializeFormData(Form, Variables, values);
 
         await Task.Run(() =>
         {
@@ -307,6 +329,33 @@ public partial class DigitalFormsHostViewModel<TModel, TShell, TParent, TParentL
             Navigation.Back();
             OnSaved?.Invoke();
         }
+    }
+
+    private async Task<bool> SaveForm()
+    {
+        string[] options;
+        if(DigitalForm.AppliesTo.Equals(nameof(Kanban)) || DigitalForm.AppliesTo.Equals(nameof(Job)))
+        {
+            options = ["Save Progress", "Complete Form", "Complete and Duplicate", "Delete Form"];
+        }
+        else
+        {
+            options = ["Save Progress", "Complete Form", "Delete Form"];
+        }
+        var chosenOption = await OptionDialog.Execute("Select Option", options);
+        if(chosenOption is null)
+        {
+            return true;
+        }
+
+        await SaveForm(chosenOption switch
+        {
+            "Save Progress" => SaveOption.Save,
+            "Complete Form" => SaveOption.Complete,
+            "Complete and Duplicate" => SaveOption.CompleteDuplicate,
+            "Delete Form" => SaveOption.Delete,
+            _ => SaveOption.Save
+        });
 
         return true;
     }

+ 13 - 1
PRS.Avalonia/PRS.Avalonia/Components/FormsEditor/Fields/DFStringFieldControl.cs

@@ -27,6 +27,8 @@ partial class DFStringFieldControl : DigitalFormFieldControl<DFLayoutStringField
     private Button? Btn;
     private TextBlock? TextBlock;
 
+    private bool _initialised;
+
     [NotNull]
     private string? Text
     {
@@ -55,6 +57,12 @@ partial class DFStringFieldControl : DigitalFormFieldControl<DFLayoutStringField
         return Text;
     }
 
+    protected override void OnLoaded(RoutedEventArgs e)
+    {
+        base.OnLoaded(e);
+        _initialised = true;
+    }
+
     protected override Control Create()
     {
         if (Field.Properties.PopupEditor)
@@ -82,7 +90,11 @@ partial class DFStringFieldControl : DigitalFormFieldControl<DFLayoutStringField
             TextBox.TextAlignment = TextAlignment.Left;
             TextBox.VerticalContentAlignment = VerticalAlignment.Center;
             TextBox.VerticalAlignment = VerticalAlignment.Stretch;
-            TextBox.TextChanged += (sender, e) => ChangeField();
+            TextBox.TextChanged += (sender, e) =>
+            {
+                if (!_initialised) return;
+                ChangeField();
+            };
 
             return TextBox;
         }

+ 15 - 1
PRS.Avalonia/PRS.Avalonia/Modules/MyTasks/TaskEditViewModel.cs

@@ -39,6 +39,9 @@ internal partial class TaskEditViewModel : ModuleViewModel
     [ObservableProperty]
     private KanbanFormModel _forms;
 
+    [ObservableProperty]
+    private DigitalFormModel _digitalForms;
+
     [ObservableProperty]
     private Func<Task>? _takePhotoAction;
 
@@ -88,6 +91,8 @@ internal partial class TaskEditViewModel : ModuleViewModel
         Forms = new KanbanFormModel(DataAccess,
             () => new Filter<KanbanForm>(x => x.Parent.ID).IsEqualTo(Shell?.ID ?? CoreUtils.FullGuid),
             () => DefaultCacheFileName<KanbanFormShell>(Shell?.ID));
+
+        DigitalForms = Repositories.DigitalForms();
     }
 
     protected override async Task<TimeSpan> OnRefresh()
@@ -129,7 +134,16 @@ internal partial class TaskEditViewModel : ModuleViewModel
 
     private async Task<bool> NewForm()
     {
-        await MessageDialog.ShowMessage("Unimplemented");
+        var form = await FormsList.SelectForm<KanbanForm, Kanban, KanbanLink>(DigitalForms);
+        if (form is null) return true;
+
+        var kanbanForm = Forms.CreateItem();
+        kanbanForm.FormID = form.ID;
+        kanbanForm.FormCode = form.Code;
+        kanbanForm.FormDescription = form.Description;
+        kanbanForm.FormDescriptionExpression = form.DescriptionExpression;
+
+        DigitalFormsHostViewModel<KanbanFormModel, KanbanFormShell, Kanban, KanbanLink, KanbanForm>.EditForm(Forms, kanbanForm, Shell.Entity);
         return true;
     }
 

+ 22 - 15
PRS.Avalonia/PRS.Avalonia/ViewModelBase.cs

@@ -128,15 +128,15 @@ public abstract partial class ViewModelBase : ObservableValidator, IViewModelBas
         return true;
     }
 
-    private enum ConfirmChangesResult
+    public enum ConfirmChangesResult
     {
         Cancel,
         Save,
         KeepEditing
     }
-    protected static bool ConfirmChanges(IShell item)
+    protected static bool ConfirmChanges(bool changed, Action<ConfirmChangesResult> done)
     {
-        if (item.IsChanged())
+        if (changed)
         {
             var result = ConfirmChangesResult.Cancel;
             new MessageDialogViewModel()
@@ -159,18 +159,7 @@ public abstract partial class ViewModelBase : ObservableValidator, IViewModelBas
                 .Display()
                 .ContinueWith(task =>
                 {
-                    switch (result)
-                    {
-                        case ConfirmChangesResult.Cancel:
-                            item.Cancel();
-                            break;
-                        case ConfirmChangesResult.Save:
-                            item.Save("Saved on Mobile Device");
-                            break;
-                        case ConfirmChangesResult.KeepEditing:
-                            return;
-                    }
-                    Navigation.Back();
+                    done(result);
                 });
             return false;
         }
@@ -179,6 +168,24 @@ public abstract partial class ViewModelBase : ObservableValidator, IViewModelBas
             return true;
         }
     }
+    protected static bool ConfirmChanges(IShell item)
+    {
+        return ConfirmChanges(item.IsChanged(), result =>
+        {
+            switch (result)
+            {
+                case ConfirmChangesResult.Cancel:
+                    item.Cancel();
+                    break;
+                case ConfirmChangesResult.Save:
+                    item.Save("Saved on Mobile Device");
+                    break;
+                case ConfirmChangesResult.KeepEditing:
+                    return;
+            }
+            Navigation.Back();
+        });
+    }
     
     public async Task Activate()
     {