XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Text.Json;
using XFEEDToolBox.Core.Notifications;
using XFEEDToolBox.Services.Arrival;
using XFEEDToolBox.Views;
using Windows.Graphics.Imaging;

namespace XFEEDToolBox;

public partial class App
{
    private ArrivalNotifications? arrivalNotifications;
    private IDisposable? arrivalSubscription;
    private readonly GameAnnouncementObserver announcementObserver=new();
    private void OnGameAnnouncement(XFEEDToolBox.Core.Data.ObservedJournalEvent observed,XFEEDToolBox.Core.Models.PlayerState player)
    {
        var notice=announcementObserver.Observe(observed,DateTimeOffset.UtcNow);
        if(notice is null)return;
        Runtime.Log("游戏公告",notice.Message);
        MainWindow.DispatcherQueue.TryEnqueue(()=>arrivalNotifications?.Send(notice));
    }
    private void InitializeArrivalNotifications(bool enabled)
    {
        if(!enabled)return;
        arrivalNotifications=new(Runtime,MainWindow.DispatcherQueue,page=>
        {
            AppShellPage.Current?.Navigate(page switch{"home"=>typeof(MainPage),"current-system"=>typeof(CurrentSystemPage),_=>typeof(NavigationPage)});
            if(MainWindow.AppWindow.Presenter is Microsoft.UI.Windowing.OverlappedPresenter presenter
                &&presenter.State==Microsoft.UI.Windowing.OverlappedPresenterState.Minimized)presenter.Restore();
            MainWindow.Activate();
        });
        if(arrivalNotifications.Start())
        {
            Runtime.LiveJournalEvent+=OnGameAnnouncement;
            arrivalSubscription=ViewModel.ObserveArrivals(
            (arrival,pid)=>arrivalNotifications.Send(arrival,pid,()=>Runtime.Player),
            (scene,pid)=>arrivalNotifications.CaptureStar(scene,pid,()=>Runtime.Player),
            (ready,pid)=>arrivalNotifications.Send(ready,pid,()=>Runtime.Player));
        }
    }
    private void StopArrivalNotifications(){Runtime.LiveJournalEvent-=OnGameAnnouncement;arrivalSubscription?.Dispose();arrivalNotifications?.Dispose();}
    private static async Task RunArrivalNotificationProbeAsync(string path)
    {
        var directory=Path.GetDirectoryName(Path.GetFullPath(path))!;Directory.CreateDirectory(directory);
        string? failure=null;object? result=null;
        try
        {
            if(!ViewModel.OfflinePreview)throw new InvalidOperationException("Notification preview requires an isolated offline data directory.");
            using var source=File.OpenRead(Path.Combine(AppContext.BaseDirectory,"Assets","Home","navigation-orbit.png"));
            var decoder=await BitmapDecoder.CreateAsync(source.AsRandomAccessStream());
            var data=await decoder.GetPixelDataAsync(BitmapPixelFormat.Bgra8,BitmapAlphaMode.Ignore,new BitmapTransform(),ExifOrientationMode.IgnoreExifOrientation,ColorManagementMode.DoNotColorManage);
            var frame=new ArrivalFrame((int)decoder.PixelWidth,(int)decoder.PixelHeight,data.DetachPixelData());
            var arrival=new NavigationArrival(Guid.NewGuid().ToString("N"),42,"Sol","Sol · 离线样例",false,false,"fixture",DateTimeOffset.UtcNow,DateTimeOffset.UtcNow);
            var image=Path.Combine(directory,"arrival-hero.png");await ArrivalHeroCard.SaveAsync(ArrivalHeroCard.Render(frame,arrival),image);
            var longTitle=arrival with{Destination="Col 285 Sector MC-I b11-2 · 长名称预览"};
            await ArrivalHeroCard.SaveAsync(ArrivalHeroCard.Render(frame,longTitle),Path.Combine(directory,"arrival-long-name.png"));
            await File.WriteAllTextAsync(Path.Combine(directory,"arrival-toast.xml"),ArrivalToastContent.Build(arrival,image));
            var ready=new SessionReadyNotification(Guid.NewGuid().ToString("N"),"已重新进入游戏","一键大退已完成 · Sol · 离线样例",arrival);
            await ArrivalHeroCard.SaveAsync(ArrivalHeroCard.Render(frame,ready),Path.Combine(directory,"session-ready-hero.png"));
            await File.WriteAllTextAsync(Path.Combine(directory,"session-ready-toast.xml"),ArrivalToastContent.Build(ready));
            bool? platformSupported=null;string? platformError=null;
            try{platformSupported=Microsoft.Windows.AppNotifications.AppNotificationManager.IsSupported();}catch(Exception error){platformError=error.Message;}
            string captureStatus="尚未确认";string? captureError=null;object? captureMetrics=null;
            try
            {
                MainWindow.Content=new Grid{Background=new Microsoft.UI.Xaml.Media.SolidColorBrush(Windows.UI.Color.FromArgb(255,4,12,22)),Children=
                    {new Image{Source=new Microsoft.UI.Xaml.Media.Imaging.BitmapImage(new Uri(Path.Combine(AppContext.BaseDirectory,"Assets","Home","navigation-orbit.png"))),Stretch=Microsoft.UI.Xaml.Media.Stretch.UniformToFill}}};
                MainWindow.AppWindow.Move(new(-30000,-30000));MainWindow.AppWindow.Resize(new(1100,650));MainWindow.AppWindow.Show(false);
                await Task.Delay(400);((FrameworkElement)MainWindow.Content).UpdateLayout();
                var captured=await ArrivalWindowCapture.CaptureOwnPreviewAsync(CancellationToken.None);
                if(captured is not null)
                {
                    captureStatus="captured";captureMetrics=new{captured.Width,captured.Height,bytes=captured.Bgra.Length};
                    await ArrivalHeroCard.SaveAsync(ArrivalHeroCard.Render(captured,arrival),Path.Combine(directory,"window-capture-hero.png"));
                }
            }
            catch(Exception error){captureError=error.ToString();}
            finally{MainWindow.AppWindow.Hide();}
            var nativeRegistered=false;var nativeShown=false;var nativeHistory=false;uint nativeId=0;string? nativeError=null;var nativeClicks=0;
            if(Environment.GetCommandLineArgs().Contains("--test-windows-notification"))
            {
                var manager=Microsoft.Windows.AppNotifications.AppNotificationManager.Default;
                void Invoked(Microsoft.Windows.AppNotifications.AppNotificationManager sender,Microsoft.Windows.AppNotifications.AppNotificationActivatedEventArgs args)=>Interlocked.Increment(ref nativeClicks);
                manager.NotificationInvoked+=Invoked;
                try
                {
                    manager.Register("XFE ED 工具箱",new Uri(Path.Combine(AppContext.BaseDirectory,"Assets","icon.png")));nativeRegistered=true;
                    var content=System.Xml.Linq.XElement.Parse(ArrivalToastContent.Build(arrival,image));
                    content.Descendants("text").First().Value="测试通知 · 已抵达 Sol(离线样例)";
                    var notification=new Microsoft.Windows.AppNotifications.AppNotification(content.ToString(System.Xml.Linq.SaveOptions.DisableFormatting))
                        {Tag="arrival-test",Group="arrival-test",Expiration=DateTimeOffset.UtcNow.AddMinutes(5)};
                    manager.Show(notification);nativeShown=true;nativeId=notification.Id;
                    nativeHistory=(await manager.GetAllAsync()).Any(n=>n.Id==nativeId&&n.Id>0);
                    await File.WriteAllTextAsync(Path.Combine(directory,"notification-queued.json"),JsonSerializer.Serialize(new{nativeId,nativeHistory,previewOnly=true}));
                    await Task.Delay(12000);
                }
                catch(Exception error){nativeError=error.ToString();}
                finally
                {
                    if(nativeId>0)try{await manager.RemoveByIdAsync(nativeId);}catch(Exception error){nativeError??=error.ToString();}
                    manager.NotificationInvoked-=Invoked;if(nativeRegistered)manager.Unregister();
                }
            }
            result=new{image,width=ArrivalHeroCard.Width,height=ArrivalHeroCard.Height,fixtureOnly=true,
                backgroundSource="Bundled offline artwork, not a game screenshot",nativeRegistrationInvoked=nativeRegistered,nativeShowInvoked=nativeShown,gameCaptureInvoked=false,
                nativeId,nativeHistory,nativeError,nativeClicks,platformSupported,platformError,captureStatus,captureError,captureMetrics,actualWindowsPresentation="尚未确认",gameInputsInvoked=false};
        }
        catch(Exception error){failure=error.ToString();}
        await File.WriteAllTextAsync(path,JsonSerializer.Serialize(new{result,failure},new JsonSerializerOptions{WriteIndented=true}));MainWindow.Close();
    }
}