diff --git a/.idea/.idea.GazpromApp/.idea/avalonia.xml b/.idea/.idea.GazpromApp/.idea/avalonia.xml index 19730a9..c574bf2 100644 --- a/.idea/.idea.GazpromApp/.idea/avalonia.xml +++ b/.idea/.idea.GazpromApp/.idea/avalonia.xml @@ -5,6 +5,7 @@ + diff --git a/GazpromApp.csproj b/GazpromApp.csproj index 7118db3..f7408a1 100644 --- a/GazpromApp.csproj +++ b/GazpromApp.csproj @@ -14,6 +14,7 @@ + diff --git a/Messages/EditPointMessage.cs b/Messages/EditPointMessage.cs index 3098dc8..85e0314 100644 --- a/Messages/EditPointMessage.cs +++ b/Messages/EditPointMessage.cs @@ -3,4 +3,7 @@ using GazpromApp.ViewModels; namespace GazpromApp.Messages; -public class EditPointMessage : AsyncRequestMessage; \ No newline at end of file +public class EditPointMessage(PointViewModel pointViewModel) : AsyncRequestMessage +{ + public PointViewModel Point { get; } = pointViewModel; +} \ No newline at end of file diff --git a/Messages/ViewImageMessage.cs b/Messages/ViewImageMessage.cs new file mode 100644 index 0000000..8b31140 --- /dev/null +++ b/Messages/ViewImageMessage.cs @@ -0,0 +1,9 @@ +using CommunityToolkit.Mvvm.Messaging.Messages; +using GazpromApp.ViewModels; + +namespace GazpromApp.Messages; + +public class ViewImageMessage(ImageViewModel imageViewModel) : AsyncRequestMessage +{ + public ImageViewModel Image { get; } = imageViewModel; +} \ No newline at end of file diff --git a/ViewModels/Basic/ImageViewModel.cs b/ViewModels/Basic/ImageViewModel.cs index 3b38795..a3816c0 100644 --- a/ViewModels/Basic/ImageViewModel.cs +++ b/ViewModels/Basic/ImageViewModel.cs @@ -1,6 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices.JavaScript; +using System.Collections.Generic; +using System.IO; using Avalonia.Media.Imaging; using CommunityToolkit.Mvvm.ComponentModel; using GazpromApp.Models; @@ -24,13 +23,23 @@ public partial class ImageViewModel : ViewModelBase Bytes = image.Bytes; Equipment = image.Equipment; Points = image.Points; + FileName = image.Bytes is { Length: > 0 } ? new Bitmap(new MemoryStream(image.Bytes)) : null; + } + + public ImageViewModel() + { + Bytes = null; + Equipment = null; + Points = null; } public Image GetImage() { + MemoryStream ms = new MemoryStream(); + FileName?.Save(ms); return new Image() { - Bytes = Bytes ?? [], + Bytes = ms.ToArray(), Equipment = Equipment ?? [], Points = Points ?? [], }; diff --git a/ViewModels/EditPointDialogViewModel.cs b/ViewModels/EditPointDialogViewModel.cs index 5015529..e4fa17f 100644 --- a/ViewModels/EditPointDialogViewModel.cs +++ b/ViewModels/EditPointDialogViewModel.cs @@ -1,6 +1,120 @@ -namespace GazpromApp.ViewModels; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Avalonia.Controls; +using Avalonia.Media.Imaging; +using Avalonia.Platform.Storage; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using CommunityToolkit.Mvvm.Messaging; +using GazpromApp.Messages; +using GazpromApp.Models; +using Image = GazpromApp.Models.Image; + +namespace GazpromApp.ViewModels; public partial class EditPointDialogViewModel : ViewModelBase { + public ObservableCollection Images { get; set; } + [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(CompleteEditCommand))] + private string? _name; + + [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(CompleteEditCommand))] + private string? _description; + + [ObservableProperty] + private bool _isNameEditing; + + [ObservableProperty] + private bool _isDescriptionEditing; + + [RelayCommand] + private void EditName() + { + IsNameEditing = !IsNameEditing; + IsDescriptionEditing = false; + } + + [RelayCommand] + private void EditDescription() + { + IsDescriptionEditing = !IsDescriptionEditing; + IsNameEditing = false; + } + + [RelayCommand] + private async Task AddImage(Window w) + { + IReadOnlyList files = await w.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions() + { + AllowMultiple = true, + Title = "Выберите одну или несколько картинок", + FileTypeFilter = [FilePickerFileTypes.ImageAll], + }); + foreach (var file in files) + Images.Add(new ImageViewModel(new Image()) { FileName = new Bitmap(file.Path.AbsolutePath) }); + + IsImagesEmpty = Images.Count == 0; + } + + [RelayCommand] + private void DeleteImage(ImageViewModel image) + { + Images.Remove(image); + IsImagesEmpty = Images.Count == 0; + } + + [RelayCommand] + private async Task ViewImage(ImageViewModel image) + { + _ = await WeakReferenceMessenger.Default.Send(new ViewImageMessage(image)); + } + + private bool CanCompleteEdit() => !string.IsNullOrWhiteSpace(Name); + + [RelayCommand(CanExecute = nameof(CanCompleteEdit))] + private void CompleteEdit() + { + Point point = new Point() + { + Name = Name, + Description = Description, + Images = Images.Select(e => e.GetImage()).ToList() + }; + WeakReferenceMessenger.Default.Send(new EditPointDone(new PointViewModel(point))); + } + + [RelayCommand] + private static void CancelEdit(Window w) + { + w.Close(); + } + + [ObservableProperty] + private bool _isImagesEmpty; + + public EditPointDialogViewModel() + { + Name = ""; + Description = ""; + Images = []; + IsImagesEmpty = true; + } + + public EditPointDialogViewModel(PointViewModel point) + { + Name = point.Name; + Description = point.Description; + Images = new ObservableCollection((point.Images ?? []).Select(e => new ImageViewModel(e))); + foreach (ImageViewModel imageViewModel in Images) + { + Debug.WriteLine(imageViewModel.FileName); + } + IsImagesEmpty = Images.Count == 0; + } } \ No newline at end of file diff --git a/ViewModels/MainWindowViewModel.cs b/ViewModels/MainWindowViewModel.cs index 6285428..036e579 100644 --- a/ViewModels/MainWindowViewModel.cs +++ b/ViewModels/MainWindowViewModel.cs @@ -1,40 +1,45 @@ using CommunityToolkit.Mvvm.ComponentModel; - -namespace GazpromApp.ViewModels; using GazpromApp.Messages; using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Messaging; using System.Collections.ObjectModel; -using System.Diagnostics; using System.Threading.Tasks; +using GazpromApp.Models; + +namespace GazpromApp.ViewModels; public partial class MainWindowViewModel : ViewModelBase { - public ObservableCollection Points { get; } = new ObservableCollection(); + public ObservableCollection Points { get; } = []; [RelayCommand] private async Task AddPoint() { var point = await WeakReferenceMessenger.Default.Send(new NewPointMessage()); + if (point != null) Points.Add(point); - IsLineVisible = true; + + IsLineVisible = Points.Count > 0; + } + + [RelayCommand] + private async Task EditPoint(PointViewModel point) + { + PointViewModel p = await WeakReferenceMessenger.Default.Send(new EditPointMessage(point)) ?? point; + Points[Points.IndexOf(point)] = p; } [RelayCommand] private void RemovePoint(PointViewModel point) { Points.Remove(point); - if (Points.Count == 0) - IsLineVisible = false; + + IsLineVisible = Points.Count > 0; } - - [RelayCommand] - private void EditPoint(PointViewModel point) - { - Debug.WriteLine(point.Name); - } - + + // Visual properties + [ObservableProperty] private bool _isLineVisible; } \ No newline at end of file diff --git a/ViewModels/NewPointDialogViewModel.cs b/ViewModels/NewPointDialogViewModel.cs index 97de157..dce3b81 100644 --- a/ViewModels/NewPointDialogViewModel.cs +++ b/ViewModels/NewPointDialogViewModel.cs @@ -1,10 +1,7 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Diagnostics; using System.Linq; using System.Threading.Tasks; -using Avalonia; using Avalonia.Controls; using Avalonia.Media.Imaging; using Avalonia.Platform.Storage; @@ -20,20 +17,14 @@ namespace GazpromApp.ViewModels; public partial class NewPointDialogViewModel : ViewModelBase { [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(EnterPointCommand))] private string? _name; [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(EnterPointCommand))] private string? _description; - public ObservableCollection Images { get; } = new ObservableCollection(); - - [RelayCommand] - public void DeleteImage(ImageViewModel image) - { - Images.Remove(image); - if (Images.Count == 0) - IsImagesEmpty = true; - } + public ObservableCollection Images { get; } = []; [RelayCommand] private async Task AddImage(Window w) @@ -46,16 +37,21 @@ public partial class NewPointDialogViewModel : ViewModelBase }); foreach (var file in files) Images.Add(new ImageViewModel(new Image()) { FileName = new Bitmap(file.Path.AbsolutePath) }); - IsImagesEmpty = false; + + IsImagesEmpty = Images.Count == 0; } - [ObservableProperty] - private bool _isImagesEmpty = true; + [RelayCommand] + private void DeleteImage(ImageViewModel image) + { + Images.Remove(image); + IsImagesEmpty = Images.Count == 0; + } - private bool CanExecuteEnterPoint() => !string.IsNullOrEmpty(Name) || !string.IsNullOrEmpty(Description); + private bool CanEnterPoint() => !string.IsNullOrEmpty(Name); - [RelayCommand(CanExecute = nameof(CanExecuteEnterPoint))] - public void EnterPoint() + [RelayCommand (CanExecute = nameof(CanEnterPoint))] + private void EnterPoint() { Point point = new Point() { @@ -65,4 +61,15 @@ public partial class NewPointDialogViewModel : ViewModelBase }; WeakReferenceMessenger.Default.Send(new NewPointDone(new PointViewModel(point))); } + + [RelayCommand] + private static void CancelEnterPoint(Window w) + { + w.Close(); + } + + // Visual properties + + [ObservableProperty] + private bool _isImagesEmpty = true; } \ No newline at end of file diff --git a/Views/EditPointDialog.axaml b/Views/EditPointDialog.axaml index 6a66c72..6ca598f 100644 --- a/Views/EditPointDialog.axaml +++ b/Views/EditPointDialog.axaml @@ -2,8 +2,104 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" + xmlns:vm="using:GazpromApp.ViewModels" + x:Name="Window" + mc:Ignorable="d" d:DesignWidth="1000" d:DesignHeight="600" + Width="1000" Height="600" x:Class="GazpromApp.Views.EditPointDialog" - Title="EditPointDialog"> - Welcome to Avalonia! + x:DataType="vm:EditPointDialogViewModel" + Title="Редактирование/просмотр объекта" + Icon="/Assets/ic_fluent_edit_24_filled (Custom).png" + WindowStartupLocation="CenterOwner"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + - - + + -