XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 0
UTF-8
using XFEEliteDangerous.Client;
using System.Text.Json.Nodes;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;

namespace XFEEliteDangerous.Desktop;

public sealed record FleetShipChoice(uint Id,string Name,string Prototype,bool Active)
{public string Label=>$"{Name} · {Prototype}"+(Active?AppText.Get("FleetPage.Text118"):"");}
public sealed record FleetSlotChoice(string Name,string Module,JsonNode Data)
{public string Label=>$"{Name} · {(string.IsNullOrEmpty(Module)?AppText.Get("FleetPage.Text119"):Module)}";}
public sealed record StoredModuleChoice(uint Id,string Module)
{public string Label=>AppText.Format("FleetPage.Text120", (Module), (Id));}

public sealed class FleetPage : DesktopPage
{
    private readonly ComboBox accounts=new(){MinWidth=380,DisplayMemberPath=nameof(AccountChoice.Label)};
    private readonly ComboBox ships=new(){MinWidth=440,DisplayMemberPath=nameof(FleetShipChoice.Label)};
    private readonly ListView slots=new(){MinHeight=150,MaxHeight=400,DisplayMemberPath=nameof(FleetSlotChoice.Label)};
    private readonly ComboBox modules=new(){MinWidth=440,PlaceholderText=AppText.Get("FleetPage.Text121")};
    private readonly ComboBox storage=new(){MinWidth=440,DisplayMemberPath=nameof(StoredModuleChoice.Label),PlaceholderText=AppText.Get("FleetPage.Text122")};
    private readonly TextBox name=new(){PlaceholderText=AppText.Get("FleetPage.Text123"),MaxLength=100,MinWidth=240};
    private readonly TextBox ident=new(){PlaceholderText=AppText.Get("FleetPage.Text124"),MaxLength=24,MinWidth=140};
    private readonly TextBlock details=new(){TextWrapping=TextWrapping.Wrap};
    private JsonNode? fleet;
    private string version="";
    private bool refreshing;
    private string? AccountId=>DesktopContext.IsAdmin?(accounts.SelectedItem as AccountChoice)?.Id:DesktopContext.State.AccountId;
    public FleetPage():base(AppText.Get("AppShellPage.Text102"),AppText.Get("FleetPage.Text125"))
    {
        accounts.Name="FleetAccounts";ships.Name="FleetShips";slots.Name="FleetSlots";
        if(DesktopContext.IsAdmin)Body.Children.Add(Card(AppText.Get("DesktopContracts.Text115"),AppText.Get("FleetPage.Text126"),accounts));
        accounts.SelectionChanged+=async(_,_)=>{if(!refreshing)await RunAsync(LoadAsync);};
        Body.Children.Add(Horizontal(ships,Button(AppText.Get("FleetPage.Text127"),()=>RunAsync(RefreshAsync))));
        Body.Children.Add(details);
        if(DesktopContext.IsAdmin)Body.Children.Add(Button(AppText.Get("FleetPage.Text128"),()=>RunAsync(async()=>
        {
            await DesktopContext.Local.InitializeNativeAsync(AccountId,version,Lifetime.Token);await LoadAsync();Success(AppText.Get("FleetPage.Text129"));
        })));
        ships.SelectionChanged+=(_,_)=>SelectShip();
        Body.Children.Add(Card(AppText.Get("FleetPage.Text130"),AppText.Get("FleetPage.Text131"),Horizontal(name,ident,Button(AppText.Get("FleetPage.Text132"),()=>RunAsync(()=>EditAsync(new(){["action"]="rename",["name"]=name.Text,["ident"]=ident.Text}))))));
        var create=Button(AppText.Get("FleetPage.Text133"),()=>RunAsync(CloneAsync));create.Name="CreateFleetShip";
        var select=Button(AppText.Get("FleetPage.Text134"),()=>RunAsync(()=>EditAsync(new(){["action"]="select"})));select.Name="SelectFleetShip";
        var remove=Button(AppText.Get("FleetPage.Text135"),()=>RunAsync(DeleteAsync));remove.Name="DeleteFleetShip";
        Body.Children.Add(Horizontal(create,select,remove));
        var launch=Button(AppText.Get("FleetPage.Text136"),()=>RunAsync(async()=>
        {
            if(AccountId is not {} id)throw new InvalidOperationException(AppText.Get("FleetPage.Text137"));
            await ManagedGameLauncher.StartAsync(id,Lifetime.Token);Success(AppText.Get("FleetPage.Text138"));
        }),true);launch.Name="LaunchManagedSolo";Body.Children.Add(launch);
        Body.Children.Add(Card(AppText.Get("FleetPage.Text139"),AppText.Get("FleetPage.Text140"),slots));
        slots.SelectionChanged+=(_,_)=>
        {
            var compatible=(slots.SelectedItem as FleetSlotChoice)?.Data["compatible"].Rows().Select(value=>value.Text("name")).ToArray()??[];
            modules.ItemsSource=compatible;modules.SelectedIndex=compatible.Length>0?0:-1;
        };
        var fit=Button(AppText.Get("FleetPage.Text141"),()=>RunAsync(()=>SlotAction("module")));fit.Name="FitFleetModule";
        var store=Button(AppText.Get("FleetPage.Text142"),()=>RunAsync(()=>SlotAction("store")));store.Name="StoreFleetModule";
        Body.Children.Add(Horizontal(modules,fit,store));
        Body.Children.Add(Card(AppText.Get("FleetPage.Text143"),AppText.Get("FleetPage.Text144"),Horizontal(storage,Button(AppText.Get("FleetPage.Text145"),()=>RunAsync(()=>SlotAction("retrieve"))))));
        Body.Children.Add(new InfoBar{IsOpen=true,IsClosable=false,Severity=InfoBarSeverity.Informational,Title=AppText.Get("FleetPage.Text146"),Message=AppText.Get("FleetPage.Text147")});
        var advanced=new Expander{Header=AppText.Get("FleetPage.Text148"),HorizontalAlignment=HorizontalAlignment.Stretch};
        advanced.Content=Horizontal(Button(AppText.Get("FleetPage.Text149"),()=>RunAsync(ExportAsync)),Button(AppText.Get("FleetPage.Text150"),()=>RunAsync(ImportAsync)));
        Body.Children.Add(advanced);
        Loaded+=async(_,_)=>await RunAsync(RefreshAsync);
    }
    private async Task RefreshAsync()
    {
        if(!DesktopContext.State.IsLoggedIn)return;
        if(DesktopContext.IsAdmin)
        {
            var old=AccountId;var rows=(await DesktopContext.Local.AccountsAsync(Lifetime.Token)).Rows().Select(value=>new AccountChoice(value.Text("id"),value.Text("email"),value.Text("displayName"),value.Text("role"))).ToArray();
            refreshing=true;try{accounts.ItemsSource=rows;accounts.SelectedItem=rows.FirstOrDefault(value=>value.Id==old)??rows.FirstOrDefault();}finally{refreshing=false;}
        }
        await LoadAsync();
    }
    private async Task LoadAsync()
    {
        if(string.IsNullOrEmpty(AccountId))return;
        var old=(ships.SelectedItem as FleetShipChoice)?.Id;
        fleet=await DesktopContext.Local.FleetAsync(AccountId,Lifetime.Token);version=fleet["commander"].Text("version");
        var rows=fleet.Flag("native")?fleet["ships"].Rows().Select(value=>new FleetShipChoice((uint)value.Number("id"),value["label"].Text("name"),value.Text("prototype"),value.Flag("active"))).ToArray():[];
        ships.ItemsSource=rows;ships.SelectedItem=rows.FirstOrDefault(value=>value.Id==old)??rows.FirstOrDefault();
        storage.ItemsSource=fleet["stored"].Rows().Select(value=>new StoredModuleChoice((uint)value.Number("slotId"),value["module"].Text("name"))).ToArray();
        if(!fleet.Flag("native"))details.Text=AppText.Get("FleetPage.Text151");
        SelectShip();
    }
    private void SelectShip()
    {
        if(ships.SelectedItem is not FleetShipChoice choice){slots.ItemsSource=null;return;}
        var ship=fleet?["ships"].Rows().Single(value=>value.Number("id")==choice.Id);
        name.Text=ship?["label"].Text("name")??"";ident.Text=ship?["label"].Text("ident")??"";
        details.Text=AppText.Format("FleetPage.Text152", (choice.Id), (choice.Prototype), (ship?["fuel"].Text("level")), (ship?["fuel"].Text("capacity")));
        slots.ItemsSource=ship?["slots"].Rows().Select(value=>new FleetSlotChoice(value.Text("name"),value["module"].Text("name"),value.DeepClone())).ToArray();
    }
    private async Task EditAsync(JsonObject command)
    {
        if(!DesktopContext.State.CanEditShips)throw new UnauthorizedAccessException(AppText.Get("FleetPage.Text153"));
        if(ships.SelectedItem is not FleetShipChoice ship)throw new InvalidOperationException(AppText.Get("FleetPage.Text154"));
        command["shipId"]=ship.Id;
        await DesktopContext.Local.EditFleetAsync(AccountId,command,version,Lifetime.Token);await LoadAsync();Success(AppText.Get("FleetPage.Text155"));
    }
    private async Task CloneAsync()
    {
        if(ships.SelectedItem is not FleetShipChoice source)throw new InvalidOperationException(AppText.Get("FleetPage.Text156"));
        var label=new TextBox{Text=source.Name+AppText.Get("FleetPage.Text157"),MaxLength=100};var callSign=new TextBox{Text="XFE-NEW",MaxLength=24};
        var panel=new StackPanel{Spacing=12};panel.Children.Add(new TextBlock{Text=AppText.Get("FleetPage.Text158"),TextWrapping=TextWrapping.Wrap});panel.Children.Add(label);panel.Children.Add(callSign);
        if(await ShowAsync(AppText.Get("FleetPage.Text159"),panel,AppText.Get("FleetPage.Text160"))!=ContentDialogResult.Primary)return;
        await EditAsync(new(){["action"]="clone",["templateShipId"]=source.Id,["name"]=label.Text,["ident"]=callSign.Text});
    }
    private async Task DeleteAsync()
    {
        if(ships.SelectedItem is not FleetShipChoice ship)return;
        if(await ShowAsync(AppText.Get("FleetPage.Text161"),new TextBlock{Text=AppText.Format("FleetPage.Text162", (ship.Name)),TextWrapping=TextWrapping.Wrap},AppText.Get("FleetPage.Text163"))==ContentDialogResult.Primary)
            await EditAsync(new(){["action"]="remove"});
    }
    private Task SlotAction(string action)
    {
        if(slots.SelectedItem is not FleetSlotChoice slot)throw new InvalidOperationException(AppText.Get("FleetPage.Text164"));
        var command=new JsonObject{["action"]=action,["slot"]=slot.Name};
        if(action=="module")command["module"]=modules.SelectedItem as string??throw new InvalidOperationException(AppText.Get("FleetPage.Text165"));
        if(action=="retrieve")command["storageId"]=(storage.SelectedItem as StoredModuleChoice)?.Id??throw new InvalidOperationException(AppText.Get("FleetPage.Text166"));
        return EditAsync(command);
    }
    private async Task ExportAsync()
    {
        var save=await DesktopContext.Local.ExportNativeAsync(AccountId,Lifetime.Token);
        var text=new TextBox{Text=save.ToJsonString(new(){WriteIndented=true}),IsReadOnly=true,AcceptsReturn=true,TextWrapping=TextWrapping.NoWrap,MinWidth=600,MaxHeight=480};
        await ShowAsync(AppText.Get("FleetPage.Text167"),text);
    }
    private async Task ImportAsync()
    {
        var text=new TextBox{AcceptsReturn=true,TextWrapping=TextWrapping.Wrap,MinWidth=600,MinHeight=300,MaxHeight=480,MaxLength=4*1024*1024,PlaceholderText=AppText.Get("FleetPage.Text168")};
        if(await ShowAsync(AppText.Get("FleetPage.Text169"),text,AppText.Get("FleetPage.Text170"))!=ContentDialogResult.Primary)return;
        await DesktopContext.Local.ImportNativeAsync(AccountId,JsonNode.Parse(text.Text)?.AsObject()??throw new InvalidDataException(AppText.Get("FleetPage.Text171")),version,Lifetime.Token);
        await LoadAsync();Success(AppText.Get("FleetPage.Text172"));
    }
}