Files
MeWeb/tools/Screenshots/Program.cs
T
thepraandClaude Opus 5.5 37752f9f07
Build / Desktop, server and tools (push) Successful in 59s
Release / Every platform, the server, the release (push) Successful in 7m35s
me-web? 0.3: the path in drawn steps, each step's checks under it, the real RAM
- The path from this device to the internet is a vertical zig-zag of larger drawings (this
  phone or computer, the router or the mobile network, a shared exit, the provider's building,
  the globe) that pulse while their step is checked, joined by curved wires with the link and
  its speed, and a few details beside each: the model, the addresses inside and outside the
  router and which port-opening protocols answer, the AS number, the public addresses.
- The results are grouped under the step they concern, in the path's order, with the same
  drawing as a heading; tapping a step in the path scrolls to its checks.
- After a check, the status and "Check again" move to the end, beside sharing.
- Memory reads the device's RAM: on Android it showed the runtime's heap limit (0.1 GB).
  Labelled "Memory (RAM)" in every language. Free disk is read for the app's own folder, so
  Android shows it too. The device's model is read on Android, Linux and Windows.
- Two icons drew outside their box (the outside test's shield, the calls and games radio
  tower): joined Lucide elements started with a relative move. Fixed; twelve unused icons
  deleted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012CzABvBkbcFqoHdmi8b9WB
2026-10-15 08:08:37 +02:00

75 lines
2.5 KiB
C#

using Avalonia;
using Avalonia.Controls;
using Avalonia.Headless;
using Avalonia.Media.Imaging;
using Avalonia.Threading;
using MeWeb.App;
using MeWeb.App.Services;
using MeWeb.App.ViewModels;
using MeWeb.App.Views;
using MeWeb.Core.Checks;
using Microsoft.Extensions.DependencyInjection;
var output = args.Length > 0 ? args[0] : Path.Combine("dist", "screenshots");
var codes = args.Length > 1 ? args[1].Split(',', StringSplitOptions.RemoveEmptyEntries) : Languages.All.Select(l => l.Code).ToArray();
Directory.CreateDirectory(output);
var session = HeadlessUnitTestSession.StartNew(typeof(ScreenshotEntry));
await session.Dispatch(async () =>
{
var run = await App.Services.GetRequiredService<CheckRunner>().Run((_, _) => { }, CancellationToken.None);
Console.WriteLine($"run: {string.Join(", ", run.Findings.Select(f => $"{f.Id}={f.Outcome}"))}");
foreach (var (width, height, label) in new[] { (1100, 1500, "desktop"), (400, 8000, "phone") })
{
foreach (var code in codes)
{
Localizer.Instance.SetLanguage(Languages.Find(code) ?? Languages.Fallback);
Shoot(width, height, $"main-{label}-{code}", model => model.Replay(run));
if (label != "desktop")
{
Shoot(width, 860, $"start-{code}", _ => { });
continue;
}
Shoot(width, 900, $"contacts-{code}", model => model.ShowContacts = true);
Shoot(width, 900, $"share-{code}", model =>
{
model.Replay(run);
model.OpenShareCommand.Execute(null);
});
}
}
return 0;
}, CancellationToken.None);
Environment.Exit(0);
void Shoot(int width, int height, string name, Action<MainViewModel> prepare)
{
var model = App.Services.GetRequiredService<MainViewModel>();
var view = new MainView { DataContext = model };
var window = new Window { Width = width, Height = height, Content = view };
window.Show();
model.AvailableWidth = width;
prepare(model);
for (var i = 0; i < 6; i++) Dispatcher.UIThread.RunJobs();
var frame = window.CaptureRenderedFrame();
var path = Path.Combine(output, $"{name}.png");
if (frame is not null)
{
using var file = File.Create(path);
frame.Save(file, new PngBitmapEncoderOptions());
}
Console.WriteLine($"{path} {(frame is null ? "no frame" : "ok")}");
window.Close();
}
public static class ScreenshotEntry
{
public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure<MeWeb.App.App>()
.UseSkia()
.UseHarfBuzz()
.WithInterFont()
.UseHeadless(new AvaloniaHeadlessPlatformOptions { UseHeadlessDrawing = false });
}