diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..986a9fe Binary files /dev/null and b/.DS_Store differ diff --git a/._.DS_Store b/._.DS_Store new file mode 100644 index 0000000..4943dd3 Binary files /dev/null and b/._.DS_Store differ diff --git a/.gitignore b/.gitignore index dbd545c..900cc1d 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ /WpfApp/obj /App.WPF /WpfApp/bin/Debug/net8.0-windows +/._.gitignore diff --git a/App.Cmd/ViewModels/SaveViewModel.cs b/App.Cmd/ViewModels/SaveViewModel.cs index 2c27d10..1e4d4ee 100644 --- a/App.Cmd/ViewModels/SaveViewModel.cs +++ b/App.Cmd/ViewModels/SaveViewModel.cs @@ -1,6 +1,7 @@ using App.Core.Models; using App.Core.Services; using Newtonsoft.Json; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.Reflection; using System.Text.RegularExpressions; @@ -15,6 +16,7 @@ public partial class SaveViewModel private readonly LoggerService? loggerService; private readonly CopyService? copyService; private readonly DisplayService displayService; + private ThreadManagerService threadManagerService = new(); [GeneratedRegex(@"^\d+;\d+$")] private static partial Regex MyRegex(); @@ -32,7 +34,8 @@ public SaveViewModel() }; loggerService = new(); - copyService = new(stateManagerService); + copyService = new(); + copyService.stateManagerService = stateManagerService; displayService = new(); saveService = new() @@ -46,21 +49,12 @@ public SaveViewModel() saveService.ListStateManager = listState; } - - - public enum TypeOfSave { Sequential, Complete } - - /// - /// Method to get the user choice - /// - /// - /// public bool UserChoice(int UserEntry) { saveService!.ListSaveModel = ListSaveModel; @@ -215,7 +209,7 @@ public bool UserChoice(int UserEntry) saveService!.CreateSave( InPath, OutPath, type, SaveName); - stateManagerService!.UpdateStateFile(); + //stateManagerService!.UpdateStateFile(); ListSaveModel = saveService.ListSaveModel; listState = stateManagerService!.listStateModel!; @@ -262,57 +256,45 @@ public bool UserChoice(int UserEntry) { if (!saveService!.IsSoftwareRunning()) { - + List list = new List(); string[] parts = UserChoice.Split(';'); int z1 = int.Parse(parts[0]); int z2 = int.Parse(parts[1]); - DisplayService.SetForegroundColor("Green", $"Save {z1} is running"); - - saveService!.ExecuteSave(ListSaveModel[z1]); - DisplayService.SetForegroundColor("Green", $"Save {z1} Executed"); - Thread.Sleep(1000); - DisplayService.SetForegroundColor("Green", $"Save {z2} is running"); - saveService!.ExecuteSave(ListSaveModel[z2]); - DisplayService.SetForegroundColor("Green", $"Save {z2} Executed"); - Thread.Sleep(1000); - - + Console.WriteLine(); + list.Add(ListSaveModel[z1]); + list.Add(ListSaveModel[z2]); + saveService!.ExecuteSave(list, threadManagerService); } else { DisplayService.SetBackForeColor("Black", "DarkRed", "Software is running save cannot be executed..."); System.Threading.Thread.Sleep(1500); } - } else { //TODO : Ajouter un try catch pour la gestion des entrées de l'utilisateur if (!saveService!.IsSoftwareRunning()) { + List list = new List(); string[] parts = UserChoice.Split('-'); int min = int.Parse(parts[0]); int max = int.Parse(parts[1]); for (int x = min; x <= max; x++) { - DisplayService.SetForegroundColor("Green", $"Save {x} is running"); - saveService!.ExecuteSave(ListSaveModel[x]); - DisplayService.SetForegroundColor("Green", $"Save {x} Executed"); - Thread.Sleep(1000); + list.Add(ListSaveModel[x]); } - + saveService!.ExecuteSave(list, threadManagerService); } else { DisplayService.SetBackForeColor("Black", "DarkRed", "Software is running save cannot be executed..."); System.Threading.Thread.Sleep(1500); } - - } - //return true; - } + } + catch (ArgumentOutOfRangeException) { //TODO : Quand save est vide @@ -355,15 +337,21 @@ public bool UserChoice(int UserEntry) } } + private void SaveViewModel_CopyPaused(object? sender, EventArgs e) + { + Console.WriteLine("Save Paused"); + } - - + private void SaveViewModel_CopyStopped(object? sender, EventArgs e) + { + Console.WriteLine("Save Stopped"); + } public void ShowLogs() { //Method to show the logs - loggerService.OpenLogFile(); + loggerService?.OpenLogFile(); } /// @@ -384,17 +372,17 @@ public void ShowSavesSchedule() { FileInfo fileInfo = new("saves.json"); - if (fileInfo.Length > 0) - { - string json = File.ReadAllText("saves.json"); - ListSaveModel = JsonConvert.DeserializeObject>(json) ?? []; + if (fileInfo.Length > 0) + { + string json = File.ReadAllText("saves.json"); + ListSaveModel = JsonConvert.DeserializeObject>(json) ?? []; + } + else + { + // Fichier vide, initialiser la liste sans désérialiser + ListSaveModel = []; + } } - else - { - // Fichier vide, initialiser la liste sans désérialiser - ListSaveModel = []; - } - } else { // Créer le fichier s'il n'existe pas @@ -406,7 +394,7 @@ public void ShowSavesSchedule() foreach (SaveModel item in ListSaveModel) { - Console.WriteLine($"{i} "+saveService!.ShowInfo(item)); + Console.WriteLine($"{i} "+saveService!.ShowInfo(item) + threadManagerService.AreThreadsRunning(i)); i++; } diff --git a/App.Core/Models/ConfigModel.cs b/App.Core/Models/ConfigModel.cs deleted file mode 100644 index a1c8cd2..0000000 --- a/App.Core/Models/ConfigModel.cs +++ /dev/null @@ -1,15 +0,0 @@ -using App.Core.Services; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Configuration; - -namespace App.Core.Models -{ - public class ConfigModel - { - - } -} diff --git a/App.Core/Models/CopyModel.cs b/App.Core/Models/CopyModel.cs index f4d3307..7925634 100644 --- a/App.Core/Models/CopyModel.cs +++ b/App.Core/Models/CopyModel.cs @@ -1,11 +1,14 @@  +using System.ComponentModel; + namespace App.Core.Models { - public class CopyModel + public class CopyModel : INotifyPropertyChanged { public string SourcePath { get; set; } = string.Empty; // Path of the source file public string TargetPath { get; set; } = string.Empty; // Path of the target file + public event PropertyChangedEventHandler? PropertyChanged; } } diff --git a/App.Core/Models/LoggerModel.cs b/App.Core/Models/LoggerModel.cs index ca60ee8..2599988 100644 --- a/App.Core/Models/LoggerModel.cs +++ b/App.Core/Models/LoggerModel.cs @@ -1,6 +1,8 @@ -namespace App.Core.Models +using System.ComponentModel; + +namespace App.Core.Models { - public class LoggerModel + public class LoggerModel : INotifyPropertyChanged { public string Name { get; set; } = string.Empty; // Name of the save public string FileSource { get; set; } = string.Empty; // Path of the source file @@ -9,5 +11,7 @@ public class LoggerModel public string FileTransferTime { get; set; } = string.Empty; // Time of the transfer public string FileEncryptionTime { get; set; } = string.Empty; // Time of the encryption public DateTime Time { get; set; } = DateTime.Now; // Date of the save + + public event PropertyChangedEventHandler? PropertyChanged; } } diff --git a/App.Core/Models/SaveModel.cs b/App.Core/Models/SaveModel.cs index ec17d61..366918a 100644 --- a/App.Core/Models/SaveModel.cs +++ b/App.Core/Models/SaveModel.cs @@ -1,12 +1,37 @@ -namespace App.Core.Models +using System; +using System.ComponentModel; + +namespace App.Core.Models { - public class SaveModel + public class SaveModel : INotifyPropertyChanged { - public string InPath { get; set; } = ""; // Path of the source file - public string OutPath { get; set; } = ""; // Path of the target file - public string Type { get; set; } = ""; // Type of the save // false = Complete, true = Sequentiel - public string SaveName { get; set; } = "" ; // Name of the save + private int _percentage; + + public string InPath { get; set; } = ""; // Path of the source file + public string OutPath { get; set; } = ""; // Path of the target file + public string Type { get; set; } = ""; // Type of the save (false = Complete, true = Sequential) + public string SaveName { get; set; } = ""; // Name of the save public string EncryptChoice { get; set; } = ""; - public DateTime Date { get; } = DateTime.Now; // Date of the save + public DateTime Date { get; } = DateTime.Now; // Date of the save + + public float percentage + { + get { return _percentage; } + set + { + if (_percentage != value) + { + _percentage = (int)value; + OnPropertyChanged(nameof(percentage)); + } + } + } + + public event PropertyChangedEventHandler? PropertyChanged; + + protected virtual void OnPropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } } } diff --git a/App.Core/Models/StateManagerModel.cs b/App.Core/Models/StateManagerModel.cs index d32e3c7..3e1c3c5 100644 --- a/App.Core/Models/StateManagerModel.cs +++ b/App.Core/Models/StateManagerModel.cs @@ -1,7 +1,9 @@ -namespace App.Core.Models +using System.ComponentModel; + +namespace App.Core.Models { - public class StateManagerModel + public class StateManagerModel : INotifyPropertyChanged { public string SaveName { get; set; } = string.Empty; // Name of the save public string SourceFilePath { get; set; } = string.Empty; // Path of the source file @@ -12,5 +14,6 @@ public class StateManagerModel public long NbFilesLeftToDo { get; set; } = 0; // Number of files left to copy public float Progression { get; set; } = 0; // Progression of the save + public event PropertyChangedEventHandler? PropertyChanged; } } diff --git a/App.Core/Services/CopyService.cs b/App.Core/Services/CopyService.cs index c6e05ca..d9a4fa3 100644 --- a/App.Core/Services/CopyService.cs +++ b/App.Core/Services/CopyService.cs @@ -1,62 +1,58 @@ using App.Core.Models; using System.Diagnostics; +using System.Drawing; using System.IO; using System.Threading; namespace App.Core.Services { - public class CopyService + public class CopyService { public LoggerService loggerService = new(); public StateManagerService stateManagerService = new(); - private bool isStopped; - private bool isPaused; public bool isEncrypted; - private long totalFile = 0; - private long totalSize = 0; - private float progress =0; + private readonly object locker = new(); public CopyModel CopyModel { get; set; } + public event EventHandler? BackupStarted; + public event EventHandler? BackupCompleted; + + + public CopyService() { this.CopyModel = new(); } - public CopyService(StateManagerService stateManagerService) - { - this.CopyModel = new(); - this.stateManagerService = stateManagerService; - } - public void ExecuteCopy(SaveModel saveModel) + public void ExecuteCopy(SaveModel saveModel, StreamWriter logWriter, StreamWriter stateWriter) { - isPaused = false; - isStopped = false; - totalFile = 0; - totalSize = 0; - ProcessCopy(saveModel); + + Thread thread = new Thread(() => + { + OnBackupStarted(saveModel); + BackupDirectory(saveModel.InPath, saveModel.OutPath, logWriter, stateWriter); + OnBackupCompleted(saveModel); + }); + thread.Start(); + } - public void PauseCopy(SaveModel saveModel) + public void PauseCopy() { - isPaused = true; - // Implement any necessary logic for pausing the copying process } - public void StopCopy(SaveModel saveModel) + public void ResumeCopy() { - isStopped = true; - // Implement any necessary logic for stopping the copying process + } - public void ResumeCopy(SaveModel saveModel) + public void StopCopy() { - isPaused = false; - // Implement any necessary logic for resuming the copying process - ProcessCopy(saveModel); } + private void EncryptFile(string sourcePath) { string additionalArgument = "abcabcab"; @@ -69,138 +65,395 @@ private void EncryptFile(string sourcePath) Process.Start(startInfo); } - - private void ProcessCopy(SaveModel saveModel) + void BackupDirectory(string sourceDirPath, string targetDirPath, StreamWriter logWriter, StreamWriter stateWriter) { - if (isPaused || isStopped) - return; + while (true) + { // Wait until manualReset is set - foreach (var item in Directory.GetFiles(this.CopyModel.SourcePath, "*", SearchOption.AllDirectories)) - { - totalFile += 1; - totalSize += new FileInfo(item).Length; - } - - foreach (StateManagerModel stateModel in stateManagerService.listStateModel!) - { - if (stateModel.SaveName == saveModel.SaveName) + int TotalFailed = 0; + // Stage 1: Create the destination folder + if (!Directory.Exists(targetDirPath)) { - - stateModel.TotalFilesToCopy += totalFile; - stateModel.NbFilesLeftToDo = totalFile; - stateModel.TotalFilesSize = totalSize; - stateModel.Progression = 100 - ((stateModel.NbFilesLeftToDo / totalFile) * 100); - progress = stateModel.Progression; - stateModel.State = "ACTIVE"; - stateManagerService.UpdateStateFile(); - - if (File.Exists(this.CopyModel.SourcePath)) + try { - // File copying operation - - stateModel.SourceFilePath = this.CopyModel.SourcePath; - stateModel.TargetFilePath = this.CopyModel.TargetPath; - stateManagerService.UpdateStateFile(); - - + Directory.CreateDirectory(targetDirPath); + logWriter.WriteLine($"Create folder: {targetDirPath}"); + } + catch (Exception ex) + { + // Cannot create folder + stateWriter.WriteLine($"Failed to create folder: {targetDirPath}\r\nAccess Denied\r\n"); + return; + } + } - File.Copy(this.CopyModel.SourcePath, this.CopyModel.TargetPath, true); - stateModel.Progression = 100 - ((stateModel.NbFilesLeftToDo / totalFile) * 100); - progress = stateModel.Progression; - stateModel.NbFilesLeftToDo = stateModel.NbFilesLeftToDo > 0 ? stateModel.NbFilesLeftToDo - 1 : 0; + // Stage 2: Get all files from the source folder + string[] files = null; + try + { + files = Directory.GetFiles(sourceDirPath); + } + catch (UnauthorizedAccessException) + { + // Access denied, cannot read folder or files + stateWriter.WriteLine($"{sourceDirPath}\r\nAccess Denied\r\n"); + } + catch (Exception e) + { + // Other unknown read errors + stateWriter.WriteLine($"{sourceDirPath}\r\n{e.Message}\r\n"); + } - stateManagerService.UpdateStateFile(); + // Stage 3: Copy all files from source to destination folder + if (files != null && files.Length > 0) + { + foreach (string file in files) + { + try + { + string name = Path.GetFileName(file); + string dest = Path.Combine(targetDirPath, name); + + File.Copy(file, dest, true); + } + catch (UnauthorizedAccessException) + { + // Access denied, cannot write file + stateWriter.WriteLine($"{file}\r\nAccess Denied\r\n"); + TotalFailed++; + } + catch (Exception e) + { + // Other unknown error + TotalFailed++; + stateWriter.WriteLine($"{file}\r\n{e.Message}\r\n"); + } + } + } - loggerService!.loggerModel!.Name = saveModel.SaveName; - loggerService.loggerModel.FileSource = this.CopyModel.SourcePath; - loggerService.loggerModel.FileTarget = this.CopyModel.TargetPath; - loggerService.loggerModel.FileSize = new FileInfo(this.CopyModel.SourcePath).Length.ToString(); - loggerService.AddEntryLog(); + // Stage 4: Get all sub-folders + string[] folders = null; + try + { + folders = Directory.GetDirectories(sourceDirPath); + } + catch (UnauthorizedAccessException) + { + // Access denied, cannot read folders + stateWriter.WriteLine($"{sourceDirPath}\r\nAccess denied\r\n"); + } + catch (Exception e) + { + // Other unknown read errors + stateWriter.WriteLine($"{sourceDirPath}\r\nAccess {e.Message}\r\n"); + } - } - else if (Directory.Exists(this.CopyModel.SourcePath)) + // Stage 5: Backup files and "sub-sub-folders" in the sub-folder + if (folders != null && folders.Length > 0) + { + foreach (string folder in folders) { - // Directory copying operation - CopyDirectory(this.CopyModel.SourcePath, this.CopyModel.TargetPath, stateModel); + try + { + string name = Path.GetFileName(folder); + string dest = Path.Combine(targetDirPath, name); + + // recursive call with updated source and target paths + BackupDirectory(folder, dest, logWriter, stateWriter); + } + catch (UnauthorizedAccessException) + { + // Access denied, cannot read folders + stateWriter.WriteLine($"{folder}\r\nAccess denied\r\n"); + } + catch (Exception e) + { + // Other unknown read errors + stateWriter.WriteLine($"{targetDirPath}\r\nAccess {e.Message}\r\n"); + } } - else - { - // Log the error and handle it gracefully - loggerService!.loggerModel!.Name = saveModel.SaveName; - loggerService.AddEntryLog(); - } - - + } - stateModel.State = "END"; - stateManagerService.UpdateStateFile(); + // Perform encryption if required + if (this.isEncrypted) + { + EncryptFile(this.CopyModel.TargetPath); } + + } - - - if (isEncrypted) EncryptFile(this.CopyModel.TargetPath); - - } - private void CopyDirectory(string sourceDirPath, string targetDirPath, StateManagerModel stateModel) - { - - // Vérifie si le répertoire source existe - if (!Directory.Exists(sourceDirPath)) + //public void CompleteSave(string inputpathsave, string inputDestToSave, bool copyDir, bool verif) //Function for full folder backup + //{ + // StateManagerModel stateModel = new StateManagerModel(); + // stateModel.State = "ACTIVE"; + // Stopwatch stopwatch = new Stopwatch(); + // Stopwatch cryptwatch = new Stopwatch(); + // stopwatch.Start(); //Starting the timed for the log file + + // DirectoryInfo dir = new DirectoryInfo(inputpathsave); // Get the subdirectories for the specified directory. + + // if (!dir.Exists) //Check if the file is present + // { + // throw new DirectoryNotFoundException("ERROR 404 : Directory Not Found ! " + inputpathsave); + // } + + // DirectoryInfo[] dirs = dir.GetDirectories(); + // Directory.CreateDirectory(inputDestToSave); // If the destination directory doesn't exist, create it. + + // FileInfo[] files = dir.GetFiles(); // Get the files in the directory and copy them to the new location. + + // if (!verif) // Check for the status file if it needs to reset the variables + // { + // TotalSize = 0; + // nbfilesmax = 0; + // size = 0; + // nbfiles = 0; + // progs = 0; + + // foreach (FileInfo file in files) // Loop to allow calculation of files and folder size + // { + // TotalSize += file.Length; + // nbfilesmax++; + // } + // foreach (DirectoryInfo subdir in dirs) // Loop to allow calculation of subfiles and subfolder size + // { + // FileInfo[] Maxfiles = subdir.GetFiles(); + // foreach (FileInfo file in Maxfiles) + // { + // TotalSize += file.Length; + // nbfilesmax++; + // } + // } + + // } + + // Loop that allows to copy the files to make the backup + // foreach (FileInfo file in files) + // { + // if (this.button_pause == true) + // { + // MessageBox.Show("test"); + // } + // if (this.button_stop == true) + // { + // Thread.ResetAbort(); + // } + + // string tempPath = Path.Combine(inputDestToSave, file.Name); + + // if (size > 0) + // { + // progs = ((float)size / TotalSize) * 100; + // } + + // Systems which allows to insert the values ​​of each file in the report file. + // DataState.SourceFile = Path.Combine(inputpathsave, file.Name); + // DataState.TargetFile = tempPath; + // DataState.TotalSize = nbfilesmax; + // DataState.TotalFile = TotalSize; + // DataState.TotalSizeRest = TotalSize - size; + // DataState.FileRest = nbfilesmax - nbfiles; + // DataState.Progress = progs; + // UpdateStatefile(); //Call of the function to start the state file system + + // if (PriorityExt(Path.GetExtension(file.Name))) + // { + // if (CryptExt(Path.GetExtension(file.Name))) + // { + // cryptwatch.Start(); + // Encrypt(DataState.SourceFile, tempPath); + // cryptwatch.Stop(); + // } + // else + // { + // file.CopyTo(tempPath, true); //Function that allows you to copy the file to its new folder. + // } + + // } + // else + // { + // if (CryptExt(Path.GetExtension(file.Name))) + // { + // cryptwatch.Start(); + // Encrypt(DataState.SourceFile, tempPath); + // cryptwatch.Stop(); + // } + // else + // { + // file.CopyTo(tempPath, true); //Function that allows you to copy the file to its new folder. + // } + // } + + // nbfiles++; + // size += file.Length; + + // } + + // If copying subdirectories, copy them and their contents to new location. + // if (copyDir) + // { + // foreach (DirectoryInfo subdir in dirs) + // { + // string tempPath = Path.Combine(inputDestToSave, subdir.Name); + // CompleteSave(subdir.FullName, tempPath, copyDir, true); + // } + // } + // System which allows the values ​​to be reset to 0 at the end of the backup + // DataState.TotalSize = TotalSize; + // DataState.SourceFile = null; + // DataState.TargetFile = null; + // DataState.TotalFile = 0; + // DataState.TotalSize = 0; + // DataState.TotalSizeRest = 0; + // DataState.FileRest = 0; + // DataState.Progress = 0; + // DataState.SaveState = false; + + // UpdateStatefile(); //Call of the function to start the state file system + + // stopwatch.Stop(); //Stop the stopwatch + // cryptwatch.Stop(); + // this.TimeTransfert = stopwatch.Elapsed; // Transfer of the chrono time to the variable + // this.CryptTransfert = cryptwatch.Elapsed; + //} + + //public void DifferentialSave(string pathA, string pathB, string pathC) // Function that allows you to make a differential backup + //{ + // DataState = new DataState(NameStateFile); //Instattation of the method + // Stopwatch stopwatch = new Stopwatch(); // Instattation of the method + // Stopwatch cryptwatch = new Stopwatch(); + // stopwatch.Start(); //Starting the stopwatch + + // DataState.SaveState = true; + // TotalSize = 0; + // nbfilesmax = 0; + + // System.IO.DirectoryInfo dir1 = new System.IO.DirectoryInfo(pathA); + // System.IO.DirectoryInfo dir2 = new System.IO.DirectoryInfo(pathB); + + // Take a snapshot of the file system. + // IEnumerable list1 = dir1.GetFiles("*.*", System.IO.SearchOption.AllDirectories); + // IEnumerable list2 = dir2.GetFiles("*.*", System.IO.SearchOption.AllDirectories); + + // A custom file comparer defined below + // FileCompare myFileCompare = new FileCompare(); + + // var queryList1Only = (from file in list1 select file).Except(list2, myFileCompare); + // size = 0; + // nbfiles = 0; + // progs = 0; + + // foreach (var v in queryList1Only) + // { + // TotalSize += v.Length; + // nbfilesmax++; + + // } + + // Loop that allows the backup of different files + // foreach (var v in queryList1Only) + // { + // string tempPath = Path.Combine(pathC, v.Name); + // Systems which allows to insert the values ​​of each file in the report file. + // DataState.SourceFile = Path.Combine(pathA, v.Name); + // DataState.TargetFile = tempPath; + // DataState.TotalSize = nbfilesmax; + // DataState.TotalFile = TotalSize; + // DataState.TotalSizeRest = TotalSize - size; + // DataState.FileRest = nbfilesmax - nbfiles; + // DataState.Progress = progs; + + // UpdateStatefile();//Call of the function to start the state file system + + // if (PriorityExt(Path.GetExtension(v.Name))) + // { + // if (CryptExt(Path.GetExtension(v.Name))) + // { + // cryptwatch.Start(); + // Encrypt(DataState.SourceFile, tempPath); + // cryptwatch.Stop(); + // } + // else + // { + // v.CopyTo(tempPath, true); //Function that allows you to copy the file to its new folder. + // } + // } + // else + // { + // if (CryptExt(Path.GetExtension(v.Name))) + // { + // cryptwatch.Start(); + // Encrypt(DataState.SourceFile, tempPath); + // cryptwatch.Stop(); + // } + // else + // { + // v.CopyTo(tempPath, true); //Function that allows you to copy the file to its new folder. + // } + // } + + // size += v.Length; + // nbfiles++; + // } + + // System which allows the values ​​to be reset to 0 at the end of the backup + // DataState.SourceFile = null; + // DataState.TargetFile = null; + // DataState.TotalFile = 0; + // DataState.TotalSize = 0; + // DataState.TotalSizeRest = 0; + // DataState.FileRest = 0; + // DataState.Progress = 0; + // DataState.SaveState = false; + // UpdateStatefile();//Call of the function to start the state file system + + // stopwatch.Stop(); //Stop the stopwatch + // this.TimeTransfert = stopwatch.Elapsed; // Transfer of the chrono time to the variable + // this.CryptTransfert = cryptwatch.Elapsed; + //} + + + + + + + protected void OnBackupStarted(SaveModel save) + { + BackupStarted?.Invoke(this, new BackupEventArgs { - Console.WriteLine("Le répertoire source n'existe pas."); - return; - } + SourcePath = save.InPath, + TargetPath = save.OutPath, + StartTime = DateTime.Now + }); + } - // Crée le répertoire cible s'il n'existe pas encore - if (!Directory.Exists(targetDirPath)) + protected void OnBackupCompleted(SaveModel save) + { + BackupCompleted?.Invoke(this, new BackupEventArgs { - Directory.CreateDirectory(targetDirPath); - } + SourcePath = save.InPath, + TargetPath = save.OutPath, + EndTime = DateTime.Now + }); + } + } - // Obtient la liste des fichiers et des sous-répertoires dans le répertoire source - string[] files = Directory.GetFiles(sourceDirPath); - string[] subdirectories = Directory.GetDirectories(sourceDirPath); - - // Copie les fichiers - foreach (string filePath in files) - { - string fileName = Path.GetFileName(filePath); - string targetFilePath = Path.Combine(targetDirPath, fileName); - stateModel.SourceFilePath = filePath; - stateModel.TargetFilePath = targetFilePath; - - stateManagerService.UpdateStateFile(); - - DateTime start = DateTime.Now; - File.Copy(filePath, targetFilePath, true); // Le paramètre true permet d'écraser le fichier s'il existe déjà dans le répertoire cible - stateModel.NbFilesLeftToDo = stateModel.NbFilesLeftToDo > 0 ? stateModel.NbFilesLeftToDo - 1 : 0; - start = DateTime.Now; - - loggerService!.loggerModel!.FileEncryptionTime = (DateTime.Now - start).ToString(); - - stateManagerService.UpdateStateFile(); - loggerService!.loggerModel!.Name = stateModel.SaveName; - loggerService!.loggerModel!.FileSource = filePath; - loggerService!.loggerModel.FileTarget = targetFilePath; - loggerService!.loggerModel.FileSize = new FileInfo(filePath).Length.ToString(); - loggerService!.loggerModel.FileTransferTime = (DateTime.Now - start).ToString(); - loggerService.AddEntryLog(); - } + +} - // Copie les sous-répertoires récursivement - foreach (string subdirectory in subdirectories) - { - string subdirectoryName = Path.GetFileName(subdirectory); - string targetSubdirectoryPath = Path.Combine(targetDirPath, subdirectoryName); - CopyDirectory(subdirectory, targetSubdirectoryPath, stateModel); // Appel récursif pour copier les sous-répertoires - } - } - } +public class BackupEventArgs : EventArgs +{ + public string SourcePath { get; set; } + public string TargetPath { get; set; } + public DateTime StartTime { get; set; } + public DateTime EndTime { get; set; } } + + diff --git a/App.Core/Services/LoggerService.cs b/App.Core/Services/LoggerService.cs index de31b5c..09471c6 100644 --- a/App.Core/Services/LoggerService.cs +++ b/App.Core/Services/LoggerService.cs @@ -1,4 +1,5 @@ -using System.Text.Json; +using System.Reflection.Metadata.Ecma335; +using System.Text.Json; using System.Xml.Serialization; using App.Core.Models; using static System.Runtime.InteropServices.JavaScript.JSType; @@ -21,40 +22,6 @@ public LoggerService() loggerModel = new(); } - - //public void WriteLog() - //{ - // //TODO : Gerer les exeptions - - // try - // { - // // Serialize the log model to JSON - - // string logEntry = JsonSerializer.Serialize(loggerModel, options) + ","; - // string jsonlogEntry = JsonSerializer.Serialize(loggerModel, options) + ","; - // // Append the log entry to the log file or create if not exist - // using StreamWriter LogWriter = File.AppendText(jsonlogFilePath); - // LogWriter.WriteLineAsync(jsonlogEntry); - - // // Serialize the log model to XML - // using StringWriter xmlStringWriter = new(); - // XmlSerializer xmlSerializer = new(typeof(loggerModel)); - // xmlSerializer.Serialize(xmlStringWriter, loggerModel); - // string xmlLogEntry = xmlStringWriter.ToString(); - // // Append the XML log entry to the XML log file or create if not exist - - // using StreamWriter xmlLogWriter = File.AppendText(xmlLogFilePath); - // xmlLogWriter.WriteLineAsync(xmlLogEntry); - // } - // catch (Exception ex) - // { - // Console.WriteLine($"Error writing to log file: {ex.Message}"); - - // } - //} - /// - /// Method to open the log file - /// public void OpenLogFile() { // Open the log file in notepad @@ -73,14 +40,22 @@ public void CreateLogFile() File.WriteAllText(jsonlogFilePath, "[]"); } - public void AddEntryLog() + public string GetLogFormat() + { + if (configService.LogsFormat == "JSON") return jsonlogFilePath; + else return xmlLogFilePath; + } + + public void AddEntryLog(StreamWriter streamWriter) { if (configService.LogsFormat == "JSON") { try { - using StreamWriter logWriter = File.AppendText(jsonlogFilePath); - logWriter.WriteLineAsync(JsonSerializer.Serialize(loggerModel, options) + ","); + using (streamWriter = File.AppendText(jsonlogFilePath)) ; + { + streamWriter.WriteLineAsync(JsonSerializer.Serialize(loggerModel, options) + ","); + } } catch (InvalidOperationException) { @@ -93,7 +68,7 @@ public void AddEntryLog() { XmlSerializer xmlSerializer = new XmlSerializer(typeof(LoggerModel)); - using (StreamWriter streamWriter = File.AppendText(xmlLogFilePath)) + using (streamWriter = File.AppendText(xmlLogFilePath)) { xmlSerializer.Serialize(streamWriter, loggerModel ); } diff --git a/App.Core/Services/SaveService.cs b/App.Core/Services/SaveService.cs index 960cb24..29cf401 100644 --- a/App.Core/Services/SaveService.cs +++ b/App.Core/Services/SaveService.cs @@ -5,55 +5,260 @@ namespace App.Core.Services { - public class SaveService + public class SaveService : IDisposable { - public required ObservableCollection ListStateManager { get; set; } = []; - public required ObservableCollection ListSaveModel { get; set; } = []; - private readonly ConfigService configService = new(); + public ObservableCollection ListStateManager { get; set; } = []; + public ObservableCollection ListSaveModel { get; set; } = []; + public ManualResetEvent pauseEvent { get; private set; } = new ManualResetEvent(false); + public ManualResetEvent resumeEvent { get; private set; } = new ManualResetEvent(true); + public ManualResetEvent stopEvent { get; private set; } = new ManualResetEvent(false); + + private int progress = 0; + //TODO : Mettre manualResetsEvent et autre event resume + + private readonly StreamWriter? logWriter ; + private readonly StreamWriter? stateWriter; + + private readonly StateManagerService stateManagerService = new(); public CopyService copyService = new(); private readonly JsonSerializerOptions options = new() { WriteIndented = true }; + private Thread saveThread; + private long fileDo =0; + private long fileTotal = 0; + public SaveService() { + //logWriter = new StreamWriter(loggerService.GetLogFormat()); + //stateWriter = new StreamWriter(StateManagerService.stateFilePath); LoadSave(); copyService.stateManagerService.listStateModel = ListStateManager; - copyService.stateManagerService.UpdateStateFile(); + //copyService.stateManagerService.UpdateStateFile(stateWriter); } public bool IsSoftwareRunning() { // Check if the software is running (e.g., "notepad.exe") - Process[] processes = Process.GetProcessesByName(configService.Software); - if (processes.Length > 0) + + Process[] processes = Process.GetProcessesByName("mspaint"); + return processes.Length > 0; + + + } + + public void ExecuteSave(List saveModel, ThreadManagerService threadManagerService) + { + foreach (SaveModel save in saveModel) { - return true; + copyService = new(); + copyService.CopyModel.SourcePath = save.InPath; + copyService.CopyModel.TargetPath = save.OutPath; + copyService.stateManagerService.listStateModel = ListStateManager; + + // Start copying process in a separate thread + + + copyService.BackupStarted += (sender, args) =>Console.WriteLine($"Backup started from {args.SourcePath} to {args.TargetPath} at {args.StartTime}"); + + copyService.BackupCompleted += (sender, args) => Console.WriteLine($"Backup completed from {args.SourcePath} to {args.TargetPath} at {args.EndTime}"); + + + Thread thread = new Thread(() => copyService.ExecuteCopy(save, logWriter!, stateWriter!)); + threadManagerService.AddThread(thread); + thread.Start(); + + copyService.BackupStarted -= (sender, args) => Console.WriteLine($"Backup started from {args.SourcePath} to {args.TargetPath} at {args.StartTime}"); + + copyService.BackupCompleted -= (sender, args) =>Console.WriteLine($"Backup completed from {args.SourcePath} to {args.TargetPath} at {args.EndTime}"); + + } - else + } + + public void LaunchSave(SaveModel saveModel) + { + //TODO : Detection logicel Métier + + if (saveModel.Type == "Complete") { - return false; + // Set the resume event to allow it to be resumed later + saveThread = new Thread(() => + { + //resumeEvent.Set(); + //pauseEvent.Set(); + + stopEvent.Reset(); + fileDo = 0; + CompleteSave(saveModel.InPath, saveModel.OutPath, true, saveModel); + fileDo = fileTotal; + saveModel.percentage = (fileDo * 100 / fileTotal); + }); + + // Start the thread + saveThread.Start(); + } + if (saveModel.Type == "Incremental") + { + //IncrementalSave(saveModel.InPath, saveModel.OutPath, true); + } } - public void ExecuteSave(SaveModel saveModel) + public void PauseSave() { - // Method to execute the copy service - // Execute the copy service - copyService.CopyModel.SourcePath = saveModel.InPath; - copyService.CopyModel.TargetPath = saveModel.OutPath; - copyService.stateManagerService.listStateModel = ListStateManager; - copyService.ExecuteCopy(saveModel); + pauseEvent.Set(); // Reset the pause event to block threads + resumeEvent.Reset(); // Set the resume event to allow it to be resumed later + } + + public void StopSave() + { + fileDo = 0; + stopEvent.Set(); // Signal the stop event to stop the save operation + } + public void ResumeSave() + { + pauseEvent.Reset(); // Signal the pause event to resume the save operation + resumeEvent.Set(); // Reset the resume event to block it until it's signaled again } - public void LoadSave() + private bool CompleteSave(string InPath, string OutPath, bool verif, SaveModel saveModel) + { + // DataState = new DataState(NameStateFile); + // this.DataState.SaveState = true; + + // Wait for pauseEvent to be signaled before proceeding + pauseEvent.WaitOne(0); + + while (IsSoftwareRunning() && !stopEvent.WaitOne(0)) + { + // Software is running, wait for it to close + Thread.Sleep(1000); + // Display message box to inform the user that the software is still running + } + + if (stopEvent.WaitOne(0)) + { + // Stop event has been signaled, return false to indicate incomplete save + return false; + } + + // Implement the logic with the event resume, pause, and stop + + // Wait for resumeEvent to be signaled before continuing + resumeEvent.WaitOne(); + + fileTotal += Directory.GetFiles(InPath).Length; + + // Recursively count files in subdirectories + + fileTotal += CountFiles(InPath); + + StateManagerModel stateModel = new() + { + SaveName = saveModel.SaveName, + State = "END" + }; + + foreach (StateManagerModel item in ListStateManager) + { + if (item.SaveName == stateModel.SaveName) + { + stateModel = item; + } + } + + long TotalSize = 0; + long nbfilesmax = 0; + long size = 0; + long nbfiles = 0; + + Stopwatch stopwatch = new Stopwatch(); + stopwatch.Start(); // Starting the timed for the log file + + DirectoryInfo dir = new DirectoryInfo(InPath); // Get the subdirectories for the specified directory. + + if (!dir.Exists) // Check if the file is present + { + throw new DirectoryNotFoundException("ERROR 404 : Directory Not Found ! " + InPath); + } + + DirectoryInfo[] dirs = dir.GetDirectories(); + Directory.CreateDirectory(OutPath); // If the destination directory doesn't exist, create it. + + FileInfo[] files = dir.GetFiles(); // Get the files in the directory and copy them to the new location. + if (verif) // Check for the status file if it needs to reset the variables + { + TotalSize = 0; + nbfilesmax = 0; + size = 0; + nbfiles = 0; + + foreach (FileInfo file in files) // Loop to allow calculation of files and folder size + { + TotalSize += file.Length; + nbfilesmax++; + } + foreach (DirectoryInfo subdir in dirs) // Loop to allow calculation of subfiles and subfolder size + { + FileInfo[] Maxfiles = subdir.GetFiles(); + foreach (FileInfo file in Maxfiles) + { + TotalSize += file.Length; + nbfilesmax++; + } + } + + } + + // Loop that allows to copy the files to make the backup + foreach (FileInfo file in files) + { + string tempPath = Path.Combine(OutPath, file.Name); + + stateModel.SourceFilePath = Path.Combine(OutPath, file.Name); + stateModel.TargetFilePath = tempPath; + stateModel.TotalFilesToCopy = nbfilesmax; + stateModel.TotalFilesSize = TotalSize; + stateModel.NbFilesLeftToDo = nbfilesmax - nbfiles; + stateModel.State = "IN PROGRESS"; + + stateManagerService.UpdateStateFile(ListStateManager); + + // Systems which allows to insert the values of each file in the report file. + + file.CopyTo(tempPath, true); // Function that allows you to copy the file to its new folder. + nbfiles++; + fileDo+= nbfiles; + size += file.Length; + saveModel.percentage = (int)((fileDo * 100) / fileTotal); + + // Calculate the global percentage of execution and store it in saveModel.percentage + + } + + // If copying subdirectories, copy them and their contents to new location. + + foreach (DirectoryInfo subdir in dirs) + { + string tempPath = Path.Combine(OutPath, subdir.Name); + CompleteSave(subdir.FullName, tempPath, true, saveModel); + } + + stopwatch.Stop(); // Stop the stopwatch + return false; + } + + + public ObservableCollection LoadSave() { if (File.Exists("saves.json")) @@ -78,27 +283,21 @@ public void LoadSave() File.WriteAllText("saves.json", "[]"); } + return ListSaveModel; + } - /// - /// Show info of a save - /// - /// - /// public Tuple ShowInfo(SaveModel saveModel) { return Tuple.Create(saveModel.SaveName, saveModel.InPath, saveModel.OutPath, saveModel.Type, saveModel.Date); } - - - - public bool CreateSave(string inPath, string outPath, string type, string saveName) + public bool CreateSave(SaveModel saveModel) { try { - ListSaveModel.Add(new SaveModel { InPath = inPath, OutPath = outPath, Type = type, SaveName = saveName}); - ListStateManager.Add(new StateManagerModel { SaveName = saveName, SourceFilePath = inPath, TargetFilePath = outPath }); + ListSaveModel.Add(saveModel); + ListStateManager.Add(new StateManagerModel { SaveName = saveModel.SaveName, SourceFilePath = saveModel.InPath, TargetFilePath = saveModel.OutPath }); File.WriteAllText("saves.json", JsonSerializer.Serialize(ListSaveModel, options)); return true; } @@ -107,16 +306,35 @@ public bool CreateSave(string inPath, string outPath, string type, string saveNa return false; } } - - + public void DeleteSave(SaveModel saveModel) { ListSaveModel.Remove(saveModel); } - + public void Dispose() + { + logWriter?.Dispose(); + stateWriter?.Dispose(); + } + + public int CountFiles(string directoryPath) + { + int fileCount = 0; + + // Count files in the current directory + fileCount += Directory.GetFiles(directoryPath).Length; + + // Recursively count files in subdirectories + foreach (string subDirectory in Directory.GetDirectories(directoryPath)) + { + fileCount += CountFiles(subDirectory); + } + + return fileCount; + } } } diff --git a/App.Core/Services/StateManagerService.cs b/App.Core/Services/StateManagerService.cs index 8a89083..4689d80 100644 --- a/App.Core/Services/StateManagerService.cs +++ b/App.Core/Services/StateManagerService.cs @@ -1,4 +1,5 @@ using App.Core.Models; +using Newtonsoft.Json; using System.Collections.ObjectModel; using System.Text.Json; @@ -6,16 +7,11 @@ namespace App.Core.Services { public class StateManagerService { - + public ObservableCollection? listStateModel; - private readonly string stateFilePath = "state.json"; - + public static readonly string stateFilePath = "state.json"; - //Options for the JsonSerializer - private readonly JsonSerializerOptions options = new() - { - WriteIndented = true - }; + private static Mutex mut = new(); public StateManagerService() @@ -23,7 +19,7 @@ public StateManagerService() //Create the state file if it does not exist if (!File.Exists(stateFilePath)) { - CreateStateFile(); + //CreateStateFile(); } //UpdateStateFile(); @@ -35,34 +31,42 @@ public void OpenStateFile() System.Diagnostics.Process.Start("notepad.exe", stateFilePath); } - public void UpdateStateFile() + + public void UpdateStateFile(ObservableCollection stateManagerModels) { - // Clear the state file - ClearStateFile(); - int i = 0; - foreach (StateManagerModel stateModel in listStateModel!) + //TODO : Voir les states files + mut.WaitOne(); + try { - using (StreamWriter stateWriter = File.AppendText(stateFilePath)) + ClearStateFile(); + // Open the file for writing (append mode) + StreamWriter? streamWriter = null; + using (streamWriter = File.AppendText(stateFilePath)) { - stateWriter.WriteLineAsync(JsonSerializer.Serialize(stateModel, options) + ","); + foreach (StateManagerModel stateModel in stateManagerModels!) + { + // Write the serialized stateModel to the file + streamWriter.WriteLineAsync(JsonConvert.SerializeObject(stateModel, Formatting.Indented) + Environment.NewLine); + } } - //Increment the index to get the next save name - i += 1; + streamWriter?.Dispose(); } + catch (IOException ex) + { + // Handle the exception (e.g., log or retry) + Console.WriteLine($"Error updating state file: {ex.Message}"); + } + mut.ReleaseMutex(); } - public void CreateStateFile() - { - // Create the state file - File.WriteAllText(stateFilePath, "[]"); - } public void ClearStateFile() { // Clear the state file - File.WriteAllText(stateFilePath, ""); + File.WriteAllText(stateFilePath, "") ; } + } } diff --git a/App.Core/Services/ThreadManagerService.cs b/App.Core/Services/ThreadManagerService.cs new file mode 100644 index 0000000..1af7141 --- /dev/null +++ b/App.Core/Services/ThreadManagerService.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using System.Threading; + +namespace App.Core.Services +{ + public class ThreadManagerService + { + private List runningThreads = new List(); + + public void AddThread(Thread thread) + { + + runningThreads.Add(thread); + + } + + public void RemoveThread(Thread thread) + { + runningThreads.Remove(thread); + } + + public bool AreThreadsRunning(int threadNumber) + { + if (runningThreads.Count == 0 || threadNumber >= runningThreads.Count) + { + return false; + } + + try + { + Console.WriteLine($"Thread {runningThreads[threadNumber].ThreadState}"); + return runningThreads[threadNumber].ThreadState == ThreadState.Running; + } + catch (System.Exception) + { + return false; + } + } + + } +} diff --git a/WpfApp/MainWindow.xaml b/WpfApp/MainWindow.xaml index 8011f17..fda4c68 100644 --- a/WpfApp/MainWindow.xaml +++ b/WpfApp/MainWindow.xaml @@ -3,34 +3,105 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:local="clr-namespace:WpfApp.Views" + xmlns:local="clr-namespace:WpfApp.ViewModels" mc:Ignorable="d" Title="EasySave" Height="475" Width="800" MinHeight="475" MinWidth="800"> + + + + - + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + - - - + + + + + + + public partial class MainWindow : Window { + private readonly MainViewModel? viewModel; + public ObservableCollection Saves { get; set; } = new ObservableCollection(); + public MainWindow() { InitializeComponent(); + viewModel = new MainViewModel(); + List_Save.Items.Clear(); + LoadSave(); + List_Save.ItemsSource = this.Saves; + } + + private void LoadSave() + { + this.Saves = viewModel!.saves; + } + + private void addSave_Click(object sender, RoutedEventArgs e) + { + SaveModel save = new SaveModel + { + SaveName = SaveName.Text, + InPath = SourceName.Text, + OutPath = DestinationName.Text, + Type = IsComplete.IsChecked != null && (bool)IsComplete.IsChecked ? "Complete" : "Incremental", + EncryptChoice = IsEncrypted.IsChecked != null && (bool)IsEncrypted.IsChecked ? "True" : "False" + }; + try + { + if (string.IsNullOrEmpty(SaveName.Text) || SourceName.Text == "" || DestinationName.Text == "" || Destination.Text == "Destination" || Source.Text == "Source" ) + { + MessageBox.Show("Please fill in all the fields"); + return; + } + + viewModel!.AddSave(save); + MessageBox.Show("Save added successfully"); + } + catch + { + // TODO : Handle exception + } + } + + private void SourcePopup_Click(object sender, RoutedEventArgs e) + { + OpenFolderDialog dialog = new OpenFolderDialog(); //Declaration of the method to open the window to choose the folder path. + dialog.DefaultDirectory = ""; + if ((bool)dialog.ShowDialog()) + { + SourceName.Text = dialog.FolderName; + } + + + } + + private void DestinationPopup_Click(object sender, RoutedEventArgs e) + { + OpenFolderDialog dialog = new OpenFolderDialog(); //Declaration of the method to open the window to choose the folder path. + dialog.DefaultDirectory = ""; + if ((bool)dialog.ShowDialog()) + { + DestinationName.Text = dialog.FolderName; + } + } + + private void StartSave_Click(object sender, RoutedEventArgs e) + { + if (List_Save.SelectedItem != null) + { + // Start the save operation asynchronously + var selectedItem = (SaveModel)List_Save.SelectedItem; + var row_init = (DataGridRow)List_Save.ItemContainerGenerator.ContainerFromItem(selectedItem); + if (row_init != null) + { + row_init.Background = Brushes.Green; + } + viewModel!.LaunchSave(selectedItem); + + } + else + { + // Handle case where no item is selected + } + } + + + + + + + private void DeleteSave_Click(object sender, RoutedEventArgs e) + { + if (List_Save.SelectedItem != null) + { + // Start the save operation + viewModel!.DeleteSave((SaveModel)List_Save.SelectedItem); + } + } + + private void PlaySave_Click(object sender, RoutedEventArgs e) + { + var selectedItem = (SaveModel)List_Save.SelectedItem; + var row_init = (DataGridRow)List_Save.ItemContainerGenerator.ContainerFromItem(selectedItem); + if (row_init != null) + { + row_init.Background = Brushes.Green; + } + viewModel!.PlaySave(); + } + + private void PauseSave_Click(object sender, RoutedEventArgs e) + { + var selectedItem = (SaveModel)List_Save.SelectedItem; + var row_init = (DataGridRow)List_Save.ItemContainerGenerator.ContainerFromItem(selectedItem); + if (row_init != null) + { + row_init.Background = Brushes.Orange; + } + viewModel!.PauseSave(); + } + + + private void StopSave_Click(object sender, RoutedEventArgs e) + { + var selectedItem = (SaveModel)List_Save.SelectedItem; + var row_init = (DataGridRow)List_Save.ItemContainerGenerator.ContainerFromItem(selectedItem); + if (row_init != null) + { + row_init.Background = Brushes.Red; + } + viewModel!.StopSave(); } } } \ No newline at end of file diff --git a/WpfApp/ViewModels/ListViewModel.cs b/WpfApp/ViewModels/ListViewModel.cs index 00d49fa..8791323 100644 --- a/WpfApp/ViewModels/ListViewModel.cs +++ b/WpfApp/ViewModels/ListViewModel.cs @@ -6,113 +6,111 @@ namespace WpfApp.ViewModels { - class ListViewModel : INotifyPropertyChanged + class ListViewModel { - private SaveModel _selected; - public SaveModel Selected + public ObservableCollection Selected { - get => _selected; + get => Selected; set { - if (_selected != value) + if (Selected != value) { - _selected = value; - OnPropertyChanged(); + Selected = value; } } } - public ObservableCollection listStateManager { get; set; } = new ObservableCollection(); - public ObservableCollection listSaveModel{ get; set; } = new ObservableCollection(); - public ObservableCollection Items { get; set; } = new ObservableCollection(); - - - private SaveService? saveService; - - - public event PropertyChangedEventHandler PropertyChanged; - - public RelayCommand RefreshCommand { get; } - public RelayCommand CreateCommand { get; } - public RelayCommand ExecuteCommand { get; } - public RelayCommand DeleteCommand { get; } - - public ListViewModel() - { - saveService = new() - { - ListStateManager = this.listStateManager, - ListSaveModel = this.listSaveModel - }; - - saveService.LoadSave(); - this.listSaveModel = saveService.ListSaveModel; - this.listStateManager = saveService.ListStateManager; - foreach (var item in listSaveModel) - { - Items.Add(item); - } - RefreshCommand = new RelayCommand(Refresh); - CreateCommand = new RelayCommand(Create); - ExecuteCommand = new RelayCommand(Execute); - DeleteCommand = new RelayCommand(Delete); - - } - - public void Execute() - { - if (Selected != null) - { - Task.Run(() => saveService!.ExecuteSave(Selected)); - } - else - { - // Handle case where no item is selected - } - } - - public void Create() - { - // Create a new instance of SaveModel (assuming SaveModel has a default constructor) - var newSaveModel = new SaveModel(); - - // Add the new SaveModel instance to the Items collection - Items.Add(newSaveModel); - - // Optionally, select the newly added item - newSaveModel = Selected; - - saveService!.CreateSave(newSaveModel.InPath, newSaveModel.OutPath, newSaveModel.Type, newSaveModel.SaveName); - Thread.Sleep(500); - Refresh(); - } - - public void Refresh() - { - Items.Clear(); - foreach (var item in listSaveModel) - { - Items.Add(item); - } - } - - public void Delete() - { - if (Selected != null) - { - saveService!.DeleteSave(Selected); - Refresh(); - } - else - { - // Handle case where no item is selected - } - } - - protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } + //public ObservableCollection listStateManager { get; set; } = new ObservableCollection(); + //public ObservableCollection listSaveModel{ get; set; } = new ObservableCollection(); + //public ObservableCollection Items { get; set; } = new ObservableCollection(); + + + //private SaveService? saveService; + + + //public event PropertyChangedEventHandler PropertyChanged; + + //public RelayCommand RefreshCommand { get; } + //public RelayCommand CreateCommand { get; } + //public RelayCommand ExecuteCommand { get; } + //public RelayCommand DeleteCommand { get; } + + //public ListViewModel() + //{ + // saveService = new() + // { + // ListStateManager = this.listStateManager, + // ListSaveModel = this.listSaveModel + // }; + + // saveService.LoadSave(); + // this.listSaveModel = saveService.ListSaveModel; + // this.listStateManager = saveService.ListStateManager; + // foreach (var item in listSaveModel) + // { + // Items.Add(item); + // } + // RefreshCommand = new RelayCommand(Refresh); + // CreateCommand = new RelayCommand(Create); + // ExecuteCommand = new RelayCommand(Execute); + // DeleteCommand = new RelayCommand(Delete); + + //} + + //public void Execute() + //{ + // if (Selected != null) + // { + // Task.Run(() => saveService!.ExecuteSave(Selected)); + // } + // else + // { + // // Handle case where no item is selected + // } + //} + + //public void Create() + //{ + // // Create a new instance of SaveModel (assuming SaveModel has a default constructor) + // var newSaveModel = new ObservableCollection(); + + // // Add the new SaveModel instance to the Items collection + // Items.Add(newSaveModel); + + // // Optionally, select the newly added item + // newSaveModel = Selected; + + // saveService!.CreateSave(newSaveModel.InPath, newSaveModel.OutPath, newSaveModel.Type, newSaveModel.SaveName); + // Thread.Sleep(500); + // Refresh(); + //} + + //public void Refresh() + //{ + // Items.Clear(); + // foreach (var item in listSaveModel) + // { + // Items.Add(item); + // } + //} + + //public void Delete() + //{ + // if (Selected != null) + // { + // saveService!.DeleteSave(Selected); + // Refresh(); + // } + // else + // { + // // Handle case where no item is selected + // } + //} + + //protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) + //{ + // PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + //} } } diff --git a/WpfApp/ViewModels/MainViewModel.cs b/WpfApp/ViewModels/MainViewModel.cs new file mode 100644 index 0000000..ecc20b9 --- /dev/null +++ b/WpfApp/ViewModels/MainViewModel.cs @@ -0,0 +1,68 @@ +using App.Core.Models; +using App.Core.Services; +using System.Collections.ObjectModel; +using System.Linq; +using System.Windows.Media.Animation; + +namespace WpfApp.ViewModels +{ + public class MainViewModel + { + public readonly ObservableCollection saves = new(); + private readonly SaveService saveService = new(); + private readonly HashSet runningSaves = new(); // HashSet to store the IDs of running saves + public int percentage { get; set; } = 100; + + + + public MainViewModel() + { + saves = saveService.LoadSave(); + } + + public void AddSave(SaveModel save) + { + saveService.CreateSave(save); + } + + + + public void DeleteSave(SaveModel saveModel) + { + saveService.DeleteSave(saveModel); + } + + public void PlaySave() + { + saveService.ResumeSave(); + } + + public void PauseSave() + { + saveService.PauseSave(); + } + + public void StopSave() + { + saveService.StopSave(); + } + + public bool IsSaveRunning(SaveModel saveModel) + { + lock (runningSaves) + { + return runningSaves.Contains(saveModel); // Check if the saveModel instance is in the runningSaves collection + } + } + + public void LaunchSave(SaveModel saveModel) + { + // Vérifiez si la sauvegarde est en cours d'exécution + saveService.LaunchSave(saveModel); + + } + + + + } +} diff --git a/WpfApp/Views/ControlView.xaml b/WpfApp/Views/ControlView.xaml deleted file mode 100644 index 5726ac5..0000000 --- a/WpfApp/Views/ControlView.xaml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - diff --git a/WpfApp/Views/ControlView.xaml.cs b/WpfApp/Views/ControlView.xaml.cs deleted file mode 100644 index 6e8551a..0000000 --- a/WpfApp/Views/ControlView.xaml.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; - -namespace WpfApp.Views -{ - /// - /// Logique d'interaction pour ControlView.xaml - /// - public partial class ControlView : UserControl - { - public ControlView() - { - InitializeComponent(); - } - } -} diff --git a/WpfApp/Views/ListView.xaml b/WpfApp/Views/ListView.xaml deleted file mode 100644 index 26fc407..0000000 --- a/WpfApp/Views/ListView.xaml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WpfApp/Views/MenuView.xaml.cs b/WpfApp/Views/MenuView.xaml.cs deleted file mode 100644 index cce221c..0000000 --- a/WpfApp/Views/MenuView.xaml.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; - -namespace WpfApp.Views -{ - /// - /// Logique d'interaction pour Menu.xaml - /// - public partial class Menu : UserControl - { - public Menu() - { - InitializeComponent(); - } - } -} diff --git a/WpfApp/WpfApp.csproj b/WpfApp/WpfApp.csproj index c6fdd78..7f2af4d 100644 --- a/WpfApp/WpfApp.csproj +++ b/WpfApp/WpfApp.csproj @@ -67,4 +67,8 @@ + + + + diff --git a/WpfApp/WpfApp.csproj.user b/WpfApp/WpfApp.csproj.user index e4c3053..644b0a6 100644 --- a/WpfApp/WpfApp.csproj.user +++ b/WpfApp/WpfApp.csproj.user @@ -6,29 +6,9 @@ Designer - - - Code - - - Code - - - Code - - Designer - - Designer - - - Designer - - - Designer - \ No newline at end of file