diff --git a/SolutionParityChecker.App/SolutionParityChecker.App.csproj b/SolutionParityChecker.App/SolutionParityChecker.App.csproj index 081513a..54cc2ec 100644 --- a/SolutionParityChecker.App/SolutionParityChecker.App.csproj +++ b/SolutionParityChecker.App/SolutionParityChecker.App.csproj @@ -26,4 +26,8 @@ + + + + diff --git a/SolutionParityChecker.App/ViewModels/MainWindowViewModel.cs b/SolutionParityChecker.App/ViewModels/MainWindowViewModel.cs index dac9045..c56147a 100644 --- a/SolutionParityChecker.App/ViewModels/MainWindowViewModel.cs +++ b/SolutionParityChecker.App/ViewModels/MainWindowViewModel.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; using System.IO; using System.Text; using System.Threading; @@ -13,14 +15,37 @@ namespace SolutionParityChecker.App.ViewModels; public partial class MainWindowViewModel : ViewModelBase { - public string SolutionFolderPath { get; set; } = string.Empty; - public string SolutionFilePath { get; set; } = string.Empty; + [ObservableProperty] + private string _solutionFolderPath; + + [ObservableProperty] + private string _solutionFilePath; [ObservableProperty] private string? _fileText; + [ObservableProperty] + private ObservableCollection _parityResults = new ObservableCollection() + { + "Test" + }; + [RelayCommand] - private async Task OpenFile(CancellationToken token) + private async Task ExecuteParityChecker(CancellationToken token) + { + var results = SolutionParityChecker.CompareSolutionAndCSharpProjects( + SolutionFolderPath, + SolutionFilePath + ); + ParityResults.Clear(); + foreach (var result in results) + { + ParityResults.Add(result); + } + } + + [RelayCommand] + private async Task LoadSolutionFile(CancellationToken token) { ErrorMessages?.Clear(); try @@ -29,17 +54,7 @@ public partial class MainWindowViewModel : ViewModelBase if (file is null) return; - // Limit the text file to 1MB so that the demo won't lag. - if ((await file.GetBasicPropertiesAsync()).Size <= 1024 * 1024 * 1) - { - await using var readStream = await file.OpenReadAsync(); - using var reader = new StreamReader(readStream); - FileText = await reader.ReadToEndAsync(token); - } - else - { - throw new Exception("File exceeded 1MB limit."); - } + SolutionFilePath = file.Path.AbsolutePath; } catch (Exception e) { @@ -48,26 +63,16 @@ public partial class MainWindowViewModel : ViewModelBase } [RelayCommand] - private async Task SaveFile() + private async Task LoadSolutionFolder(CancellationToken token) { ErrorMessages?.Clear(); try { - var file = await DoSaveFilePickerAsync(); - if (file is null) + var folder = await DoOpenFolderPickerAsync(); + if (folder is null) return; - // Limit the text file to 1MB so that the demo won't lag. - if (FileText?.Length <= 1024 * 1024 * 1) - { - var stream = new MemoryStream(Encoding.Default.GetBytes((string)FileText)); - await using var writeStream = await file.OpenWriteAsync(); - await stream.CopyToAsync(writeStream); - } - else - { - throw new Exception("File exceeded 1MB limit."); - } + SolutionFolderPath = folder.Path.AbsolutePath; } catch (Exception e) { @@ -98,7 +103,7 @@ public partial class MainWindowViewModel : ViewModelBase return files?.Count >= 1 ? files[0] : null; } - private async Task DoSaveFilePickerAsync() + private async Task DoOpenFolderPickerAsync() { // For learning purposes, we opted to directly get the reference // for StorageProvider APIs here inside the ViewModel. @@ -106,7 +111,7 @@ public partial class MainWindowViewModel : ViewModelBase // For your real-world apps, you should follow the MVVM principles // by making service classes and locating them with DI/IoC. - // See DepInject project for a sample of how to accomplish this. + // See IoCFileOps project for an example of how to accomplish this. if ( Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop @@ -114,8 +119,10 @@ public partial class MainWindowViewModel : ViewModelBase ) throw new NullReferenceException("Missing StorageProvider instance."); - return await provider.SaveFilePickerAsync( - new FilePickerSaveOptions() { Title = "Save Text File" } + var folder = await provider.OpenFolderPickerAsync( + new FolderPickerOpenOptions() { Title = "Open Text File", AllowMultiple = false } ); + + return folder?.Count >= 1 ? folder[0] : null; } } diff --git a/SolutionParityChecker.App/ViewModels/ViewModelBase.cs b/SolutionParityChecker.App/ViewModels/ViewModelBase.cs index ebf744e..f85eddd 100644 --- a/SolutionParityChecker.App/ViewModels/ViewModelBase.cs +++ b/SolutionParityChecker.App/ViewModels/ViewModelBase.cs @@ -9,7 +9,7 @@ public partial class ViewModelBase : ObservableObject { ErrorMessages = new ObservableCollection(); } - - [ObservableProperty] + + [ObservableProperty] private ObservableCollection? _errorMessages; -} \ No newline at end of file +} diff --git a/SolutionParityChecker.App/Views/MainWindow.axaml b/SolutionParityChecker.App/Views/MainWindow.axaml index 639da74..aac9435 100644 --- a/SolutionParityChecker.App/Views/MainWindow.axaml +++ b/SolutionParityChecker.App/Views/MainWindow.axaml @@ -11,18 +11,18 @@ - + Welcome to Avalonia! - - - - + + + - + + diff --git a/SolutionParityChecker.App/Views/MainWindow.axaml.cs b/SolutionParityChecker.App/Views/MainWindow.axaml.cs index 53ebbc5..ca21c9d 100644 --- a/SolutionParityChecker.App/Views/MainWindow.axaml.cs +++ b/SolutionParityChecker.App/Views/MainWindow.axaml.cs @@ -1,5 +1,6 @@ using Avalonia.Controls; using Avalonia.Interactivity; +using SolutionParityChecker.App.ViewModels; namespace SolutionParityChecker.App.Views; @@ -9,14 +10,4 @@ public partial class MainWindow : Window { InitializeComponent(); } - - private void LoadSolutionFolder(object? sender, RoutedEventArgs e) - { - SolutionFolderPath.Text = "Solution folder path"; - } - - private void LoadSolutionFile(object? sender, RoutedEventArgs e) - { - SolutionFilePath.Text = "Solution file path"; - } } diff --git a/SolutionParityChecker/SolutionParityChecker.cs b/SolutionParityChecker/SolutionParityChecker.cs index 2812b75..5f5e338 100644 --- a/SolutionParityChecker/SolutionParityChecker.cs +++ b/SolutionParityChecker/SolutionParityChecker.cs @@ -4,13 +4,26 @@ namespace SolutionParityChecker; public static class SolutionParityChecker { - public static void CompareSolutionAndCSharpProjects( + public static List CompareSolutionAndCSharpProjects( string solutionFolderPath, string solutionFilePath - ) { } + ) + { + var csprojList = RetrieveAllCSharpProjectNamesFromFolder(solutionFolderPath); + var solutionFile = ParseSolutionFileFromPath(solutionFilePath); + ArgumentNullException.ThrowIfNull(solutionFile); + var projectsMissingFromSolution = FindProjectsMissingFromSolution(csprojList, solutionFile); + + return projectsMissingFromSolution; + } public static string[] RetrieveAllCSharpProjectNamesFromFolder(string solutionFolderPath) { + // if solutionFolderPath does not end with a slash, add one + if (solutionFolderPath[^1] != Path.DirectorySeparatorChar) + { + solutionFolderPath += Path.DirectorySeparatorChar; + } var csprojList = Directory.GetFiles( solutionFolderPath, "*.csproj",