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 groupPresentersDataSource = new List(); // Коллекция групп, отображаемых в интерфейсе. Используется ReactiveUI для обновления интерфейса при изменении данных. private ObservableCollection _groups; public ObservableCollection Groups => _groups; // Выбранная группа в интерфейсе. Изменения этого свойства вызывают обновление списка пользователей. private GroupPresenter? _selectedGroupItem; public GroupPresenter? SelectedGroupItem { get => _selectedGroupItem; set => this.RaiseAndSetIfChanged(ref _selectedGroupItem, value); } // Коллекция пользователей, связанных с выбранной группой. Обновляется при изменении выбранной группы. public ObservableCollection Users { get => _users; } private ObservableCollection _users; // Список доступных опций сортировки пользователей. public List SortOptions { get; } = new List { "По фамилии", "По убыванию" }; // Выбранная опция сортировки пользователей. Изменение этого свойства вызывает сортировку списка пользователей. 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 SelectedUsers { get; set; } = new ObservableCollection(); // Реактивные команды для обработки действий пользователя. Обеспечивают реактивное поведение интерфейса. public ReactiveCommand OnDeleteUserClicks { get; } public ReactiveCommand EditUserCommand { get; } public ReactiveCommand 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(groupPresentersDataSource); _users = new ObservableCollection(); // Подписка на изменения выбранной группы для обновления списка пользователей. 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(); // Обновляем список пользователей в группе 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 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(); updatedUsers.Add(newStudent); SelectedGroupItem.users = updatedUsers; } SetUsers(); // Обновляем список пользователей } // Чтение студентов из CSV файла. private List ReadStudentsFromCsv(string filePath) { var students = new List(); 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().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(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(groupPresentersDataSource); // Обновляем коллекцию групп } } }