yavsc/src/PostIt/PostIt/ViewLocator.cs

40 lines
1.3 KiB
C#
Raw Normal View History

2026-05-29 01:29:36 +01:00
using System;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
2026-06-11 00:14:51 +01:00
using Microsoft.Extensions.DependencyInjection;
2026-05-29 01:29:36 +01:00
using PostIt.ViewModels;
2026-06-11 00:14:51 +01:00
using PostIt.Views;
2026-05-29 01:29:36 +01:00
namespace PostIt;
/// <summary>
/// Given a view model, returns the corresponding view if possible.
/// </summary>
2026-06-11 00:14:51 +01:00
2026-05-29 01:29:36 +01:00
public class ViewLocator : IDataTemplate
{
2026-06-11 00:14:51 +01:00
private readonly IServiceProvider _services;
2026-05-29 01:29:36 +01:00
2026-06-11 00:14:51 +01:00
public ViewLocator(IServiceProvider services)
{
_services = services;
2026-05-29 01:29:36 +01:00
}
public Control Build(object? data)
2026-05-29 01:29:36 +01:00
{
2026-06-11 00:14:51 +01:00
return data switch
{
MainPageViewModel => _services.GetRequiredService<MainPage>(),
Settings => _services.GetRequiredService<SettingsPage>(),
2026-06-26 01:45:21 +01:00
HomePageViewModel => _services.GetRequiredService<HomePage>(),
feat(postit): signature capture page (dev entry, file persistence) Builds on f9cfd560 (SignaturePadControl + SignaturePadData) with a full Avalonia page that captures signatures, renders them as Polylines, and persists the wire-format payload to ~/.local/share/PostIt/signatures as JSON v1. Scope - New SignaturePage (axaml + code-behind) hosts the render-agnostic control: a fixed-size Border is the hit-test surface, an overlaid Canvas is rebuilt on every RedrawRequested from the Strokes buffer. - SignaturePageViewModel wraps the control: exposes StrokeCount / PointCount / StatusMessage, Clear and CaptureAsync commands, and Attach/Detach for view-lifetime ownership. - CaptureAsync writes a JSON envelope { format, coordinateMax, capturedAtUtc, strokes, strokeCount } to LocalApplicationData/PostIt/signatures/signature-yyyyMMdd-HHmmssfff.json. This is a stop-gap; the production transport will be POST /api/signature/{devisId} on Yavsc.Api (commit 3+). - Entry point is a [DEV] button on MainPage that pushes the page onto the NavigationPage. The production trigger is a SignalR push from Yavsc.Org ("devis received, sign here") landing on a hub handler — the button and its Click handler are explicitly marked dev-only and tracked for removal in the same commit that wires the SignalR handler. Plumbing - App.axaml.cs: SignaturePage and SignaturePageViewModel registered as Transient in the DI container. - ViewLocator: routes SignaturePageViewModel to SignaturePage. - SignaturePadData: adds PointCount (sum of pairs across strokes), used by the VM status bar and the test surface. Tests (57/57 green, 9 new in this commit) - SignaturePageViewModelTests: constructors and dimension validation, Attach/Detach idempotence, StrokeCompleted and Clear propagate to the VM, CaptureAsync on empty buffer is a no-op, CaptureAsync on a non-empty buffer writes a v1 envelope with the expected structure (parsed back via JsonDocument, not text matching), and creates the destination directory if missing. - All previously-green tests (48) remain green. Out of scope - POST /api/signature endpoint on Yavsc.Api (commit 3). - SignalR handler that opens the page on a "devis received" push. - Rasterization: this commit only proves capture and persistence; the visible ink is a Polyline reconstruction, not a PNG, by design (per the wire-format decision in commit 1). Note on SignaturePadData - The PointCount property was added after f9cfd560 landed. It is folded into this commit rather than amending f9cfd560 to keep the existing history readable; the change is mechanical and tested by the new SignaturePageViewModelTests.
2026-07-04 15:11:22 +01:00
SignaturePageViewModel => _services.GetRequiredService<SignaturePage>(),
2026-08-19 14:09:31 +01:00
AddCircleMemberDialogViewModel => _services.GetRequiredService<AddCircleMemberDialog>(),
CirclesPageViewModel => _services.GetRequiredService<CirclesPage>(),
PostAclDialogViewModel => _services.GetRequiredService<PostAclDialog>(),
null => new TextBlock { Text = "No view for <null>" },
2026-06-26 01:45:21 +01:00
_ => new TextBlock { Text = $"No view for {data.GetType().Name}" }
2026-06-11 00:14:51 +01:00
};
2026-05-29 01:29:36 +01:00
}
2026-06-11 00:14:51 +01:00
public bool Match(object? data) => data is ViewModelBase;
2026-06-26 01:45:21 +01:00
}