From a2705f4cccf4a5f97fa5d5a4d01fa49bb61e621d Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Fri, 27 Feb 2026 17:17:27 +0000 Subject: [PATCH 1/3] Add progress bar on image load --- .../Controllers/ImagesController.cs | 7 ++++ src/ImageMapper.Api/Services/IImageService.cs | 7 ++++ src/ImageMapper.Api/Services/ImageService.cs | 17 +++++++- .../Client/ImageItemFetcher.cs | 10 +++++ .../Components/Pages/Home.razor | 42 +++++++++++++++++++ .../Components/Pages/Home.razor.cs | 23 ++++++++++ 6 files changed, 104 insertions(+), 2 deletions(-) diff --git a/src/ImageMapper.Api/Controllers/ImagesController.cs b/src/ImageMapper.Api/Controllers/ImagesController.cs index 05f4640..ce9eb91 100644 --- a/src/ImageMapper.Api/Controllers/ImagesController.cs +++ b/src/ImageMapper.Api/Controllers/ImagesController.cs @@ -19,6 +19,13 @@ public IAsyncEnumerable Get(CancellationToken ct) return _svc.GetImagesAsync(ct); } + [HttpGet("count")] + public async Task> GetCount(CancellationToken ct) + { + var count = await _svc.GetImageCountAsync(ct); + return Ok(count); + } + [HttpGet("raw/{**relativePath}")] public async Task GetRaw(string relativePath, CancellationToken ct) { diff --git a/src/ImageMapper.Api/Services/IImageService.cs b/src/ImageMapper.Api/Services/IImageService.cs index 5019260..c3a55a1 100644 --- a/src/ImageMapper.Api/Services/IImageService.cs +++ b/src/ImageMapper.Api/Services/IImageService.cs @@ -27,4 +27,11 @@ public interface IImageService /// null if the image could not be found. /// Thrown when the provided relative path is invalid or attempts to traverse outside the allowed directory." Task GetImageBytesAsync(string relativePath, CancellationToken ct = default); + + /// + /// Asynchronously retrieves the total count of image files. + /// + /// A cancellation token that can be used to cancel the operation. + /// The total count of image files. + Task GetImageCountAsync(CancellationToken ct = default); } diff --git a/src/ImageMapper.Api/Services/ImageService.cs b/src/ImageMapper.Api/Services/ImageService.cs index 94b878a..72c509c 100644 --- a/src/ImageMapper.Api/Services/ImageService.cs +++ b/src/ImageMapper.Api/Services/ImageService.cs @@ -67,11 +67,11 @@ public async IAsyncEnumerable GetImagesAsync([EnumeratorCancellation] var full = Path.Combine(_imagesRoot, normalized); var fullPath = Path.GetFullPath(full); var rootPath = Path.GetFullPath(_imagesRoot); - + // Ensure rootPath ends with separator for proper boundary checking if (!rootPath.EndsWith(Path.DirectorySeparatorChar)) rootPath += Path.DirectorySeparatorChar; - + // Validate that the resolved path is within the root directory if (!fullPath.StartsWith(rootPath, StringComparison.OrdinalIgnoreCase)) { @@ -83,4 +83,17 @@ public async IAsyncEnumerable GetImagesAsync([EnumeratorCancellation] return await File.ReadAllBytesAsync(fullPath, ct); } + + public Task GetImageCountAsync(CancellationToken ct = default) + { + if (!System.IO.Directory.Exists(_imagesRoot)) + return Task.FromResult(0); + + var extensions = new[] { ".jpg", ".jpeg", ".png", ".tif", ".tiff", ".nef" }; + + var count = System.IO.Directory.EnumerateFiles(_imagesRoot, "*.*", SearchOption.AllDirectories) + .Count(f => extensions.Contains(Path.GetExtension(f).ToLowerInvariant())); + + return Task.FromResult(count); + } } diff --git a/src/ImageMapper.Web/Client/ImageItemFetcher.cs b/src/ImageMapper.Web/Client/ImageItemFetcher.cs index 0daaeb7..82ab000 100644 --- a/src/ImageMapper.Web/Client/ImageItemFetcher.cs +++ b/src/ImageMapper.Web/Client/ImageItemFetcher.cs @@ -1,9 +1,19 @@ using ImageMapper.Models; +using System.Net.Http.Json; namespace ImageMapper.Web.Client { public class ImageItemFetcher(HttpClient httpClient) { + /// + /// Fetch the total count of available images + /// + /// The total count of images + public async Task FetchImageCount(CancellationToken ct = default) + { + return await httpClient.GetFromJsonAsync("/api/images/count", ct); + } + /// /// Fetch list of available images with metadata, streamed as async enumerable /// diff --git a/src/ImageMapper.Web/Components/Pages/Home.razor b/src/ImageMapper.Web/Components/Pages/Home.razor index fec100d..7b84b5d 100644 --- a/src/ImageMapper.Web/Components/Pages/Home.razor +++ b/src/ImageMapper.Web/Components/Pages/Home.razor @@ -8,6 +8,18 @@
+ + +