# Copilot Instructions ## Build & Test Commands ```powershell # Build dotnet build Catalog.sln # Run all tests dotnet test MaddoShared.Tests # Run a single test dotnet test MaddoShared.Tests --filter "FullyQualifiedName~MethodName" # Benchmarks (modes: quick | all | parallel | chunks | sizes | stress) .\run-benchmarks.ps1 quick # Publish release build (self-contained Windows EXE) dotnet publish "imagecatalog\ImageCatalog 2.csproj" -c Release -r win-x64 --self-contained ``` ## Architecture This is a WinForms/WPF image cataloging application targeting .NET 10.0-windows. ### Projects | Project | Purpose | |---------|---------| | **imagecatalog** | Main desktop application — WinForms (default), WPF (`--wpf`), or Avalonia (`--avalonia`) | | **MaddoShared** | Shared image processing library (the core) | | **MaddoShared.Tests** | Unit tests for MaddoShared | | **MaddoShared.Benchmarks** | BenchmarkDotNet performance benchmarks | | **WPFCatalog** | Alternate WPF UI (secondary) | | **ImageCatalogCS / ImageCatalogParallel** | Legacy/experimental variants | | **CatalogLib / CatalogLibVb / CatalogVbLib** | Legacy VB.NET libraries | The main app selects its UI at startup via command-line flag: - *(default)* — WinForms (`MainForm`) - `--wpf` — WPF with MahApps.Metro (`MainWindow`) - `--avalonia` — Avalonia with Fluent theme (`AvaloniaMainWindow`) All three UIs bind to the same `DataModel`. Dialog events (`SelectSourceFolderRequested`, etc.) are subscribed in each window's code-behind. `DataModel.UiInvoker` must be set by the active UI to enable cross-thread UI updates (Avalonia sets this to `Dispatcher.UIThread.Invoke`; WPF uses `Application.Current.Dispatcher`). ### Core Flow 1. User configures paths/settings in the UI (`DataModel.cs` — MVVM ViewModel) 2. `ProcessImagesCommand` triggers `ImageCreationService` 3. `ImageCreationService` processes files in parallel chunks, with configurable concurrency and batch size (GC flush between chunks) 4. Each file is handled by an `IImageCreator` implementation (GDI+ or ImageSharp) 5. Output: resized/watermarked/overlaid images written to a destination folder hierarchy ### Key Abstractions (MaddoShared) - **`IImageCreator`** — single async method to process one image; two implementations: `ImageCreatorGDI` (System.Drawing) and `ImageCreatorSharp` (SixLabors.ImageSharp) - **`ImageCreationService`** — parallel orchestrator; uses `AsyncEnumerator` with chunking; loads logo once, clones per thread for thread safety - **`ImageState`** — per-file processing context (input path, EXIF orientation, thumbnail sizes, overlays, logo, rotation) - **`PicSettings`** — 50+ property configuration model (dimensions, fonts, colors, JPEG quality, watermark, logo positioning, `ImageCreatorProvider` selector) - **`FileHelperSharp`** — recursive file enumeration with folder-per-N-files mapping and counter formatting ### Implementation Selection `PicSettings.ImageCreatorProvider` switches between `"Sharp"` (SixLabors.ImageSharp) and `"Alternate"` (GDI+) at runtime. ## Conventions ### C# Style - File-scoped namespaces everywhere: `namespace MaddoShared;` - Nullable reference types enabled (`enable`) - Implicit usings enabled - `ConfigureAwait(false)` on all `await` calls in library code ### Dependency Injection - Constructor injection throughout; loggers typed as `ILogger` - Main app wires services in `Program.cs` via `IServiceCollection` ### Testing - MSTest with `[TestClass]` / `[TestMethod]` - FluentAssertions for assertions - Moq for mocking - Factory helper pattern in tests: `CreateService(Action configure = null)` methods for flexible test setup ### Async / Parallelism - All image I/O is `async Task` - `ImageCreationService` uses configurable `MaxDegreeOfParallelism` and `ChunkSize`; explicit `GC.Collect()` between chunks to manage memory under batch load ### Versioning & CI - Semantic versioning via **GitVersion** (mode: `ContinuousDelivery`, current base: `3.2.0`) - GitLab CI pipeline: builds → single-file self-contained EXE → GitLab Release - Private NuGet packages scoped to `AIFotoONLUS.*` prefix, routed to the GitLab package registry (see `NuGet.Config`)