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.Settings; using ModpackUpdater.Apps.Manager.Ui.Models.MainWindow; 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.End(); } private void LoadRecentWorkspaces() { var settings = Program.Settings.Get(); MenuItemRecentWorkspaces.Items.Clear(); settings.Workspaces.ForEach(config => { if (PluginFeatureController.Instance.Features.Get(FeatureTypes.Workspace).OfType().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(); settings.Workspaces.Remove(workspace.Config); settings.Workspaces.Insert(0, workspace.Config); while (settings.Workspaces.Count > 20) settings.Workspaces.RemoveAt(20); } private void Window_OnLoaded(object? sender, RoutedEventArgs e) { 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); } }