Files
minecraft-modpack-updater/ModpackUpdater.Apps.Manager/Ui/MainWindow.axaml.cs
2025-11-17 19:02:40 +01:00

270 lines
10 KiB
C#

using System.Reflection;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Media;
using ModpackUpdater.Apps.Manager.Api;
using ModpackUpdater.Apps.Manager.Api.Model;
using ModpackUpdater.Apps.Manager.Api.Plugins.Features;
using ModpackUpdater.Apps.Manager.Api.Plugins.Params;
using ModpackUpdater.Apps.Manager.LangRes;
using ModpackUpdater.Apps.Manager.Settings;
using ModpackUpdater.Apps.Manager.Ui.Models.MainWindow;
using MsBox.Avalonia;
using MsBox.Avalonia.Enums;
using Pilz.Extensions;
using Pilz.Features;
using Pilz.UI.AvaloniaUI.Features;
using Pilz.UI.Symbols;
namespace ModpackUpdater.Apps.Manager.Ui;
public partial class MainWindow : Window, IMainApi
{
public static IImage? ButtonImageAddAction => AppGlobals.Symbols.GetImageSource(AppSymbols.add);
public static IImage? ButtonImageRemoveAction => AppGlobals.Symbols.GetImageSource(AppSymbols.remove);
private WorkspaceFeature? curWs;
public MainWindowViewModel Model { get; } = new();
Window IMainApi.MainWindow => this;
public IMainApi MainApi => this;
public bool HasClosed { get; private set; }
public MainWindow()
{
InitializeComponent();
Title = $"{Title} (v{Assembly.GetExecutingAssembly().GetAppVersion().ToShortString()})";
GridMain.DataContext = Model;
ButtonWorkspace.ImageSource = AppGlobals.Symbols.GetImageSource(AppSymbols.workspace);
MenuItemWorkspacePreferences.Icon = AppGlobals.Symbols.GetImage(AppSymbols.settings, SymbolSize.Small);
MenuItemSaveWorkspace.Icon = AppGlobals.Symbols.GetImage(AppSymbols.save, SymbolSize.Small);
MenuItemNewWorkspace.Icon = AppGlobals.Symbols.GetImage(AppSymbols.new_window, SymbolSize.Small);
MenuItemRecentWorkspaces.Icon = AppGlobals.Symbols.GetImage(AppSymbols.time_machine, SymbolSize.Small);
ButtonUpdate.ImageSource = AppGlobals.Symbols.GetImageSource(AppSymbols.update_done);
ButtonTools.ImageSource = AppGlobals.Symbols.GetImageSource(AppSymbols.tools);
MenuItemCreateUpdate.Icon = AppGlobals.Symbols.GetImage(AppSymbols.add, SymbolSize.Small);
MenuItemRemoveUpdate.Icon = AppGlobals.Symbols.GetImage(AppSymbols.remove, SymbolSize.Small);
ImageUpdate.Source = AppGlobals.Symbols.GetImageSource(AppSymbols.update_done);
ImageMetadata.Source = AppGlobals.Symbols.GetImageSource(AppSymbols.show_property);
ImageGeneral.Source = AppGlobals.Symbols.GetImageSource(AppSymbols.normal_screen);
ImageSource.Source = AppGlobals.Symbols.GetImageSource(AppSymbols.input);
ImageDestination.Source = AppGlobals.Symbols.GetImageSource(AppSymbols.output);
PluginFeatureController.Instance.Features.Get(FeatureTypes.Workspace).Ordered().InsertItemsTo(MenuItemNewWorkspace.Items,
customClickHandler: MenuItemNewWorkspaceItem_Click,
insertPrioSplitters: true);
PluginFeatureController.Instance.Features.Get(FeatureTypes.ActionsContextMenu).Ordered().InsertItemsTo(ContextMenuActions.Items,
customClickHandler: MenuItemActionItem_Click,
insertPrioSplitters: true);
var menuFlyoutTools = new MenuFlyout();
ButtonTools.Flyout = menuFlyoutTools;
PluginFeatureController.Instance.Functions.Get(FeatureTypes.Tools).InsertItemsTo(menuFlyoutTools.Items,
customClickHandler: MenuItemToolsItem_Click,
insertPrioSplitters: true);
}
private async Task LoadNewWorkspace(IWorkspace? workspace, WorkspaceFeature feature)
{
if (workspace is null)
return;
if (!await workspace.Load())
return;
if (workspace != Model.CurrentWorkspace)
{
Model.CurrentWorkspace = workspace;
curWs = feature;
}
AddToRecentFiles(workspace);
LoadRecentWorkspaces();
}
private async Task SaveWorkspace()
{
if (Model.CurrentWorkspace is not { } ws)
return;
Model.Progress.Start();
await ws.Save();
Model.Progress.Stop();
}
private void LoadRecentWorkspaces()
{
var settings = Program.Settings.Get<WorkspaceSettings>();
MenuItemRecentWorkspaces.Items.Clear();
settings.Workspaces.ForEach(config =>
{
if (PluginFeatureController.Instance.Features.Get(FeatureTypes.Workspace).OfType<WorkspaceFeature>().FirstOrDefault(n => n.Identifier == config.ProviderId) is not WorkspaceFeature feature)
return;
var item = new MenuItem
{
Header = config.DisplayText,
Icon = feature.Icon,
DataContext = new MainWindowRecentFilesItem(config, feature),
};
item.Click += MenuItemRecentWorkspaceItem_Click;
MenuItemRecentWorkspaces.Items.Add(item);
});
}
private static void AddToRecentFiles(IWorkspace workspace)
{
var settings = Program.Settings.Get<WorkspaceSettings>();
settings.Workspaces.Remove(workspace.Config);
settings.Workspaces.Insert(0, workspace.Config);
while (settings.Workspaces.Count > 20)
settings.Workspaces.RemoveAt(20);
}
private async void Window_OnLoaded(object? sender, RoutedEventArgs e)
{
var updater = new AppUpdates(Program.UpdateUrl, this);
updater.OnDownloadProgramUpdate += (o, args) => Model.Progress.Start();
await updater.UpdateApp();
Model.Progress.Stop();
LoadRecentWorkspaces();
}
private void Window_OnClosed(object? sender, EventArgs e)
{
HasClosed = true;
}
private async void Window_OnKeyDown(object? sender, KeyEventArgs e)
{
if (e.KeyModifiers == KeyModifiers.Control && e.Key == Key.Space)
await SaveWorkspace();
}
private async void MenuItemNewWorkspaceItem_Click(object? sender, RoutedEventArgs e)
{
if (sender is not MenuItem item || item.Tag is not WorkspaceFeature feature)
return;
var context = new WorkspaceContext(MainApi, null);
await feature.Configure(context);
if (!context.Canceled)
await LoadNewWorkspace(context.Workspace, feature);
}
private async void MenuItemWorkspacePreferences_OnClick(object? sender, RoutedEventArgs e)
{
if (curWs is null || Model.CurrentWorkspace is null)
return;
var context = new WorkspaceContext(MainApi, Model.CurrentWorkspace);
await curWs.Configure(context);
if (!context.Canceled)
await LoadNewWorkspace(context.Workspace, curWs);
}
private async void MenuItemSaveWorkspace_OnClick(object? sender, RoutedEventArgs e)
{
await SaveWorkspace();
}
private async void MenuItemRecentWorkspaceItem_Click(object? sender, RoutedEventArgs e)
{
if (sender is MenuItem item && item.DataContext is MainWindowRecentFilesItem tag && tag.Feature.CreateFromConfig(tag.Config) is IWorkspace workspace)
await LoadNewWorkspace(workspace, tag.Feature);
}
private async void MenuItemToolsItem_Click(object? sender, RoutedEventArgs e)
{
if (sender is MenuItem item && item.Tag is PluginFunction func)
await func.ExecuteAsync(new MainApiParameters(this));
}
private async void MenuItemActionItem_Click(object? sender, RoutedEventArgs e)
{
if (sender is MenuItem item && item.Tag is PluginFunction func)
await func.ExecuteAsync(new MainApiParameters(this));
}
private void MenuItemCreateUpdate_OnClick(object? sender, RoutedEventArgs e)
{
if (Model.CurrentWorkspace?.UpdateInfos is null
|| Model.CurrentTreeNodes?.ElementAtOrDefault(1) is not { } nodeUpdates)
return;
var update = new UpdateInfo
{
Version = new(),
};
Model.CurrentWorkspace.UpdateInfos.Updates.Insert(0, update);
nodeUpdates.Nodes.Insert(0, new ActionSetTreeNode(update));
}
private void MenuItemRemoveUpdate_OnClick(object? sender, RoutedEventArgs e)
{
if (Model.CurrentWorkspace?.UpdateInfos is null
|| Model.CurrentTreeNodes?.ElementAtOrDefault(1) is not { } nodeUpdates
|| Model.SelectedTreeNode is not ActionSetTreeNode nodeUpdate
|| nodeUpdate.Infos is not UpdateInfo update)
return;
nodeUpdates.Nodes.Remove(nodeUpdate);
Model.CurrentWorkspace.UpdateInfos.Updates.Remove(update);
}
private void ButtonAddAction_OnClick(object? sender, RoutedEventArgs e)
{
if (Model.CurrentWorkspace?.InstallInfos is not { } rootInfos
|| Model.SelectedTreeNode is not ActionSetTreeNode nodeUpdate
|| Model.CurrentGridRows is not { } rows)
return;
InstallAction action;
switch (nodeUpdate.Infos)
{
case UpdateInfo updateInfos:
updateInfos.Actions.Add((UpdateAction)(action = new UpdateAction()));
break;
case InstallInfos installInfos:
installInfos.Actions.Add(action = new InstallAction());
break;
default:
return;
}
rows.Add(new MainWindowGridRow(action, rootInfos));
}
private void ButtonRemoveAction_OnClick(object? sender, RoutedEventArgs e)
{
if (Model.SelectedGridRow is not { } row
|| Model.SelectedTreeNode is not ActionSetTreeNode nodeUpdate
|| Model.CurrentGridRows is not { } rows)
return;
switch (nodeUpdate.Infos)
{
case UpdateInfo updateInfos:
if (row.Action is UpdateAction action)
updateInfos.Actions.Remove(action);
break;
case InstallInfos installInfos:
installInfos.Actions.Remove(row.Action);
break;
default:
return;
}
rows.Remove(row);
}
}