483 lines
18 KiB
C#
483 lines
18 KiB
C#
using CommunityToolkit.Mvvm.ComponentModel;
|
|
using CommunityToolkit.Mvvm.Input;
|
|
using DirectoryCreator.Models;
|
|
using DirectoryCreator.ViewModels;
|
|
using System.Collections.ObjectModel;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Text.Json;
|
|
using System.Windows;
|
|
|
|
namespace DirectoryCreator
|
|
{
|
|
/// <summary>
|
|
/// Interaction logic for MainWindow.xaml
|
|
/// </summary>
|
|
public partial class MainWindow : Window
|
|
{
|
|
public MainWindow()
|
|
{
|
|
InitializeComponent();
|
|
DataContext = new MainWindowViewModel();
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace DirectoryCreator.ViewModels
|
|
{
|
|
public partial class MainWindowViewModel : ObservableObject
|
|
{
|
|
private readonly string configDirectory = "Configurations";
|
|
private FolderConfig currentConfig;
|
|
|
|
[ObservableProperty]
|
|
private string lastProjectNumber;
|
|
|
|
[ObservableProperty]
|
|
private string newProjectName;
|
|
|
|
[ObservableProperty]
|
|
private string basePath;
|
|
|
|
[ObservableProperty]
|
|
private ObservableCollection<FolderConfig> availableConfigurations;
|
|
|
|
[ObservableProperty]
|
|
private FolderConfig selectedConfiguration;
|
|
|
|
public MainWindowViewModel()
|
|
{
|
|
IsDarkTheme = Properties.Settings.Default.IsDarkTheme;
|
|
ThemeManager.SetTheme(IsDarkTheme);
|
|
AvailableConfigurations = new ObservableCollection<FolderConfig>();
|
|
LoadConfigurations();
|
|
}
|
|
|
|
private void LoadConfigurations()
|
|
{
|
|
try
|
|
{
|
|
// Asegurar que existe el directorio de configuraciones
|
|
if (!Directory.Exists(configDirectory))
|
|
{
|
|
Directory.CreateDirectory(configDirectory);
|
|
|
|
// Si no existe, mover el archivo de configuración por defecto
|
|
if (File.Exists("folderConfig.json"))
|
|
{
|
|
File.Move("folderConfig.json", Path.Combine(configDirectory, "default.json"));
|
|
}
|
|
}
|
|
|
|
// Cargar todas las configuraciones
|
|
var jsonFiles = Directory.GetFiles(configDirectory, "*.json");
|
|
if (jsonFiles.Length == 0)
|
|
{
|
|
MessageBox.Show("No se encontraron archivos de configuración.", "Advertencia", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
return;
|
|
}
|
|
|
|
var options = new JsonSerializerOptions
|
|
{
|
|
PropertyNameCaseInsensitive = true,
|
|
AllowTrailingCommas = true
|
|
};
|
|
|
|
AvailableConfigurations.Clear();
|
|
foreach (var jsonFile in jsonFiles)
|
|
{
|
|
var jsonString = File.ReadAllText(jsonFile);
|
|
var config = JsonSerializer.Deserialize<FolderConfig>(jsonString, options);
|
|
if (config != null)
|
|
{
|
|
// Si no tiene descripción, usar el nombre del archivo
|
|
if (string.IsNullOrEmpty(config.Description))
|
|
{
|
|
config.Description = Path.GetFileNameWithoutExtension(jsonFile);
|
|
}
|
|
AvailableConfigurations.Add(config);
|
|
}
|
|
}
|
|
|
|
// Seleccionar la primera configuración por defecto
|
|
if (AvailableConfigurations.Count > 0)
|
|
{
|
|
SelectedConfiguration = AvailableConfigurations[0];
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show($"Error al cargar las configuraciones: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
}
|
|
}
|
|
|
|
[RelayCommand]
|
|
private void OpenBaseFolder()
|
|
{
|
|
try
|
|
{
|
|
if (Directory.Exists(BasePath))
|
|
{
|
|
Process.Start("explorer.exe", BasePath);
|
|
}
|
|
else
|
|
{
|
|
MessageBox.Show($"La carpeta base no existe: {BasePath}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show($"Error al abrir la carpeta base: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
}
|
|
}
|
|
|
|
private void LoadLastProjectNumber()
|
|
{
|
|
try
|
|
{
|
|
if (string.IsNullOrEmpty(BasePath) || !Directory.Exists(BasePath))
|
|
{
|
|
NewProjectName = "001 - ";
|
|
return;
|
|
}
|
|
|
|
var directories = Directory.GetDirectories(BasePath)
|
|
.Select(d => new DirectoryInfo(d).Name)
|
|
.ToList();
|
|
|
|
var regex = new System.Text.RegularExpressions.Regex(@"^(\d{1,3})\s-\s");
|
|
var projectNumbers = new HashSet<int>();
|
|
|
|
foreach (var dirName in directories)
|
|
{
|
|
var match = regex.Match(dirName);
|
|
if (match.Success && int.TryParse(match.Groups[1].Value, out int number))
|
|
{
|
|
projectNumbers.Add(number);
|
|
}
|
|
}
|
|
|
|
var sortedNumbers = projectNumbers.OrderByDescending(n => n).ToList();
|
|
int lastValidNumber = -1;
|
|
string lastProject = "";
|
|
|
|
foreach (int number in sortedNumbers)
|
|
{
|
|
if (projectNumbers.Contains(number - 1) && projectNumbers.Contains(number - 2))
|
|
{
|
|
lastValidNumber = number;
|
|
lastProject = directories.First(d => regex.Match(d).Success &&
|
|
int.Parse(regex.Match(d).Groups[1].Value) == number);
|
|
break;
|
|
}
|
|
}
|
|
|
|
LastProjectNumber = lastProject;
|
|
NewProjectName = lastValidNumber >= 0 ? $"{(lastValidNumber + 1):00} - " : "01 - ";
|
|
|
|
if (lastValidNumber < 0)
|
|
{
|
|
MessageBox.Show("No se encontró una secuencia válida de al menos 3 números consecutivos.\nSe iniciará desde 01.",
|
|
"Información", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show($"Error al cargar el último proyecto: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
NewProjectName = "001 - ";
|
|
}
|
|
}
|
|
|
|
[RelayCommand]
|
|
private void EditConfigurations()
|
|
{
|
|
var window = new ConfigEditorWindow
|
|
{
|
|
Owner = System.Windows.Application.Current.MainWindow
|
|
};
|
|
|
|
if (SelectedConfiguration != null)
|
|
{
|
|
var configPath = Directory.GetFiles(configDirectory, "*.json")
|
|
.FirstOrDefault(f =>
|
|
{
|
|
var config = JsonSerializer.Deserialize<FolderConfig>(
|
|
File.ReadAllText(f),
|
|
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
|
return config?.Description == SelectedConfiguration.Description;
|
|
});
|
|
|
|
window.DataContext = new ConfigEditorViewModel(window, SelectedConfiguration, configPath);
|
|
}
|
|
else
|
|
{
|
|
window.DataContext = new ConfigEditorViewModel(window);
|
|
}
|
|
|
|
if (window.ShowDialog() == true)
|
|
{
|
|
LoadConfigurations();
|
|
}
|
|
}
|
|
|
|
[ObservableProperty]
|
|
private bool isDarkTheme;
|
|
|
|
partial void OnIsDarkThemeChanged(bool value)
|
|
{
|
|
ThemeManager.SetTheme(value);
|
|
// Opcional: Guardar la preferencia del usuario
|
|
Properties.Settings.Default.IsDarkTheme = value;
|
|
Properties.Settings.Default.Save();
|
|
}
|
|
|
|
[ObservableProperty]
|
|
private ObservableCollection<string> existingProjects = new();
|
|
|
|
[ObservableProperty]
|
|
private string selectedProject;
|
|
|
|
private void LoadExistingProjects()
|
|
{
|
|
try
|
|
{
|
|
if (string.IsNullOrEmpty(BasePath) || !Directory.Exists(BasePath))
|
|
{
|
|
ExistingProjects = new ObservableCollection<string>();
|
|
return;
|
|
}
|
|
|
|
var directories = Directory.GetDirectories(BasePath)
|
|
.Select(d => new DirectoryInfo(d).Name)
|
|
.OrderByDescending(name => name)
|
|
.ToList();
|
|
|
|
ExistingProjects = new ObservableCollection<string>(directories);
|
|
|
|
// Seleccionar el LastProjectNumber si existe
|
|
if (ExistingProjects.Count > 0)
|
|
{
|
|
if (!string.IsNullOrEmpty(LastProjectNumber) && ExistingProjects.Contains(LastProjectNumber))
|
|
{
|
|
SelectedProject = LastProjectNumber;
|
|
}
|
|
else
|
|
{
|
|
SelectedProject = ExistingProjects[0];
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show($"Error al cargar proyectos existentes: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
ExistingProjects = new ObservableCollection<string>();
|
|
}
|
|
}
|
|
|
|
partial void OnSelectedConfigurationChanged(FolderConfig value)
|
|
{
|
|
if (value != null)
|
|
{
|
|
currentConfig = value;
|
|
BasePath = value.BasePath;
|
|
LoadLastProjectNumber();
|
|
LoadExistingProjects(); // Cargar proyectos existentes cuando cambia la configuración
|
|
}
|
|
}
|
|
|
|
[RelayCommand]
|
|
private async Task RenameProject()
|
|
{
|
|
if (string.IsNullOrEmpty(SelectedProject))
|
|
{
|
|
MessageBox.Show("Por favor seleccione un proyecto para renombrar", "Advertencia", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
return;
|
|
}
|
|
|
|
var result = Microsoft.Windows.Controls.InputDialog.Show(
|
|
"Renombrar Proyecto",
|
|
"Ingrese el nuevo nombre del proyecto:",
|
|
SelectedProject);
|
|
|
|
if (result.IsOk)
|
|
{
|
|
string newName = result.Result;
|
|
if (string.IsNullOrWhiteSpace(newName))
|
|
{
|
|
MessageBox.Show("El nombre no puede estar vacío", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
foreach (var structure in currentConfig.FolderStructures)
|
|
{
|
|
var basePath = structure.BasePath.Replace("{year}", DateTime.Now.Year.ToString());
|
|
var oldPath = Path.Combine(basePath, SelectedProject);
|
|
var newPath = Path.Combine(basePath, newName);
|
|
|
|
if (Directory.Exists(oldPath))
|
|
{
|
|
if (Directory.Exists(newPath))
|
|
{
|
|
MessageBox.Show($"Ya existe un directorio con el nombre: {newName}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
return;
|
|
}
|
|
|
|
Directory.Move(oldPath, newPath);
|
|
}
|
|
}
|
|
|
|
MessageBox.Show("Proyecto renombrado exitosamente!", "Éxito", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
LoadExistingProjects(); // Recargar la lista de proyectos
|
|
SelectedProject = newName;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show($"Error al renombrar el proyecto: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Agregar este método en la clase MainWindowViewModel
|
|
[RelayCommand]
|
|
private void DeleteProject()
|
|
{
|
|
if (string.IsNullOrEmpty(SelectedProject))
|
|
{
|
|
MessageBox.Show("Por favor seleccione un proyecto para eliminar", "Advertencia", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
// Recopilar todos los directorios a verificar
|
|
List<string> directoriesToCheck = new List<string>();
|
|
List<string> nonEmptyDirectories = new List<string>();
|
|
|
|
// Primero encontrar todos los directorios del proyecto
|
|
foreach (var structure in currentConfig.FolderStructures)
|
|
{
|
|
var basePath = structure.BasePath.Replace("{year}", DateTime.Now.Year.ToString());
|
|
var projectPath = Path.Combine(basePath, SelectedProject);
|
|
|
|
if (Directory.Exists(projectPath))
|
|
{
|
|
directoriesToCheck.Add(projectPath);
|
|
}
|
|
}
|
|
|
|
if (!directoriesToCheck.Any())
|
|
{
|
|
MessageBox.Show("No se encontraron directorios para eliminar.", "Información", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
return;
|
|
}
|
|
|
|
// Verificar que todos los directorios estén vacíos
|
|
foreach (var directory in directoriesToCheck)
|
|
{
|
|
if (!IsDirectoryEmpty(directory))
|
|
{
|
|
nonEmptyDirectories.Add(directory);
|
|
}
|
|
}
|
|
|
|
// Si hay directorios con contenido, mostrar mensaje y cancelar
|
|
if (nonEmptyDirectories.Any())
|
|
{
|
|
string message = "Los siguientes directorios contienen archivos y no pueden ser eliminados:\n\n";
|
|
message += string.Join("\n", nonEmptyDirectories);
|
|
message += "\n\nDebe vaciar estos directorios antes de poder eliminar el proyecto.";
|
|
MessageBox.Show(message, "Directorios no vacíos", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
return;
|
|
}
|
|
|
|
// Si todos están vacíos, pedir confirmación
|
|
var result = MessageBox.Show(
|
|
$"Se eliminarán los siguientes directorios:\n\n{string.Join("\n", directoriesToCheck)}\n\n¿Está seguro que desea continuar?",
|
|
"Confirmar eliminación",
|
|
MessageBoxButton.YesNo,
|
|
MessageBoxImage.Warning);
|
|
|
|
if (result == MessageBoxResult.Yes)
|
|
{
|
|
// Eliminar todos los directorios
|
|
foreach (var directory in directoriesToCheck)
|
|
{
|
|
if (Directory.Exists(directory))
|
|
{
|
|
Directory.Delete(directory, false); // false porque ya sabemos que están vacíos
|
|
}
|
|
}
|
|
|
|
MessageBox.Show("Proyecto eliminado exitosamente!", "Éxito", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
LoadExistingProjects(); // Recargar la lista de proyectos
|
|
SelectedProject = null;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show($"Error al eliminar el proyecto: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
}
|
|
}
|
|
|
|
private bool IsDirectoryEmpty(string path)
|
|
{
|
|
try
|
|
{
|
|
return !Directory.EnumerateFileSystemEntries(path, "*", SearchOption.AllDirectories).Any();
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
[RelayCommand]
|
|
private void CreateDirectories()
|
|
{
|
|
if (string.IsNullOrEmpty(NewProjectName))
|
|
{
|
|
MessageBox.Show("Por favor ingrese un nombre de proyecto!", "Advertencia", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
return;
|
|
}
|
|
|
|
if (currentConfig == null)
|
|
{
|
|
MessageBox.Show("Por favor seleccione una configuración!", "Advertencia", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
foreach (var structure in currentConfig.FolderStructures)
|
|
{
|
|
var basePath = structure.BasePath.Replace("{year}", DateTime.Now.Year.ToString());
|
|
var projectPath = Path.Combine(basePath, NewProjectName);
|
|
|
|
if (Directory.Exists(projectPath))
|
|
{
|
|
MessageBox.Show($"El directorio ya existe: {projectPath}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
return;
|
|
}
|
|
|
|
Directory.CreateDirectory(projectPath);
|
|
|
|
foreach (var subfolder in structure.Subfolders)
|
|
{
|
|
var subfolderPath = Path.Combine(projectPath, subfolder);
|
|
Directory.CreateDirectory(subfolderPath);
|
|
}
|
|
}
|
|
|
|
Process.Start("explorer.exe", Path.Combine(BasePath, NewProjectName));
|
|
MessageBox.Show("Directorios creados exitosamente!", "Éxito", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
LoadLastProjectNumber();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show($"Error al crear directorios: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
}
|
|
}
|
|
}
|
|
} |