using System.Text.Json;
using Microsoft.UI.Xaml.Media;
using XFEEDToolBox.Controls;
using XFEEDToolBox.Core.Models;
using XFEEDToolBox.Core.Outfitting;
using XFEEDToolBox.Views;
namespace XFEEDToolBox;
public partial class App
{
private static async Task<object> RunPreviewLayoutProbeAsync(string directory)
{
void Require(bool value,string message){if(!value)throw new InvalidOperationException(message);}
Require(ViewModel.OfflinePreview,"Layout probe must use an isolated offline directory.");
MainWindow.AppWindow.Move(new(-30000,-30000));MainWindow.AppWindow.Resize(new(2900,1600));MainWindow.AppWindow.Show(false);
var shell=AppShellPage.Current!;shell.Navigate(typeof(MainPage));await Task.Delay(150);
var home=(MainPage)shell.CurrentPage!;var preview=(ShipModelView)home.FindName("ShipSchematic");var card=(Border)home.FindName("CurrentShipCard");
ViewModel.HomeShipType="anaconda";ViewModel.Ship="巨蟒";ViewModel.ShipOriginalName="Anaconda";ViewModel.HomeShipDetail="41 个模块 · 装配已读取";
card.StartBringIntoView(new BringIntoViewOptions{AnimationDesired=false});await Task.Delay(200);
async Task Ready(ShipModelView model){await Task.Delay(150);var until=DateTime.UtcNow.AddSeconds(25);while((!model.IsRendering||model.Frames<2)&&DateTime.UtcNow<until)await Task.Delay(60);Require(model.IsRendering,"Model did not start: "+model.RenderError);}
await Ready(preview);
preview.FitToViewport=false;await Ready(preview);var before=await preview.CaptureFrameAtAsync(12);
using(await preview.FreezeForXamlProbeAsync(12))await CaptureRefinementElementAsync(card,Path.Combine(directory,"home-before.png"));
preview.FitToViewport=true;await Ready(preview);var after=await preview.CaptureFrameAtAsync(12);
using(await preview.FreezeForXamlProbeAsync(12))await CaptureRefinementElementAsync(card,Path.Combine(directory,"home-after.png"));
await SaveModelFrameAsync(before,Path.Combine(directory,"home-model-before.png"));await SaveModelFrameAsync(after,Path.Combine(directory,"home-model-after.png"));
var framing=new List<object>();
foreach(var type in new[]{"anaconda","cutter","sidewinder"})
{
ViewModel.HomeShipType=type;await Ready(preview);
foreach(var seconds in new[]{0d,24,48})
{
var frame=await preview.CaptureFrameAtAsync(seconds);framing.Add(new{type,seconds,size=new[]{frame.Width,frame.Height},bounds=MeasureHologramFrame(frame)});
}
}
var responsiveWindows=new List<object>();
ViewModel.HomeShipType="anaconda";await Ready(preview);
foreach(var scenario in new[]{(name:"narrow",width:950,height:1500),(name:"ultrawide",width:3600,height:1080)})
{
MainWindow.AppWindow.Resize(new(scenario.width,scenario.height));MainWindow.AppWindow.Show(false);
var details=(StackPanel)home.FindName("ShipDetails");
(double page,double width,double height,int row) previous=default;var stable=0;
var deadline=DateTime.UtcNow.AddSeconds(8);
while(stable<4&&DateTime.UtcNow<deadline)
{
await Task.Delay(90);home.UpdateLayout();
var current=(page:home.ActualWidth,width:preview.ActualWidth,height:preview.ActualHeight,row:Grid.GetRow(details));
stable=current==previous&¤t.width>0&¤t.height>0?stable+1:0;previous=current;
}
Require(stable>=4,"Dashboard size did not stabilize for "+scenario.name);
Require(Grid.GetRow(details)==(home.ActualWidth<700?1:0),"Ship details did not follow the responsive layout for "+scenario.name);
card.StartBringIntoView(new BringIntoViewOptions{AnimationDesired=false});await Task.Delay(180);await Ready(preview);
var frame=await preview.CaptureFrameAtAsync(12);var bounds=MeasureHologramFrame(frame);
var measured=JsonSerializer.SerializeToElement(bounds);
Require(measured.GetProperty("marginOnEverySide").GetBoolean(),"Model glow was clipped at "+scenario.name);
var scale=home.XamlRoot.RasterizationScale;
Require(Math.Abs(frame.Width-preview.ActualWidth*scale)<=2&&Math.Abs(frame.Height-preview.ActualHeight*scale)<=2,"GPU frame retained a stale viewport at "+scenario.name);
var modelOrigin=preview.TransformToVisual(card).TransformPoint(new(0,0));
var detailsOrigin=details.TransformToVisual(card).TransformPoint(new(0,0));
Require(Grid.GetRow(details)==1?modelOrigin.Y+preview.ActualHeight<=detailsOrigin.Y+1:modelOrigin.X+preview.ActualWidth<=detailsOrigin.X+1,"Ship details overlap the preview at "+scenario.name);
var modelPath=Path.Combine(directory,"home-"+scenario.name+"-model.png");
var cardPath=Path.Combine(directory,"home-"+scenario.name+"-card.png");
await SaveModelFrameAsync(frame,modelPath);
using(await preview.FreezeForXamlProbeAsync(12))await CaptureRefinementElementAsync(card,cardPath);
responsiveWindows.Add(new{scenario.name,requestedWindow=new[]{scenario.width,scenario.height},actualWindow=new[]{MainWindow.AppWindow.Size.Width,MainWindow.AppWindow.Size.Height},pageWidth=home.ActualWidth,
previewSize=new[]{preview.ActualWidth,preview.ActualHeight},gpuSize=new[]{frame.Width,frame.Height},detailsRow=Grid.GetRow(details),modelPath,cardPath,bounds});
}
MainWindow.AppWindow.Resize(new(2900,1600));MainWindow.AppWindow.Show(false);await Task.Delay(250);
var fixture=GetArgument(Environment.GetCommandLineArgs(),"--refit-fixture")!;
using var fixtureJson=JsonDocument.Parse(await File.ReadAllTextAsync(fixture));
var document=(fixtureJson.RootElement.TryGetProperty("document",out var wrapped)?wrapped:fixtureJson.RootElement)
.Deserialize<ShipRefitDocument>(ToolboxSettings.JsonOptions)!;
shell.Navigate(typeof(RefitPage));await Task.Delay(180);ViewModel.LoadRefitProbeDocument(document);await Task.Delay(350);
var refit=(RefitPage)shell.CurrentPage!;var background=(ShipModelView)refit.FindName("RefitShipModel");await Ready(background);
var panels=new[]{"CategoryPanel","SlotPanel","InspectorPanel"}.Select(name=>(Border)refit.FindName(name)).ToArray();
var brushes=panels.Select(panel=>(SolidColorBrush)panel.Background).ToArray();
Require(brushes.All(brush=>brush.Color.A==80),"Refit panels did not apply the shared 31% opacity brush.");
using(await background.FreezeForXamlProbeAsync(12))
{
foreach(var panel in panels)panel.Background=new SolidColorBrush(Windows.UI.Color.FromArgb(255,17,29,43));
await CapturePageAsync(refit,Path.Combine(directory,"refit-before.png"));
for(var i=0;i<panels.Length;i++)panels[i].Background=brushes[i];
MainWindow.AppWindow.Show(false);await Task.Delay(60);await CapturePageAsync(refit,Path.Combine(directory,"refit-after.png"));
}
return new{refitPanelAlpha=80,refitPanelOpacity=80/255d,homeBefore=MeasureHologramFrame(before),homeAfter=MeasureHologramFrame(after),framing,responsiveWindows,gameActionsInvoked=false};
}
}
using System.Text.Json;
using Microsoft.UI.Xaml.Media;
using XFEEDToolBox.Controls;
using XFEEDToolBox.Core.Models;
using XFEEDToolBox.Core.Outfitting;
using XFEEDToolBox.Views;
namespace XFEEDToolBox;
public partial class App
{
private static async Task<object> RunPreviewLayoutProbeAsync(string directory)
{
void Require(bool value,string message){if(!value)throw new InvalidOperationException(message);}
Require(ViewModel.OfflinePreview,"Layout probe must use an isolated offline directory.");
MainWindow.AppWindow.Move(new(-30000,-30000));MainWindow.AppWindow.Resize(new(2900,1600));MainWindow.AppWindow.Show(false);
var shell=AppShellPage.Current!;shell.Navigate(typeof(MainPage));await Task.Delay(150);
var home=(MainPage)shell.CurrentPage!;var preview=(ShipModelView)home.FindName("ShipSchematic");var card=(Border)home.FindName("CurrentShipCard");
ViewModel.HomeShipType="anaconda";ViewModel.Ship="巨蟒";ViewModel.ShipOriginalName="Anaconda";ViewModel.HomeShipDetail="41 个模块 · 装配已读取";
card.StartBringIntoView(new BringIntoViewOptions{AnimationDesired=false});await Task.Delay(200);
async Task Ready(ShipModelView model){await Task.Delay(150);var until=DateTime.UtcNow.AddSeconds(25);while((!model.IsRendering||model.Frames<2)&&DateTime.UtcNow<until)await Task.Delay(60);Require(model.IsRendering,"Model did not start: "+model.RenderError);}
await Ready(preview);
preview.FitToViewport=false;await Ready(preview);var before=await preview.CaptureFrameAtAsync(12);
using(await preview.FreezeForXamlProbeAsync(12))await CaptureRefinementElementAsync(card,Path.Combine(directory,"home-before.png"));
preview.FitToViewport=true;await Ready(preview);var after=await preview.CaptureFrameAtAsync(12);
using(await preview.FreezeForXamlProbeAsync(12))await CaptureRefinementElementAsync(card,Path.Combine(directory,"home-after.png"));
await SaveModelFrameAsync(before,Path.Combine(directory,"home-model-before.png"));await SaveModelFrameAsync(after,Path.Combine(directory,"home-model-after.png"));
var framing=new List<object>();
foreach(var type in new[]{"anaconda","cutter","sidewinder"})
{
ViewModel.HomeShipType=type;await Ready(preview);
foreach(var seconds in new[]{0d,24,48})
{
var frame=await preview.CaptureFrameAtAsync(seconds);framing.Add(new{type,seconds,size=new[]{frame.Width,frame.Height},bounds=MeasureHologramFrame(frame)});
}
}
var responsiveWindows=new List<object>();
ViewModel.HomeShipType="anaconda";await Ready(preview);
foreach(var scenario in new[]{(name:"narrow",width:950,height:1500),(name:"ultrawide",width:3600,height:1080)})
{
MainWindow.AppWindow.Resize(new(scenario.width,scenario.height));MainWindow.AppWindow.Show(false);
var details=(StackPanel)home.FindName("ShipDetails");
(double page,double width,double height,int row) previous=default;var stable=0;
var deadline=DateTime.UtcNow.AddSeconds(8);
while(stable<4&&DateTime.UtcNow<deadline)
{
await Task.Delay(90);home.UpdateLayout();
var current=(page:home.ActualWidth,width:preview.ActualWidth,height:preview.ActualHeight,row:Grid.GetRow(details));
stable=current==previous&¤t.width>0&¤t.height>0?stable+1:0;previous=current;
}
Require(stable>=4,"Dashboard size did not stabilize for "+scenario.name);
Require(Grid.GetRow(details)==(home.ActualWidth<700?1:0),"Ship details did not follow the responsive layout for "+scenario.name);
card.StartBringIntoView(new BringIntoViewOptions{AnimationDesired=false});await Task.Delay(180);await Ready(preview);
var frame=await preview.CaptureFrameAtAsync(12);var bounds=MeasureHologramFrame(frame);
var measured=JsonSerializer.SerializeToElement(bounds);
Require(measured.GetProperty("marginOnEverySide").GetBoolean(),"Model glow was clipped at "+scenario.name);
var scale=home.XamlRoot.RasterizationScale;
Require(Math.Abs(frame.Width-preview.ActualWidth*scale)<=2&&Math.Abs(frame.Height-preview.ActualHeight*scale)<=2,"GPU frame retained a stale viewport at "+scenario.name);
var modelOrigin=preview.TransformToVisual(card).TransformPoint(new(0,0));
var detailsOrigin=details.TransformToVisual(card).TransformPoint(new(0,0));
Require(Grid.GetRow(details)==1?modelOrigin.Y+preview.ActualHeight<=detailsOrigin.Y+1:modelOrigin.X+preview.ActualWidth<=detailsOrigin.X+1,"Ship details overlap the preview at "+scenario.name);
var modelPath=Path.Combine(directory,"home-"+scenario.name+"-model.png");
var cardPath=Path.Combine(directory,"home-"+scenario.name+"-card.png");
await SaveModelFrameAsync(frame,modelPath);
using(await preview.FreezeForXamlProbeAsync(12))await CaptureRefinementElementAsync(card,cardPath);
responsiveWindows.Add(new{scenario.name,requestedWindow=new[]{scenario.width,scenario.height},actualWindow=new[]{MainWindow.AppWindow.Size.Width,MainWindow.AppWindow.Size.Height},pageWidth=home.ActualWidth,
previewSize=new[]{preview.ActualWidth,preview.ActualHeight},gpuSize=new[]{frame.Width,frame.Height},detailsRow=Grid.GetRow(details),modelPath,cardPath,bounds});
}
MainWindow.AppWindow.Resize(new(2900,1600));MainWindow.AppWindow.Show(false);await Task.Delay(250);
var fixture=GetArgument(Environment.GetCommandLineArgs(),"--refit-fixture")!;
using var fixtureJson=JsonDocument.Parse(await File.ReadAllTextAsync(fixture));
var document=(fixtureJson.RootElement.TryGetProperty("document",out var wrapped)?wrapped:fixtureJson.RootElement)
.Deserialize<ShipRefitDocument>(ToolboxSettings.JsonOptions)!;
shell.Navigate(typeof(RefitPage));await Task.Delay(180);ViewModel.LoadRefitProbeDocument(document);await Task.Delay(350);
var refit=(RefitPage)shell.CurrentPage!;var background=(ShipModelView)refit.FindName("RefitShipModel");await Ready(background);
var panels=new[]{"CategoryPanel","SlotPanel","InspectorPanel"}.Select(name=>(Border)refit.FindName(name)).ToArray();
var brushes=panels.Select(panel=>(SolidColorBrush)panel.Background).ToArray();
Require(brushes.All(brush=>brush.Color.A==80),"Refit panels did not apply the shared 31% opacity brush.");
using(await background.FreezeForXamlProbeAsync(12))
{
foreach(var panel in panels)panel.Background=new SolidColorBrush(Windows.UI.Color.FromArgb(255,17,29,43));
await CapturePageAsync(refit,Path.Combine(directory,"refit-before.png"));
for(var i=0;i<panels.Length;i++)panels[i].Background=brushes[i];
MainWindow.AppWindow.Show(false);await Task.Delay(60);await CapturePageAsync(refit,Path.Combine(directory,"refit-after.png"));
}
return new{refitPanelAlpha=80,refitPanelOpacity=80/255d,homeBefore=MeasureHologramFrame(before),homeAfter=MeasureHologramFrame(after),framing,responsiveWindows,gameActionsInvoked=false};
}
}