Presence_Desktop/Presence.Desktop/ViewModels/GroupViewModel.cs

343 lines
18 KiB
C#
Raw Normal View History

2024-12-23 11:26:41 +00:00
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); // Обновляем коллекцию групп
}
}
}