using System; using System.Collections.Generic; using System.IO; using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; using System.Web; using Avalonia.Controls; using Avalonia.Platform.Storage; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Messaging; using GazpromApp.Messages; using GazpromApp.Models; using GazpromApp.Utils; using Microsoft.EntityFrameworkCore; namespace GazpromApp.ViewModels; public partial class MainWindowViewModel : ViewModelBase { public ObservableCollection Points { get; set; } [RelayCommand] private async Task AddPoint() { var point = await WeakReferenceMessenger.Default.Send(new NewPointMessage()); if (point == null) return; IsLoading = true; _context.Point.Add(point.GetPoint()); await _context.SaveChangesAsync(); Points.Add(point); IsLoading = false; } [RelayCommand] private async Task EditPoint(PointViewModel point) { var p = await WeakReferenceMessenger.Default.Send(new EditPointMessage(point)); if (p == null) return; IsLoading = true; _context.Update(p.GetPoint()); await _context.SaveChangesAsync(); var index = Points.IndexOf(point); if (index != -1) Points[index] = p; IsLoading = false; } [RelayCommand] private async Task RemovePoint(PointViewModel point) { IsLoading = true; var pointInDb = await _context.Point.FindAsync(point.GetPoint().Id); if (pointInDb == null) return; _context.Remove(pointInDb); await _context.SaveChangesAsync(); Points.Remove(point); IsLoading = false; } [RelayCommand] private async Task ImportPoint(Window w) { var files = await w.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions { AllowMultiple = true, SuggestedStartLocation = await w.StorageProvider.TryGetFolderFromPathAsync( Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)) }); IsLoading = true; foreach (var file in files) { var url = file.Path.AbsolutePath; var decoded = HttpUtility.HtmlDecode(url); var point = DataSerialization.LoadPoint(decoded); point?.SetPropertyParents(); if (point == null) continue; _context.Point.Add(point); await _context.SaveChangesAsync(); _context.Update(point); await _context.SaveChangesAsync(); Points.Add(new PointViewModel(point)); } IsLoading = false; } [RelayCommand] private async Task ExportPoint(Window w) { var folder = await w.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions { AllowMultiple = false, SuggestedStartLocation = await w.StorageProvider.TryGetFolderFromPathAsync( Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)) }); foreach (var point in Points) { DataSerialization.SavePoint(point.GetPoint(), Path.Combine(HttpUtility.HtmlDecode(folder[0].Path.AbsolutePath), point.Name + ".json") ); } } // Visual and other properties [ObservableProperty] private bool _isLoading = true; private readonly AppDbContext _context; private async Task LoadChildrenForProperties(List properties) { if (properties.Count == 0) return; var parentIds = properties.Select(p => p.Id).ToList(); var children = await _context.Property .Where(p => p.ParentPropertyId.HasValue && parentIds.Contains(p.ParentPropertyId.Value)) .AsNoTracking() .ToListAsync(); if (children.Count != 0) { var childrenLookup = children.ToLookup(child => child.ParentPropertyId); foreach (var parent in properties.Where(parent => childrenLookup.Contains(parent.Id))) parent.Properties.AddRange(childrenLookup[parent.Id]); // ReSharper disable once TailRecursiveCall await LoadChildrenForProperties(children); } } private async Task LoadDataAsync() { IsLoading = true; var pointsFromDb = await _context.Point .Include(p => p.Images) .Include(p => p.Equipment) .ThenInclude(e => e.Properties) .Include(p => p.Equipment) .ThenInclude(e => e.Images) .Include(p => p.Equipment) .ThenInclude(e => e.Inspections) .Include(p => p.Properties) .AsNoTracking() .ToListAsync(); var topLevelProperties = pointsFromDb.SelectMany(p => p.Properties) .Concat(pointsFromDb.SelectMany(p => p.Equipment).SelectMany(e => e.Properties)) .ToList(); if (topLevelProperties.Count != 0) await LoadChildrenForProperties(topLevelProperties); Points.Clear(); foreach (var point in pointsFromDb) Points.Add(new PointViewModel(point)); IsLoading = false; } public MainWindowViewModel(AppDbContext context) { Points = []; _context = context; _ = LoadDataAsync(); } public MainWindowViewModel() { Points = [new PointViewModel(new Point()) { Name = "Name test", Description = "Description test" }]; _context = new AppDbContext(); IsLoading = false; } }