Presence_Desktop/Presence.Desktop/ViewModels/GroupViewModel.cs
2024-12-23 14:26:41 +03:00

343 lines
18 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Avalonia.Controls.ApplicationLifetimes;
using domain.Models;
using domain.UseCase;
using Presence.Desktop.Views;
using ReactiveUI;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using System.Windows.Input;
using Avalonia;
using System.IO;
using CsvHelper;
using CsvHelper.Configuration;
using data.RemoteData;
namespace Presence.Desktop.ViewModels
{
public class GroupViewModel : ViewModelBase, IRoutableViewModel
{
// Объявляем поле для доступа к удаленной базе данных. Используется для доступа к данным о группах и пользователях.
private readonly RemoteDatabaseContext _remoteDatabaseContext;
// URL-сегмент для маршрутизации. Используется ReactiveUI для навигации.
public string? UrlPathSegment { get; }
// Экземпляр экрана, используемый для навигации. Предоставляет возможность перехода к другим представлениям.
public IScreen HostScreen { get; }
// Объекты для работы с бизнес-логикой. Обеспечивают взаимодействие с бизнес-слоем приложения.
private readonly UseCaseGeneratePresence _presenceUseCase; // Для генерации присутствия (возможно, не используется в этом ViewModel)
private readonly GroupUseCase _groupUseCase; // Для работы с группами (добавление, удаление, обновление)
// Временный источник данных для групп. Используется до загрузки данных из базы данных.
private List<GroupPresenter> groupPresentersDataSource = new List<GroupPresenter>();
// Коллекция групп, отображаемых в интерфейсе. Используется ReactiveUI для обновления интерфейса при изменении данных.
private ObservableCollection<GroupPresenter> _groups;
public ObservableCollection<GroupPresenter> Groups => _groups;
// Выбранная группа в интерфейсе. Изменения этого свойства вызывают обновление списка пользователей.
private GroupPresenter? _selectedGroupItem;
public GroupPresenter? SelectedGroupItem
{
get => _selectedGroupItem;
set => this.RaiseAndSetIfChanged(ref _selectedGroupItem, value);
}
// Коллекция пользователей, связанных с выбранной группой. Обновляется при изменении выбранной группы.
public ObservableCollection<UserPresenter> Users { get => _users; }
private ObservableCollection<UserPresenter> _users;
// Список доступных опций сортировки пользователей.
public List<string> SortOptions { get; } = new List<string> { "По фамилии", "По убыванию" };
// Выбранная опция сортировки пользователей. Изменение этого свойства вызывает сортировку списка пользователей.
private string _selectedSortOption;
public string SelectedSortOption
{
get => _selectedSortOption;
set => this.RaiseAndSetIfChanged(ref _selectedSortOption, value);
}
// Свойства, указывающие, доступны ли команды удаления и редактирования. Зависят от количества выбранных пользователей.
public bool CanDelete => SelectedUsers?.Count > 0;
public bool CanEdit => SelectedUsers?.Count == 1;
// Коллекция выбранных пользователей. Изменения в этой коллекции обновляют состояние команд.
public ObservableCollection<UserPresenter> SelectedUsers { get; set; } = new ObservableCollection<UserPresenter>();
// Реактивные команды для обработки действий пользователя. Обеспечивают реактивное поведение интерфейса.
public ReactiveCommand<Unit, Unit> OnDeleteUserClicks { get; }
public ReactiveCommand<Unit, Unit> EditUserCommand { get; }
public ReactiveCommand<Unit, Unit> NextPageCommand { get; }
// Команды для удаления всех студентов и добавления студента.
public ICommand RemoveAllStudentsCommand { get; }
public ICommand AddStudentCommand { get; }
// Конструктор ViewModel. Инициализирует зависимости и устанавливает начальные значения.
public GroupViewModel(IScreen screen, GroupUseCase groupUseCase, UseCaseGeneratePresence presenceUseCase, RemoteDatabaseContext remoteDatabaseContext)
{
_groupUseCase = groupUseCase;
_presenceUseCase = presenceUseCase;
HostScreen = screen;
_remoteDatabaseContext = remoteDatabaseContext; // Инициализация контекста базы данных
// Инициализация реактивных команд с условиями выполнения.
OnDeleteUserClicks = ReactiveCommand.Create(OnDeleteUserClick, this.WhenAnyValue(vm => vm.CanDelete));
EditUserCommand = ReactiveCommand.Create(OnEditUserClick, this.WhenAnyValue(vm => vm.CanEdit));
RefreshGroups(); // Загрузка и обновление списка групп
_groups = new ObservableCollection<GroupPresenter>(groupPresentersDataSource);
_users = new ObservableCollection<UserPresenter>();
// Подписка на изменения выбранной группы для обновления списка пользователей.
this.WhenAnyValue(vm => vm.SelectedGroupItem)
.Subscribe(vm => SetUsers());
// Подписка на изменения выбранной опции сортировки для сортировки списка пользователей.
this.WhenAnyValue(vm => vm.SelectedSortOption)
.Subscribe(_ => SortUsers());
// Инициализация команд добавления и удаления студентов.
RemoveAllStudentsCommand = ReactiveCommand.Create(RemoveAllStudents);
AddStudentCommand = ReactiveCommand.Create(AddStudent);
// Обработчик изменений в коллекции выбранных пользователей для обновления состояния команд.
SelectedUsers.CollectionChanged += (s, e) =>
{
this.RaisePropertyChanged(nameof(CanDelete));
this.RaisePropertyChanged(nameof(CanEdit));
};
NextPageCommand = ReactiveCommand.Create(NextPageButton);
}
// Установка списка пользователей для выбранной группы. Очищает существующий список и добавляет пользователей из выбранной группы.
private void SetUsers()
{
if (SelectedGroupItem?.users == null) return;
Users.Clear(); // Очищаем список пользователей
foreach (var item in SelectedGroupItem.users)
{
Users.Add(item); // Добавляем пользователей из выбранной группы
}
SortUsers(); // Сортируем пользователей
}
// Сортировка списка пользователей по выбранному критерию.
private void SortUsers()
{
if (SelectedGroupItem?.users == null) return;
var sortedUsers = SelectedGroupItem.users.ToList(); // Создаем копию списка пользователей
switch (SelectedSortOption)
{
case "По фамилии":
sortedUsers = sortedUsers.OrderBy(u => u.Name).ToList(); // Сортировка по имени
break;
case "По убыванию":
sortedUsers = sortedUsers.OrderByDescending(u => u.Name).ToList(); // Сортировка в обратном порядке
break;
}
Users.Clear(); // Очищаем список пользователей
foreach (var item in sortedUsers)
{
Users.Add(item); // Добавляем отсортированных пользователей
}
}
// Удаление всех студентов из выбранной группы.
private void RemoveAllStudents()
{
if (SelectedGroupItem == null) return;
_groupUseCase.RemoveAllStudentsFromGroup(SelectedGroupItem.Id); // Удаляем студентов из группы через UseCase
SelectedGroupItem.users = new List<UserPresenter>(); // Обновляем список пользователей в группе
SetUsers(); // Обновляем список пользователей в ViewModel
}
// Переход на следующую страницу (представление).
private void NextPageButton()
{
// Создаем новые экземпляры репозитория и UseCase для следующего представления.
var groupRepository = new SQLGroupRepositoryImpl(_remoteDatabaseContext);
var groupUseCase = new GroupUseCase(groupRepository);
// Переход к представлению PresenceViewModel
HostScreen.Router.Navigate.Execute(new PresenceViewModel(HostScreen, groupUseCase, _presenceUseCase));
}
// Добавление студентов из CSV файла.
private void AddStudent()
{
// Замените на корректный путь к вашему CSV файлу.
string csvFilePath = @"C:\Users\VivoBook 15X\Desktop\Программные модули\Group.csv";
List<UserPresenter> students;
try
{
students = ReadStudentsFromCsv(csvFilePath); // Читаем студентов из CSV файла
}
catch (Exception ex)
{
Console.WriteLine($"Ошибка при чтении CSV: {ex.Message}"); // Обработка исключений
return;
}
if (SelectedGroupItem == null) return;
// Добавляем каждого студента в выбранную группу.
foreach (var student in students)
{
_groupUseCase.AddStudentToGroup(SelectedGroupItem.Id, new User { FIO = student.Name }); // Добавляем студента через UseCase
var newStudent = new UserPresenter
{
Name = student.Name,
Group = SelectedGroupItem // Устанавливаем ссылку на группу
};
var updatedUsers = SelectedGroupItem.users?.ToList() ?? new List<UserPresenter>();
updatedUsers.Add(newStudent);
SelectedGroupItem.users = updatedUsers;
}
SetUsers(); // Обновляем список пользователей
}
// Чтение студентов из CSV файла.
private List<UserPresenter> ReadStudentsFromCsv(string filePath)
{
var students = new List<UserPresenter>();
try
{
using (var reader = new StreamReader(filePath))
using (var csv = new CsvReader(reader, new CsvConfiguration(System.Globalization.CultureInfo.InvariantCulture)
{
HasHeaderRecord = true, // Указываем, что в CSV есть заголовок
Delimiter = "," // Разделитель в CSV файле
}))
{
var records = csv.GetRecords<StudentCsvModel>().ToList(); // Читаем записи из CSV
foreach (var record in records)
{
var student = new UserPresenter
{
Guid = Guid.NewGuid(), // Генерируем уникальный идентификатор
Name = record.Name // Устанавливаем имя студента
};
students.Add(student); // Добавляем студента в список
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Ошибка при чтении CSV файла: {ex.Message}"); // Обработка исключений
}
return students; // Возвращаем список студентов
}
// Обработка события удаления пользователя.
public void OnDeleteUserClick()
{
if (SelectedUsers.Count == 0 || SelectedGroupItem?.users == null)
return;
foreach (var user in SelectedUsers.ToList())
{
_groupUseCase.RemoveUserByGuid(user.Guid); // Удаляем пользователя через UseCase
// Обновляем список пользователей в выбранной группе.
var updatedUsers = SelectedGroupItem.users.Where(u => u.Guid != user.Guid).ToList();
SelectedGroupItem.users = new List<UserPresenter>(updatedUsers);
}
SetUsers(); // Обновляем список пользователей
SelectedUsers.Clear(); // Очищаем список выбранных пользователей
this.RaisePropertyChanged(nameof(CanDelete)); // Обновляем состояние команды удаления
this.RaisePropertyChanged(nameof(CanEdit)); // Обновляем состояние команды редактирования
}
// Обработка события редактирования пользователя.
public async void OnEditUserClick()
{
var user = SelectedUsers.FirstOrDefault(); // Получаем первого выбранного пользователя
if (user == null) return;
var groups = _groupUseCase.GetAllGroups(); // Получаем все группы
// Преобразуем группы из domain.Models.Group в GroupPresenter
var groupPresenters = groups.Select(g => new GroupPresenter
{
Id = g.Id,
Name = g.Name,
users = g.Users?.Select(u => new UserPresenter
{
Name = u.FIO,
Guid = u.Guid,
Group = new GroupPresenter { Id = g.Id, Name = g.Name }
}).ToList()
}).ToList();
// Создаем диалоговое окно для редактирования пользователя.
var editDialog = new EditUserDialog(user.Guid, user.Name, user.Group.Id, groupPresenters);
var mainWindow = (Application.Current.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow;
if (mainWindow == null) return;
// Открываем диалоговое окно и ожидаем результата.
var result = await editDialog.ShowDialog(mainWindow);
if (result != (null, null))
{
var newName = result.Item1; // Новое имя пользователя
var newGroup = result.Item2; // Новая группа пользователя
// Обновляем пользователя.
user.Name = newName;
user.Group = newGroup;
_groupUseCase.UpdateUser(user.Guid, user.Name, user.Group.Id); // Сохраняем изменения через UseCase
SetUsers(); // Обновляем список пользователей
SelectedUsers.Clear(); // Очищаем список выбранных пользователей
this.RaisePropertyChanged(nameof(CanEdit)); // Обновляем состояние команды редактирования
this.RaisePropertyChanged(nameof(CanDelete)); // Обновляем состояние команды удаления
}
RefreshGroups(); // Обновляем список групп
}
// Обновление списка групп из UseCase.
private void RefreshGroups()
{
groupPresentersDataSource.Clear(); // Очищаем текущий список групп
foreach (var item in _groupUseCase.GetAllGroups())
{
GroupPresenter groupPresenter = new GroupPresenter
{
Id = item.Id,
Name = item.Name,
users = item.Users?.Select(user => new UserPresenter
{
Name = user.FIO,
Guid = user.Guid,
Group = new GroupPresenter { Id = item.Id, Name = item.Name }
}).ToList()
};
groupPresentersDataSource.Add(groupPresenter); // Добавляем группу в список
}
_groups = new ObservableCollection<GroupPresenter>(groupPresentersDataSource); // Обновляем коллекцию групп
}
}
}