Files
CodeContextGenerator/CodeContextGenerator/ViewModels/MainViewModel.cs
2025-12-11 00:25:23 +05:00

282 lines
10 KiB
C#
Raw 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 CodeContextGenerator.Interfaces;
using CodeContextGenerator.Models;
using CodeContextGenerator.Services;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace CodeContextGenerator.ViewModels
{
public partial class MainViewModel : ObservableObject
{
private readonly IProjectLoaderService _projectLoaderService;
private readonly IFileScannerService _fileScannerService;
private readonly IContextFileGenerator _contextFileGenerator;
private readonly IUIService _uiService;
private readonly ISettingsService _settingsService;
private CancellationTokenSource _cancellationTokenSource;
[ObservableProperty]
private FileItem rootDirectory;
[ObservableProperty]
private string selectedProjectPath;
[ObservableProperty]
private bool isProcessing;
[ObservableProperty]
private int progressValue;
[ObservableProperty]
private string progressText;
[ObservableProperty]
private bool isProjectLoaded;
// Явное объявление команд для гарантии их создания
public IRelayCommand SelectProjectCommand { get; }
public IAsyncRelayCommand GenerateContextFileCommand { get; }
public IRelayCommand CancelProcessingCommand { get; }
public IRelayCommand ExitApplicationCommand { get; }
public MainViewModel(
IProjectLoaderService projectLoaderService,
IFileScannerService fileScannerService,
IContextFileGenerator contextFileGenerator,
IUIService uiService,
ISettingsService settingsService)
{
_projectLoaderService = projectLoaderService;
_fileScannerService = fileScannerService;
_contextFileGenerator = contextFileGenerator;
_uiService = uiService;
_settingsService = settingsService;
// Явная инициализация команд
SelectProjectCommand = new RelayCommand(SelectProject, CanSelectProject);
GenerateContextFileCommand = new AsyncRelayCommand(GenerateContextFileAsync, CanGenerate);
CancelProcessingCommand = new RelayCommand(CancelProcessing);
ExitApplicationCommand = new RelayCommand(ExitApplication);
}
private bool CanSelectProject() => !IsProcessing;
private bool CanGenerate()
{
bool result = !IsProcessing &&
IsProjectLoaded &&
RootDirectory != null &&
HasSelectedFiles(RootDirectory);
// Отладочная информация
System.Diagnostics.Debug.WriteLine($"CanGenerate: {result}, IsProcessing: {IsProcessing}, IsProjectLoaded: {IsProjectLoaded}, RootDirectory: {(RootDirectory != null)}, HasSelectedFiles: {HasSelectedFiles(RootDirectory)}");
return result;
}
private void SelectProject()
{
var initialDir = !string.IsNullOrEmpty(SelectedProjectPath) && Directory.Exists(SelectedProjectPath)
? Path.GetDirectoryName(SelectedProjectPath)
: _settingsService.GetLastProjectPath();
if (_uiService.ShowOpenProjectFileDialog(out var filePath))
{
LoadProject(filePath);
return;
}
var folderPath = _uiService.ShowFolderBrowserDialog(initialDir);
if (!string.IsNullOrEmpty(folderPath))
{
LoadProject(folderPath);
}
}
private async Task GenerateContextFileAsync()
{
var selectedFiles = _fileScannerService.GetSelectedFiles(RootDirectory);
if (selectedFiles.Count == 0)
{
_uiService.ShowMessage("Пожалуйста, выберите хотя бы один файл для обработки.", "Предупреждение", MessageBoxImage.Warning);
return;
}
var defaultFileName = _projectLoaderService.GetDefaultOutputFileName(SelectedProjectPath);
var initialDir = _settingsService.GetLastProjectPath() ?? Path.GetDirectoryName(SelectedProjectPath);
if (!_uiService.ShowSaveFileDialog(defaultFileName, initialDir, out var savePath))
return;
IsProcessing = true;
ProgressText = "Генерация контекстного файла...";
ProgressValue = 0;
try
{
_cancellationTokenSource = new CancellationTokenSource();
var progress = new Progress<int>(value =>
{
ProgressValue = value;
ProgressText = $"Генерация: {value}%";
});
await _contextFileGenerator.GenerateContextFileAsync(
selectedFiles,
savePath,
Path.GetDirectoryName(SelectedProjectPath),
progress,
_cancellationTokenSource.Token);
_uiService.ShowMessage($"Файл успешно создан:\n{savePath}", "Успех");
}
catch (OperationCanceledException)
{
ProgressText = "Генерация отменена";
}
catch (IOException ex)
{
_uiService.ShowMessage($"Ошибка доступа к файлу: {ex.Message}\nПожалуйста, закройте файлы или предоставьте необходимые права доступа.", "Ошибка доступа", MessageBoxImage.Error);
}
catch (System.Exception ex)
{
_uiService.ShowMessage($"Ошибка при генерации файла: {ex.Message}", "Ошибка", MessageBoxImage.Error);
}
finally
{
IsProcessing = false;
// Принудительно обновляем команды после завершения операции
UpdateCommandsCanExecute();
}
}
private void CancelProcessing()
{
_cancellationTokenSource?.Cancel();
ProgressText = "Операция отменена";
}
private void ExitApplication()
{
Application.Current.Shutdown();
}
private void LoadProject(string projectPath)
{
SelectedProjectPath = projectPath;
_settingsService.SaveLastProjectPath(Path.GetDirectoryName(projectPath));
IsProjectLoaded = false;
RootDirectory = null;
UpdateCommandsCanExecute();
LoadProjectAsync(projectPath);
}
private async void LoadProjectAsync(string projectPath)
{
ProgressText = "Загрузка проекта...";
ProgressValue = 0;
try
{
var progress = new Progress<int>(value =>
{
ProgressValue = value;
ProgressText = $"Загрузка: {value}%";
});
_cancellationTokenSource = new CancellationTokenSource();
RootDirectory = await _projectLoaderService.LoadProjectFromPathAsync(projectPath, progress, _cancellationTokenSource.Token);
IsProjectLoaded = true;
ProgressText = "Проект загружен успешно";
// Подписываемся на события изменения выбора
SubscribeToSelectionChanges(RootDirectory);
// Сбрасываем выделение после загрузки
if (RootDirectory != null)
{
ClearSelections(RootDirectory);
}
// Принудительно обновляем команды
UpdateCommandsCanExecute();
}
catch (OperationCanceledException)
{
ProgressText = "Загрузка отменена";
}
catch (System.Exception ex)
{
_uiService.ShowMessage($"Ошибка при загрузке проекта: {ex.Message}", "Ошибка", MessageBoxImage.Error);
}
finally
{
IsProcessing = false;
UpdateCommandsCanExecute();
}
}
// Рекурсивная подписка на события изменения выбора
private void SubscribeToSelectionChanges(FileItem item)
{
if (item == null) return;
item.SelectionChanged += (sender, args) =>
{
UpdateCommandsCanExecute();
};
foreach (var child in item.Children)
{
SubscribeToSelectionChanges(child);
}
}
private void ClearSelections(FileItem item)
{
if (item == null) return;
item.IsSelected = false;
foreach (var child in item.Children)
{
ClearSelections(child);
}
}
private bool HasSelectedFiles(FileItem item)
{
if (item == null) return false;
if (!item.IsDirectory && item.IsSelected == true)
return true;
if (item.IsDirectory)
{
foreach (var child in item.Children)
{
if (HasSelectedFiles(child))
return true;
}
}
return false;
}
// Метод для принудительного обновления всех команд
private void UpdateCommandsCanExecute()
{
(SelectProjectCommand as RelayCommand)?.NotifyCanExecuteChanged();
(GenerateContextFileCommand as AsyncRelayCommand)?.NotifyCanExecuteChanged();
}
}
}