Add create new plugin button to plugin manager

This commit is contained in:
Stone_Red
2025-02-23 15:32:56 +01:00
parent 6100f444a8
commit ffd92d2259
5 changed files with 232 additions and 1 deletions
+93
View File
@@ -0,0 +1,93 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace DesktopMagic.Helpers;
internal static class FileUtilities
{
public static bool ExistsOnPath(string fileName)
{
return GetFullPath(fileName) is not null;
}
public static string? GetFullPath(string fileName)
{
if (File.Exists(fileName))
{
return Path.GetFullPath(fileName);
}
string? values = Environment.GetEnvironmentVariable("PATH");
if (string.IsNullOrEmpty(values))
{
return null;
}
foreach (string path in values.Split(Path.PathSeparator))
{
string fullPath = Path.Combine(path, fileName);
if (File.Exists(fullPath))
{
return fullPath;
}
}
return null;
}
public static bool HasAssociatedProgram(string extension)
{
return GetAssociatedProgram(extension) is not null;
}
public static string? GetAssociatedProgram(string extension)
{
uint pcchOut = 0;
_ = AssocQueryString(AssocF.Verify, AssocStr.Executable, extension, null, null, ref pcchOut);
StringBuilder pszOut = new StringBuilder((int)pcchOut);
_ = AssocQueryString(AssocF.Verify, AssocStr.Executable, extension, null, pszOut, ref pcchOut);
if (File.Exists(pszOut.ToString()))
{
return pszOut.ToString();
}
return null;
}
[DllImport("Shlwapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern uint AssocQueryString(AssocF flags, AssocStr str, string pszAssoc, string? pszExtra, [Out] StringBuilder? pszOut, [In][Out] ref uint pcchOut);
[Flags]
public enum AssocF
{
Init_NoRemapCLSID = 0x1,
Init_ByExeName = 0x2,
Open_ByExeName = 0x2,
Init_DefaultToStar = 0x4,
Init_DefaultToFolder = 0x8,
NoUserSettings = 0x10,
NoTruncate = 0x20,
Verify = 0x40,
RemapRunDll = 0x80,
NoFixUps = 0x100,
IgnoreBaseClass = 0x200
}
public enum AssocStr
{
Command = 1,
Executable,
FriendlyDocName,
FriendlyAppName,
NoOpen,
ShellNewValue,
DDECommand,
DDEIfExec,
DDEApplication,
DDETopic
}
}
@@ -96,7 +96,15 @@
</ScrollViewer>
<Border Grid.Row="3" Grid.ColumnSpan="2" Padding="0 5 0 0" BorderThickness="0 2 0 0" BorderBrush="DarkGray">
<DockPanel>
<Image Source="{StaticResource ModioLogoBlueDark}" Cursor="Hand" Height="30" MouseUp="Image_MouseUp" HorizontalAlignment="Left" />
<Button HorizontalAlignment="Right" Click="CreatePluginButton_Click">
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="Add" Margin="0 0 10 0" />
<TextBlock Text="{DynamicResource createNewPlugin}" />
</StackPanel>
</Button>
</DockPanel>
</Border>
</Grid>
</busyIndicator:BusyMask>
@@ -1,4 +1,5 @@
using DesktopMagic.DataContexts;
using DesktopMagic.Dialogs;
using DesktopMagic.Helpers;
using Modio;
@@ -9,11 +10,13 @@ using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
@@ -34,6 +37,7 @@ public partial class PluginManager : Window
private readonly PluginManagerDataContext pluginManagerDataContext = new();
private readonly string pluginsPath = Path.Combine(App.ApplicationDataPath, "Plugins");
private readonly string pluginDevelopmentPath = Path.Combine(App.ApplicationDataPath, "PluginDevelopment");
private readonly DispatcherTimer searchTimer = new()
{
@@ -125,6 +129,9 @@ public partial class PluginManager : Window
e.Cancel = pluginManagerDataContext.IsLoading;
}
[GeneratedRegex(@"[^a-zA-Z0-9]")]
private static partial Regex IdentifierNameRegex();
private async Task Install(Mod mod)
{
pluginManagerDataContext.IsLoading = true;
@@ -235,4 +242,123 @@ public partial class PluginManager : Window
pluginManagerDataContext.IsSearching = false;
}
private void CreatePluginButton_Click(object sender, RoutedEventArgs e)
{
try
{
CreateNewPlugin();
}
catch (Exception ex)
{
App.Logger.LogError(ex.Message, source: "PluginManager");
_ = MessageBox.Show(ex.Message, "Plugin Manager", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void CreateNewPlugin()
{
if (!FileUtilities.ExistsOnPath("dotnet.exe"))
{
_ = MessageBox.Show("The .NET SDK is required to create a plugin. Please install it and try again.", "Plugin Manager", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
string pluginGuid = Guid.NewGuid().ToString();
string pluginPath = Path.Combine(pluginsPath, pluginGuid);
uint pluginId = (uint)Random.Shared.Next(1000, 9999);
InputDialog inputDialog = new((string)FindResource("enterPluginName"), "Plugin Manager")
{
Owner = this,
};
if (inputDialog.ShowDialog() is not true)
{
return;
}
string pluginName = inputDialog.ResponseText;
string pluginSafeName = pluginName.ToLower().Replace("_", " ");
TextInfo info = CultureInfo.CurrentCulture.TextInfo;
pluginSafeName = info.ToTitleCase(pluginSafeName);
pluginSafeName = IdentifierNameRegex().Replace(pluginSafeName, "");
if (!Directory.Exists(pluginDevelopmentPath))
{
_ = Directory.CreateDirectory(pluginDevelopmentPath);
}
string pluginProjectPath = Path.Combine(pluginDevelopmentPath, pluginSafeName);
if (Directory.Exists(pluginProjectPath))
{
_ = MessageBox.Show("A plugin with the same name already exists. Please choose a different name.", "Plugin Manager", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
PluginMetadata pluginMetadata = new(pluginName, pluginId);
_ = Directory.CreateDirectory(pluginPath);
_ = Directory.CreateDirectory(pluginProjectPath);
string pluginMetadataPath = Path.Combine(pluginPath, "metadata.json");
File.WriteAllText(pluginMetadataPath, JsonSerializer.Serialize(pluginMetadata));
string cmd = $"new classlib -n {pluginSafeName} -o {pluginProjectPath} -f net8.0 --target-framework-override net8.0-windows7";
Process process = Process.Start("dotnet", cmd);
process.WaitForExit();
// Install the required NuGet packages
process = Process.Start("dotnet", $"add {pluginProjectPath} package DesktopMagic.Api");
process.WaitForExit();
File.Move(Path.Combine(pluginProjectPath, "Class1.cs"), Path.Combine(pluginProjectPath, $"{pluginSafeName}.cs"));
string code = $@"using DesktopMagic.Api;
using System.Drawing;
namespace {pluginSafeName};
public class {pluginSafeName}Plugin : Plugin
{{
public override Bitmap Main()
{{
Bitmap bmp = new Bitmap(1000, 1000);
using (Graphics g = Graphics.FromImage(bmp))
{{
g.Clear(Application.Theme.PrimaryColor); // Set the background color to the color specified in the DesktopMagic application.
g.DrawString(""Hello World"", new Font(Application.Theme.Font, 100), Brushes.Black, new PointF(0, 0)); // Draw ""Hello World"" to the image.
}}
bmp.SetResolution(300, 300); // Set DPI to avoid scaling issues.
return bmp; // Return the image.
}}
}}
";
File.WriteAllText(Path.Combine(pluginProjectPath, $"{pluginSafeName}.cs"), code);
// Open the project in the default IDE
string? associatedProgram = FileUtilities.GetAssociatedProgram(".csproj");
if (associatedProgram is null)
{
_ = Process.Start("explorer.exe", pluginProjectPath);
return;
}
ProcessStartInfo psi = new ProcessStartInfo
{
FileName = associatedProgram,
Arguments = Path.Combine(pluginProjectPath, $"{pluginSafeName}.csproj"),
};
_ = Process.Start(psi);
}
}
@@ -15,6 +15,8 @@
<system:String x:Key="updatePlugins">Neu Laden</system:String>
<system:String x:Key="pluginsFolder">Plugins Ordner</system:String>
<system:String x:Key="pluginManager">Plugins Manager</system:String>
<system:String x:Key="createNewPlugin">Neues Plugin erstellen</system:String>
<system:String x:Key="enterPluginName">Pluginnamen eingeben</system:String>
<system:String x:Key="color">Farbe:</system:String>
<system:String x:Key="default">Standard</system:String>
<system:String x:Key="wantToCloseProgram">Wollen sie das Programm wirklich schließen?</system:String>
@@ -15,6 +15,8 @@
<system:String x:Key="updatePlugins">Reload</system:String>
<system:String x:Key="pluginsFolder">Plugins Folder</system:String>
<system:String x:Key="pluginManager">Plugins Manager</system:String>
<system:String x:Key="createNewPlugin">Create New Plugin</system:String>
<system:String x:Key="enterPluginName">Enter plugin name</system:String>
<system:String x:Key="color">Color:</system:String>
<system:String x:Key="default">Default</system:String>
<system:String x:Key="wantToCloseProgram">Do you really want to close the program?</system:String>