297 lines
9.6 KiB
C#
297 lines
9.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.IO;
|
|
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<PointViewModel> Points { get; set; }
|
|
|
|
[ObservableProperty]
|
|
private object? _selectedItem;
|
|
|
|
[ObservableProperty]
|
|
private ViewModelBase? _selectedItemViewModel;
|
|
|
|
[RelayCommand]
|
|
private async Task AddPoint()
|
|
{
|
|
IsLoading = true;
|
|
|
|
var point = new PointViewModel(new Point {Name = "Новый объект", Description = "Описание объекта"});
|
|
|
|
_context.Point.Add(point.GetPoint());
|
|
await _context.SaveChangesAsync();
|
|
|
|
Points.Add(point);
|
|
|
|
IsLoading = false;
|
|
}
|
|
|
|
[RelayCommand]
|
|
private async Task ImportPoint(Window w)
|
|
{
|
|
Directory.CreateDirectory(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "GazpromApp"));
|
|
var files = await w.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
|
{
|
|
AllowMultiple = true,
|
|
SuggestedStartLocation =
|
|
await w.StorageProvider.TryGetFolderFromPathAsync(
|
|
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "GazpromApp"))
|
|
});
|
|
|
|
if (files.Count < 1) return;
|
|
|
|
IsLoading = true;
|
|
|
|
foreach (var file in files)
|
|
{
|
|
var url = file.Path.AbsolutePath;
|
|
var decoded = HttpUtility.UrlDecode(url);
|
|
var point = DataSerialization.LoadPoint(decoded);
|
|
point?.SetPropertyParents();
|
|
point?.SetEquipmentParents();
|
|
|
|
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)
|
|
{
|
|
Directory.CreateDirectory(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "GazpromApp"));
|
|
var folder = await w.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
|
|
{
|
|
AllowMultiple = false,
|
|
SuggestedStartLocation =
|
|
await w.StorageProvider.TryGetFolderFromPathAsync(
|
|
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "GazpromApp"))
|
|
});
|
|
if (folder.Count != 1) return;
|
|
foreach (var point in Points)
|
|
DataSerialization.SavePoint(point.GetPoint(), Path.Combine(HttpUtility.UrlDecode(folder[0].Path.AbsolutePath), point.Name + ".json") );
|
|
}
|
|
|
|
[ObservableProperty]
|
|
[NotifyCanExecuteChangedFor(nameof(SyncDbCommand))]
|
|
private bool _canSync = false;
|
|
|
|
private bool CanSyncDb() => CanSync;
|
|
|
|
[RelayCommand(CanExecute = nameof(CanSyncDb))]
|
|
private async Task SyncDb()
|
|
{
|
|
IsLoading = true;
|
|
|
|
foreach (var point in _pointsToUpdate)
|
|
{
|
|
_context.Update(point.GetPoint());
|
|
|
|
var index = Points.IndexOf(point);
|
|
if (index != -1)
|
|
Points[index] = point;
|
|
}
|
|
await _context.SaveChangesAsync();
|
|
|
|
foreach (var point in _pointsToDelete)
|
|
{
|
|
var pointInDb = await _context.Point.FindAsync(point.GetPoint().Id);
|
|
if (pointInDb == null) continue;
|
|
|
|
_context.Remove(pointInDb);
|
|
|
|
Points.Remove(point);
|
|
}
|
|
await _context.SaveChangesAsync();
|
|
|
|
_pointsToUpdate.Clear();
|
|
_pointsToDelete.Clear();
|
|
|
|
|
|
IsLoading = false;
|
|
CanSync = false;
|
|
}
|
|
|
|
// Visual and other properties
|
|
[ObservableProperty] private bool _isLoading = true;
|
|
|
|
private readonly AppDbContext _context;
|
|
|
|
private async Task LoadChildrenForProperties(List<Property> properties, HashSet<Guid> loadedIds)
|
|
{
|
|
if (properties.Count == 0)
|
|
return;
|
|
|
|
var parentIds = properties.Select(p => p.Id)
|
|
.Where(id => !loadedIds.Contains(id))
|
|
.ToList();
|
|
|
|
if (parentIds.Count == 0)
|
|
return;
|
|
|
|
parentIds.ForEach(id => loadedIds.Add(id));
|
|
|
|
var children = await _context.Property
|
|
.Where(p => p.ParentPropertyId.HasValue && parentIds.Contains(p.ParentPropertyId.Value))
|
|
.OrderBy(p => p.CreationDate)
|
|
.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.Clear();
|
|
parent.Properties.AddRange(childrenLookup[parent.Id]);
|
|
}
|
|
|
|
await LoadChildrenForProperties(children, loadedIds);
|
|
}
|
|
}
|
|
|
|
private async Task LoadChildrenForEquipments(List<Equipment> equipments, HashSet<Guid> loadedIds)
|
|
{
|
|
if (equipments.Count == 0)
|
|
return;
|
|
|
|
var parentIds = equipments.Select(e => e.Id)
|
|
.Where(id => !loadedIds.Contains(id))
|
|
.ToList();
|
|
|
|
if (parentIds.Count == 0)
|
|
return;
|
|
|
|
parentIds.ForEach(id => loadedIds.Add(id));
|
|
|
|
var children = await _context.Equipment
|
|
.Where(e => e.ParentEquipmentId.HasValue && parentIds.Contains(e.ParentEquipmentId.Value))
|
|
.OrderBy(e => e.CreationDate)
|
|
.ToListAsync();
|
|
|
|
if (children.Count != 0)
|
|
{
|
|
var childrenLookup = children.ToLookup(child => child.ParentEquipmentId);
|
|
|
|
foreach (var parent in equipments.Where(parent => childrenLookup.Contains(parent.Id)))
|
|
{
|
|
parent.Equipments.Clear();
|
|
parent.Equipments.AddRange(childrenLookup[parent.Id]);
|
|
}
|
|
|
|
await LoadChildrenForEquipments(children, loadedIds);
|
|
}
|
|
}
|
|
|
|
|
|
private async Task LoadDataAsync()
|
|
{
|
|
IsLoading = true;
|
|
|
|
// ReSharper disable once EntityFramework.NPlusOne.IncompleteDataQuery
|
|
var pointsFromDb = await _context.Point
|
|
.OrderBy(p => p.CreationDate)
|
|
.Include(p => p.Images
|
|
.OrderBy(i => i.CreationDate))
|
|
.Include(p => p.Equipment
|
|
.OrderBy(e => e.CreationDate))
|
|
.ThenInclude(e => e.Properties
|
|
.OrderBy(p => p.CreationDate))
|
|
.Include(p => p.Equipment)
|
|
.ThenInclude(e => e.Images
|
|
.OrderBy(i => i.CreationDate))
|
|
.Include(p => p.Equipment)
|
|
.ThenInclude(e => e.Inspections
|
|
.OrderBy(i => i.CreationDate))
|
|
.Include(p => p.Properties
|
|
.OrderBy(p => p.CreationDate))
|
|
.ToListAsync();
|
|
|
|
var topLevelProperties = pointsFromDb.SelectMany(p => p.Properties)
|
|
.Concat(pointsFromDb.SelectMany(p => p.Equipment).SelectMany(e => e.Properties))
|
|
.ToList();
|
|
|
|
var topLevelEquipments = pointsFromDb.SelectMany(p => p.Equipment)
|
|
.ToList();
|
|
|
|
if (topLevelProperties.Count != 0)
|
|
await LoadChildrenForProperties(topLevelProperties, []);
|
|
|
|
if (topLevelEquipments.Count != 0)
|
|
await LoadChildrenForEquipments(topLevelEquipments, []);
|
|
|
|
Points.Clear();
|
|
foreach (var point in pointsFromDb)
|
|
Points.Add(new PointViewModel(point));
|
|
|
|
IsLoading = false;
|
|
}
|
|
|
|
private readonly ObservableCollection<PointViewModel> _pointsToUpdate = [];
|
|
private readonly ObservableCollection<PointViewModel> _pointsToDelete = [];
|
|
|
|
private void EditPoint(object sender, EditPointMessage msg)
|
|
{
|
|
if (!_pointsToUpdate.Contains(msg.Point))
|
|
_pointsToUpdate.Add(msg.Point);
|
|
CanSync = true;
|
|
}
|
|
|
|
private void RemovePoint(object sender, RemovePointMessage msg)
|
|
{
|
|
if (!_pointsToDelete.Contains(msg.Point))
|
|
_pointsToDelete.Add(msg.Point);
|
|
Points.Remove(msg.Point);
|
|
CanSync = true;
|
|
}
|
|
|
|
private void HandleSelectionChanged(object sender, SelectionChangedMessage msg)
|
|
{
|
|
SelectedItemViewModel = msg.ViewModel switch
|
|
{
|
|
PointViewModel pointViewModel => new EditPointViewModel(pointViewModel),
|
|
EquipmentViewModel equipmentViewModel => new EditEquipmentViewModel(equipmentViewModel),
|
|
_ => msg.ViewModel
|
|
};
|
|
}
|
|
|
|
public MainWindowViewModel(AppDbContext context)
|
|
{
|
|
Points = [];
|
|
_context = context;
|
|
_ = LoadDataAsync();
|
|
|
|
WeakReferenceMessenger.Default.Register<EditPointMessage>(this, EditPoint);
|
|
WeakReferenceMessenger.Default.Register<RemovePointMessage>(this, RemovePoint);
|
|
WeakReferenceMessenger.Default.Register<SelectionChangedMessage>(this, HandleSelectionChanged);
|
|
}
|
|
|
|
public MainWindowViewModel()
|
|
{
|
|
Points = [new PointViewModel(new Point()) { Name = "Новый объект", Description = "Описание объекта" }];
|
|
_context = new AppDbContext();
|
|
IsLoading = false;
|
|
}
|
|
} |