diff --git a/src/DesktopMagic/App.xaml b/src/DesktopMagic/App.xaml
index e943dca..83dca8a 100644
--- a/src/DesktopMagic/App.xaml
+++ b/src/DesktopMagic/App.xaml
@@ -1,20 +1,25 @@
-
-
+
+
-
-
+
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/DesktopMagic/BuiltInPlugins/WeatherPlugin.cs b/src/DesktopMagic/BuiltInPlugins/WeatherPlugin.cs
index 300ca18..45f52e9 100644
--- a/src/DesktopMagic/BuiltInPlugins/WeatherPlugin.cs
+++ b/src/DesktopMagic/BuiltInPlugins/WeatherPlugin.cs
@@ -16,7 +16,7 @@ public class WeatherPlugin : AsyncPlugin
[Setting("city-name", "City Name")]
private readonly TextBox cityInput = new TextBox("Tokyo");
- [Setting("search-btn")]
+ [Setting("search-btn", "Update Location")]
private readonly Button searchButton = new Button("Update Location");
[Setting("show-city", "Show City Name")]
diff --git a/src/DesktopMagic/DataContexts/MainWindowDataContext.cs b/src/DesktopMagic/DataContexts/MainWindowDataContext.cs
index 183d23b..88aa449 100644
--- a/src/DesktopMagic/DataContexts/MainWindowDataContext.cs
+++ b/src/DesktopMagic/DataContexts/MainWindowDataContext.cs
@@ -13,6 +13,15 @@ internal class MainWindowDataContext : INotifyPropertyChanged
private static DesktopMagicSettings settings = new();
private bool isLoading = true;
+ public string Title =>
+#if DEBUG
+ $"{App.AppName} - Dev {System.Windows.Forms.Application.ProductVersion}";
+#else
+ $"{App.AppName} - {System.Windows.Forms.Application.ProductVersion}";
+#endif
+
+ public string AppName => App.AppName;
+
public DesktopMagicSettings Settings
{
get => settings;
diff --git a/src/DesktopMagic/DataContexts/PluginEntryDataContext.cs b/src/DesktopMagic/DataContexts/PluginEntryDataContext.cs
index 9fd8356..30e7ceb 100644
--- a/src/DesktopMagic/DataContexts/PluginEntryDataContext.cs
+++ b/src/DesktopMagic/DataContexts/PluginEntryDataContext.cs
@@ -1,8 +1,6 @@
using DesktopMagic.Helpers;
using DesktopMagic.Plugins;
-using MaterialDesignThemes.Wpf;
-
using System;
using System.ComponentModel;
using System.Diagnostics;
@@ -39,7 +37,7 @@ internal class PluginEntryDataContext(PluginMetadata pluginMetadata, ICommand co
public ICommand Command => command;
- public ButtonData InstallUninstallButtonData => new(mode == Mode.Install ? PackIconKind.Download : PackIconKind.Remove, GetInstallUninstallButtonText(), true, Command);
+ public ButtonData InstallUninstallButtonData => new(mode == Mode.Install ? "Download24" : "Delete24", GetInstallUninstallButtonText(), true, Command);
public ButtonData OpenButtonData
{
@@ -47,11 +45,11 @@ internal class PluginEntryDataContext(PluginMetadata pluginMetadata, ICommand co
{
if (string.IsNullOrWhiteSpace(pluginMetadata.ProfileUri?.ToString()))
{
- return new(PackIconKind.FolderOutline, (string)App.LanguageDictionary["folder"], path is not null, new CommandHandler(() => Process.Start("explorer.exe", path!)));
+ return new("Folder24", (string)App.LanguageDictionary["folder"], path is not null, new CommandHandler(() => Process.Start("explorer.exe", path!)));
}
else
{
- return new(PackIconKind.ExternalLink, "mod.io", true, new CommandHandler(OpenModIoPage));
+ return new("Open24", "mod.io", true, new CommandHandler(OpenModIoPage));
}
}
}
@@ -95,7 +93,7 @@ internal class PluginEntryDataContext(PluginMetadata pluginMetadata, ICommand co
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
- public record ButtonData(PackIconKind IconKind, string Text, bool IsEnabled, ICommand Command);
+ public record ButtonData(string Icon, string Text, bool IsEnabled, ICommand Command);
public enum Mode
{
diff --git a/src/DesktopMagic/DesktopMagic.csproj b/src/DesktopMagic/DesktopMagic.csproj
index 7f3b383..038bc52 100644
--- a/src/DesktopMagic/DesktopMagic.csproj
+++ b/src/DesktopMagic/DesktopMagic.csproj
@@ -50,6 +50,8 @@
+
+
diff --git a/src/DesktopMagic/Helpers/SettingElementGenerator.cs b/src/DesktopMagic/Helpers/SettingElementGenerator.cs
index c4040f0..f53b602 100644
--- a/src/DesktopMagic/Helpers/SettingElementGenerator.cs
+++ b/src/DesktopMagic/Helpers/SettingElementGenerator.cs
@@ -6,14 +6,10 @@ using System.Windows.Controls;
namespace DesktopMagic.Helpers;
-internal class SettingElementGenerator(ComboBox optionsComboBox)
+internal class SettingElementGenerator(uint pluginId)
{
- private readonly ComboBox optionsComboBox = optionsComboBox;
-
- public void Generate(SettingElement settingElement, DockPanel dockPanel, TextBlock textBlock)
+ public Control? Generate(SettingElement settingElement, System.Windows.Controls.TextBlock textBlock)
{
- dockPanel.UpdateLayout();
- textBlock.UpdateLayout();
if (settingElement.Input is DesktopMagic.Api.Settings.Label eLabel)
{
textBlock.Text = eLabel.Value;
@@ -32,16 +28,13 @@ internal class SettingElementGenerator(ComboBox optionsComboBox)
textBlock.Text = eLabel.Value;
});
};
+ return null;
}
else if (settingElement.Input is DesktopMagic.Api.Settings.Button eButton)
{
- Button button = new()
+ Wpf.Ui.Controls.Button button = new()
{
Content = eButton.Value,
- FontSize = 10,
- Height = 20,
- Margin = new Thickness(0, 10, 0, 10),
- Padding = new Thickness(0),
VerticalAlignment = VerticalAlignment.Center,
HorizontalAlignment = HorizontalAlignment.Stretch
};
@@ -64,16 +57,18 @@ internal class SettingElementGenerator(ComboBox optionsComboBox)
});
};
- _ = dockPanel.Children.Add(button);
+ return button;
}
else if (settingElement.Input is DesktopMagic.Api.Settings.CheckBox eCheckBox)
{
- CheckBox checkBox = new()
+ Wpf.Ui.Controls.ToggleSwitch checkBox = new()
{
IsChecked = eCheckBox.Value,
- Style = (Style)dockPanel.FindResource("MaterialDesignDarkCheckBox"),
VerticalAlignment = VerticalAlignment.Center,
- HorizontalAlignment = HorizontalAlignment.Stretch
+ HorizontalAlignment = HorizontalAlignment.Stretch,
+ HorizontalContentAlignment = HorizontalAlignment.Right,
+ Height = 30,
+ Style = Application.Current.FindResource("ToggleSwitchContentLeftStyle") as Style
};
checkBox.Click += (_s, _e) =>
{
@@ -94,11 +89,11 @@ internal class SettingElementGenerator(ComboBox optionsComboBox)
});
};
- _ = dockPanel.Children.Add(checkBox);
+ return checkBox;
}
else if (settingElement.Input is DesktopMagic.Api.Settings.TextBox eTextBox)
{
- TextBox textBox = new()
+ Wpf.Ui.Controls.TextBox textBox = new()
{
Text = eTextBox.Value,
TextWrapping = TextWrapping.Wrap,
@@ -123,26 +118,23 @@ internal class SettingElementGenerator(ComboBox optionsComboBox)
textBox.Text = eTextBox.Value;
});
};
- _ = dockPanel.Children.Add(textBox);
+ return textBox;
}
else if (settingElement.Input is DesktopMagic.Api.Settings.IntegerUpDown eIntegerUpDown)
{
- MaterialDesignThemes.Wpf.NumericUpDown numericUpDown = new()
+ Wpf.Ui.Controls.NumberBox numberBox = new()
{
Value = eIntegerUpDown.Value,
Minimum = eIntegerUpDown.Minimum,
Maximum = eIntegerUpDown.Maximum,
- IncreaseContent = new Label() { Content = "+" },
- DecreaseContent = new Label() { Content = "–" },
VerticalAlignment = VerticalAlignment.Center,
- HorizontalAlignment = HorizontalAlignment.Stretch,
- AllowChangeOnScroll = true
+ HorizontalAlignment = HorizontalAlignment.Stretch
};
- numericUpDown.ValueChanged += (_s, _e) =>
+ numberBox.ValueChanged += (_s, _e) =>
{
try
{
- eIntegerUpDown.Value = numericUpDown.Value;
+ eIntegerUpDown.Value = (int)numberBox.Value;
}
catch (Exception ex)
{
@@ -151,12 +143,12 @@ internal class SettingElementGenerator(ComboBox optionsComboBox)
};
eIntegerUpDown.OnValueChanged += () =>
{
- numericUpDown.Dispatcher.Invoke(() =>
+ numberBox.Dispatcher.Invoke(() =>
{
- numericUpDown.Value = eIntegerUpDown.Value;
+ numberBox.Value = eIntegerUpDown.Value;
});
};
- _ = dockPanel.Children.Add(numericUpDown);
+ return numberBox;
}
else if (settingElement.Input is DesktopMagic.Api.Settings.Slider eSlider)
{
@@ -168,7 +160,8 @@ internal class SettingElementGenerator(ComboBox optionsComboBox)
TickFrequency = 1,
IsSnapToTickEnabled = true,
VerticalAlignment = VerticalAlignment.Center,
- HorizontalAlignment = HorizontalAlignment.Stretch
+ HorizontalAlignment = HorizontalAlignment.Stretch,
+ Margin = new Thickness(0, 5, 0, 5)
};
slider.ValueChanged += (_s, _e) =>
{
@@ -189,7 +182,7 @@ internal class SettingElementGenerator(ComboBox optionsComboBox)
});
};
- _ = dockPanel.Children.Add(slider);
+ return slider;
}
else if (settingElement.Input is DesktopMagic.Api.Settings.ComboBox eComboBox)
{
@@ -220,19 +213,21 @@ internal class SettingElementGenerator(ComboBox optionsComboBox)
comboBox.SelectedItem = eComboBox.Value;
};
- _ = dockPanel.Children.Add(comboBox);
+ return comboBox;
}
+
+ return null;
}
private void DisplayException(string message)
{
App.Logger.LogInfo(message, source: "PluginInput");
- _ = MessageBox.Show("File execution error:\n" + message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
- int index = MainWindow.WindowNames.IndexOf(optionsComboBox.SelectedItem.ToString() ?? string.Empty);
+ _ = System.Windows.MessageBox.Show("File execution error:\n" + message, "Error", System.Windows.MessageBoxButton.OK, MessageBoxImage.Error);
+ int index = Manager.Instance.PluginWindows.FindIndex(p => p.PluginMetadata.Id == pluginId);
- if (index >= 0 && index < MainWindow.Windows.Count)
+ if (index >= 0 && index < Manager.Instance.PluginWindows.Count)
{
- IPluginWindow window = MainWindow.Windows[index];
+ IPluginWindow window = Manager.Instance.PluginWindows[index];
window?.Exit();
}
}
diff --git a/src/DesktopMagic/Helpers/UnderscoreEscapingConverter.cs b/src/DesktopMagic/Helpers/UnderscoreEscapingConverter.cs
new file mode 100644
index 0000000..7b057ed
--- /dev/null
+++ b/src/DesktopMagic/Helpers/UnderscoreEscapingConverter.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Globalization;
+using System.Windows.Data;
+
+namespace DesktopMagic.Helpers;
+
+public class UnderscoreEscapingConverter : IValueConverter
+{
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ if (value is string text)
+ {
+ // Replaces single underscores with double underscores to escape them in labels
+ return text.Replace("_", "__");
+ }
+ return value;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+}
diff --git a/src/DesktopMagic/MainWindow.xaml b/src/DesktopMagic/MainWindow.xaml
index 1c1b7be..1dfe583 100644
--- a/src/DesktopMagic/MainWindow.xaml
+++ b/src/DesktopMagic/MainWindow.xaml
@@ -1,156 +1,106 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
-
-
\ No newline at end of file
+
+
\ No newline at end of file
diff --git a/src/DesktopMagic/MainWindow.xaml.cs b/src/DesktopMagic/MainWindow.xaml.cs
index 2be98b0..614e1b6 100644
--- a/src/DesktopMagic/MainWindow.xaml.cs
+++ b/src/DesktopMagic/MainWindow.xaml.cs
@@ -1,663 +1,171 @@
-using DesktopMagic.BuiltInPlugins;
-using DesktopMagic.DataContexts;
-using DesktopMagic.Dialogs;
-using DesktopMagic.Helpers;
-using DesktopMagic.Plugins;
-using DesktopMagic.Settings;
+using DesktopMagic.DataContexts;
using System;
-using System.Collections.Generic;
using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Text.Json;
using System.Windows;
-using System.Windows.Controls;
-namespace DesktopMagic
+using Wpf.Ui.Appearance;
+using Wpf.Ui.Controls;
+
+namespace DesktopMagic;
+
+public partial class MainWindow : FluentWindow
{
- public partial class MainWindow : Window
+ private readonly System.Windows.Forms.NotifyIcon _notifyIcon = new();
+ private readonly Manager _manager = Manager.Instance;
+ private readonly MainWindowDataContext _mainWindowDataContext = new();
+
+ public MainWindow()
{
- private readonly System.Windows.Forms.NotifyIcon notifyIcon = new();
+ SystemThemeWatcher.Watch(this);
- private readonly MainWindowDataContext mainWindowDataContext = new();
+ InitializeComponent();
- private readonly Dictionary builtInPlugins = new()
+ DataContext = _mainWindowDataContext;
+ _mainWindowDataContext.Settings = _manager.Settings;
+
+ Resources.MergedDictionaries.Add(App.LanguageDictionary);
+ }
+
+ private void Window_Loaded(object sender, RoutedEventArgs e)
+ {
+ try
{
- {new((string)App.LanguageDictionary["musicVisualizer"], 1), typeof(MusicVisualizerPlugin)},
- {new((string)App.LanguageDictionary["time"],2), typeof(TimePlugin)},
- {new((string)App.LanguageDictionary["date"],3), typeof(DatePlugin)},
- {new((string)App.LanguageDictionary["cpuUsage"], 4), typeof(CpuMonitorPlugin)},
- {new((string)App.LanguageDictionary["weather"], 5), typeof(WeatherPlugin)},
- };
+ App.Logger.LogInfo("Loading application", source: "MainWindow");
- private bool loaded = false;
- private bool blockWindowsClosing = true;
- public static List Windows { get; } = [];
- public static List WindowNames { get; } = [];
+ _mainWindowDataContext.IsLoading = true;
- private DesktopMagicSettings Settings
- {
- get => mainWindowDataContext.Settings;
- set => mainWindowDataContext.Settings = value;
+ // Load plugins and settings through manager
+ _manager.LoadPlugins();
+ _manager.LoadSettings();
+ _manager.LoadLayout();
+
+ _manager.IsLoaded = true;
+ _mainWindowDataContext.IsLoading = false;
+
+ App.Logger.LogInfo("Application loaded", source: "MainWindow");
}
-
- public MainWindow()
+ catch (Exception ex)
{
- DataContext = mainWindowDataContext;
-
- try
- {
- Stream iconStream = Application.GetResourceStream(new Uri("pack://application:,,,/DesktopMagic;component/icon.ico")).Stream;
- notifyIcon.MouseClick += NotifyIcon_MouseClick;
- notifyIcon.Visible = true;
- notifyIcon.Text = App.AppName;
- notifyIcon.Icon = new System.Drawing.Icon(iconStream);
- notifyIcon.ContextMenuStrip = new System.Windows.Forms.ContextMenuStrip()
- {
- Items =
- {
- new System.Windows.Forms.ToolStripMenuItem((string)App.LanguageDictionary["open"], null, (s, e) => RestoreWindow()),
- new System.Windows.Forms.ToolStripMenuItem((string)App.LanguageDictionary["toggleEditMode"], null, (s, e) => { editCheckBox.IsChecked = !editCheckBox.IsChecked; EditCheckBox_Click(null, null); }),
- new System.Windows.Forms.ToolStripMenuItem((string)App.LanguageDictionary["pluginManager"], null, (s, e) => PluginManagerButton_Click(null!, null!)),
- new System.Windows.Forms.ToolStripMenuItem("GitHub", null, (s, e) => GitHubButton_Click(null!, null!)),
- new System.Windows.Forms.ToolStripMenuItem((string)App.LanguageDictionary["quit"], null, (s, e) => Quit()),
- }
- };
-
- InitializeComponent();
-
- Resources.MergedDictionaries.Add(App.LanguageDictionary);
-
-#if DEBUG
- Title = $"{App.AppName} - Dev {System.Windows.Forms.Application.ProductVersion}";
-#else
- Title = $"{App.AppName} - {System.Windows.Forms.Application.ProductVersion}";
-#endif
- }
- catch (Exception ex)
- {
- _ = MessageBox.Show(ex.ToString(), App.AppName, MessageBoxButton.OK, MessageBoxImage.Error);
- }
+ App.Logger.LogError(ex.Message, source: "MainWindow");
+ _ = System.Windows.MessageBox.Show(ex.ToString(), App.AppName, System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
}
+ }
- #region Load
+ private async void NavigationView_Loaded(object sender, RoutedEventArgs e)
+ {
+ _ = NavigationView.Navigate(typeof(Pages.MainPage));
+ }
- private readonly Dictionary plugins = [];
+ private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
+ {
+ _manager.SaveSettings();
- private void Window_Loaded(object sender, RoutedEventArgs e)
- {
- try
- {
- //Write To Log File and Load Elements
-
- App.Logger.LogInfo("Loading Plugin names", source: "Main");
- LoadPlugins();
- App.Logger.LogInfo("Loading Layout names", source: "Main");
- LoadSettings();
- App.Logger.LogInfo("Loading Layout", source: "Main");
- LoadLayout();
-
- loaded = true;
- App.Logger.LogInfo("Window Loaded", source: "Main");
- }
- catch (Exception ex)
- {
- App.Logger.LogError(ex.Message, source: "Main");
- _ = MessageBox.Show(ex.ToString(), App.AppName, MessageBoxButton.OK, MessageBoxImage.Error);
- }
- }
-
- private void LoadPlugins()
- {
- mainWindowDataContext.IsLoading = true;
- plugins.Clear();
-
- foreach (var buildInPlugin in builtInPlugins.Keys)
- {
- plugins.Add(buildInPlugin.Id, new(buildInPlugin, PluginType.DotNet, string.Empty));
- }
-
- foreach (string directory in Directory.GetDirectories(App.PluginsPath))
- {
- string? pluginDllPath = Directory.GetFiles(directory, "main.dll").FirstOrDefault();
- string? pluginHtmlPath = Directory.GetFiles(directory, "main.html").FirstOrDefault();
- string? pluginMetadataPath = Directory.GetFiles(directory, "metadata.json").FirstOrDefault();
-
- if (pluginDllPath is null && pluginHtmlPath is null)
- {
- App.Logger.LogError($"Plugin \"{directory}\" has no \"main.dll\" or \"main.html\"", source: "Main");
- continue;
- }
-
- if (pluginMetadataPath is null)
- {
- App.Logger.LogWarn($"Plugin \"{directory}\" has no \"metadata.json\"", source: "Main");
- continue;
- }
-
- PluginMetadata? pluginMetadata = JsonSerializer.Deserialize(File.ReadAllText(pluginMetadataPath));
-
- if (pluginMetadata is null)
- {
- App.Logger.LogError($"Plugin \"{directory}\" has no valid \"metadata.json\"", source: "Main");
- continue;
- }
-
- if (plugins.ContainsKey(pluginMetadata.Id))
- {
- App.Logger.LogError($"Plugin \"{directory}\" has the same id as another plugin", source: "Main");
- continue;
- }
-
- PluginType pluginType = PluginType.DotNet;
-
- if (pluginHtmlPath is not null)
- {
- pluginType = PluginType.Web;
- }
-
- plugins.Add(pluginMetadata.Id, new(pluginMetadata, pluginType, directory));
- }
- mainWindowDataContext.IsLoading = false;
- }
-
- #endregion Load
-
- #region Windows
-
- private void EditCheckBox_Click(object? sender, RoutedEventArgs? e)
- {
- foreach (IPluginWindow window in Windows)
- {
- window.SetEditMode(editCheckBox.IsChecked == true);
- }
-
- SaveSettings();
- }
-
- private void PluginCheckBox_Click(object sender, RoutedEventArgs? e)
- {
- if (sender is not CheckBox checkBox)
- {
- return;
- }
-
- LoadPlugin(uint.Parse(checkBox.Tag.ToString()!));
- }
-
- private void LoadPlugin(uint pluginId)
- {
- if (!plugins.TryGetValue(pluginId, out InternalPluginData? internalPluginData))
- {
- return;
- }
-
- if (!Settings.CurrentLayout.Plugins.TryGetValue(pluginId, out PluginSettings? pluginSettings))
- {
- pluginSettings = new PluginSettings();
- Settings.CurrentLayout.Plugins.Add(pluginId, pluginSettings);
- }
-
- if (WindowNames.Contains(internalPluginData.Metadata.Id.ToString()) || !pluginSettings.Enabled)
- {
- int index = WindowNames.IndexOf(internalPluginData.Metadata.Id.ToString());
-
- if (index >= 0)
- {
- try
- {
- blockWindowsClosing = false;
- Windows[index].Close();
- blockWindowsClosing = true;
- Windows.RemoveAt(index);
- WindowNames.RemoveAt(index);
- }
- catch (Exception ex)
- {
- App.Logger.LogError(ex.Message, source: "Main");
- }
- }
- return;
- }
-
- IPluginWindow window;
-
- if (builtInPlugins.TryGetValue(internalPluginData.Metadata, out Type? pluginType))
- {
- window = new PluginWindow((Api.Plugin)Activator.CreateInstance(pluginType)!, internalPluginData.Metadata, pluginSettings)
- {
- Title = internalPluginData.Metadata.Id.ToString()
- };
- }
- else if (internalPluginData.Type == PluginType.Web)
- {
- window = new WebPluginWindow(internalPluginData.Metadata, pluginSettings, internalPluginData.DirectoryPath)
- {
- Title = internalPluginData.Metadata.Id.ToString()
- };
- }
- else
- {
- window = new PluginWindow(internalPluginData.Metadata, pluginSettings, internalPluginData.DirectoryPath)
- {
- Title = internalPluginData.Metadata.Id.ToString()
- };
- }
-
- Action? onPluginLoaded = null;
- onPluginLoaded = () =>
- {
- Dispatcher.Invoke(() =>
- {
- if (!optionsComboBox.Items.Contains(internalPluginData.Metadata))
- {
- _ = optionsComboBox.Items.Add(internalPluginData.Metadata);
- }
- optionsComboBox.SelectedIndex = -1;
- optionsComboBox.SelectedIndex = optionsComboBox.Items.IndexOf(internalPluginData.Metadata);
-
- window.PluginLoaded -= onPluginLoaded;
- });
- };
-
- Action onExit = () =>
- {
- Windows.Remove(window);
- WindowNames.Remove(window.Title);
- blockWindowsClosing = false;
- window.Close();
- blockWindowsClosing = true;
- pluginSettings.Enabled = false;
- };
-
- window.PluginLoaded += onPluginLoaded;
- window.OnExit += onExit;
-
- window.Show();
- window.SetEditMode(editCheckBox.IsChecked == true);
-
- window.Closing += DisplayWindow_Closing;
- Windows.Add(window);
- WindowNames.Add(window.Title);
- }
-
- private void DisplayWindow_Closing(object? sender, System.ComponentModel.CancelEventArgs e)
- {
- e.Cancel = blockWindowsClosing;
- }
-
- private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
- {
- SaveSettings();
-
- if (blockWindowsClosing)
- {
- e.Cancel = true;
-
- editCheckBox.IsChecked = false;
- EditCheckBox_Click(null, null);
- ShowInTaskbar = false;
- WindowState = WindowState.Minimized;
- Visibility = Visibility.Collapsed;
- }
- }
-
- private void Window_Closed(object sender, EventArgs e)
+ if (_manager.BlockWindowsClosing)
{
+ e.Cancel = true;
+ _manager.SetEditMode(false);
+ ShowInTaskbar = false;
+ WindowState = WindowState.Minimized;
Visibility = Visibility.Collapsed;
- UpdateLayout();
- foreach (IPluginWindow window in Windows)
- {
- window.Hide();
- }
- Environment.Exit(0);
}
+ }
- #endregion Windows
+ private void Window_Closed(object sender, EventArgs e)
+ {
+ Visibility = Visibility.Collapsed;
+ UpdateLayout();
+ _manager.CloseAllPluginWindows();
+ _notifyIcon.Dispose();
+ Environment.Exit(0);
+ }
- #region Options
-
- private void AddThemeButton_Click(object sender, RoutedEventArgs e)
+ private void NotifyIcon_MouseClick(object? sender, System.Windows.Forms.MouseEventArgs e)
+ {
+ if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
- InputDialog inputDialog = new((string)FindResource("enterThemeName"))
- {
- Owner = this
- };
-
- if (inputDialog.ShowDialog() == true)
- {
- if (Settings.Themes.Any(l => l.Name.Trim() == inputDialog.ResponseText.Trim()))
- {
- _ = MessageBox.Show((string)FindResource("themeAlreadyExists"), App.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
- return;
- }
-
- Settings.Themes.Add(new Theme(inputDialog.ResponseText.Trim()));
- Settings.CurrentLayout.CurrentThemeName = inputDialog.ResponseText.Trim();
- SaveSettings();
- }
+ RestoreWindow();
}
+ }
- private void DeleteThemeButton_Click(object sender, RoutedEventArgs e)
+ internal void RestoreWindow()
+ {
+ for (int i = 0; i < 10; i++)
{
- if (Settings.Themes.Count <= 1)
- {
- _ = MessageBox.Show((string)FindResource("cannotDeleteLastTheme"), App.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
- return;
- }
-
- MessageBoxResult result = MessageBox.Show((string)FindResource("confirmDeleteTheme"), App.AppName, MessageBoxButton.YesNo, MessageBoxImage.Question);
- if (result != MessageBoxResult.Yes)
- {
- return;
- }
-
- Settings.Themes.Remove((Theme)themesListBox.SelectedItem);
- SaveSettings();
+ ShowInTaskbar = true;
+ Visibility = Visibility.Visible;
+ SystemCommands.RestoreWindow(this);
+ Topmost = true;
+ _ = Activate();
+ Topmost = false;
}
+ }
- private void ChangeThemeButton_Click(object sender, RoutedEventArgs e)
+ private void Quit()
+ {
+ _manager.BlockWindowsClosing = false;
+ Close();
+ }
+
+ private void ToggleEditMode()
+ {
+ _manager.SetEditMode(!_manager.IsEditMode);
+ }
+
+ private void OpenPluginManager()
+ {
+ RestoreWindow();
+ _ = NavigationView.Navigate(typeof(Plugins.PluginManager));
+ }
+
+ private void UpdatePlugins()
+ {
+ _mainWindowDataContext.IsLoading = true;
+ _manager.LoadPlugins();
+ _manager.LoadLayout(false);
+ _mainWindowDataContext.IsLoading = false;
+ }
+
+ private void ReportBugNavigationViewItem_Click(object sender, RoutedEventArgs e)
+ {
+ string uri = "https://github.com/Stone-Red-Code/DesktopMagic/issues/new?template=bug_report.md";
+ ProcessStartInfo psi = new()
{
- Theme theme = themesListBox.SelectedItem as Theme ?? Settings.CurrentLayout.Theme;
-
- ThemeDialog themeDialog = new(theme.Name, theme, App.AppName)
- {
- Owner = this
- };
-
- themeDialog.ShowDialog();
- }
-
- private void OptionsComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
- {
- optionsPanel.Visibility = Visibility.Visible;
- optionsPanel.Children.Clear();
- optionsPanel.UpdateLayout();
-
- if (optionsComboBox.SelectedItem is null)
- {
- return;
- }
-
- bool success = Settings.CurrentLayout.Plugins.TryGetValue(((PluginMetadata)optionsComboBox.SelectedItem).Id, out Settings.PluginSettings? pluginSettings);
- if (!success || pluginSettings is null || pluginSettings.Settings.Count == 0)
- {
- _ = optionsPanel.Children.Add(new TextBlock() { Text = (string)FindResource("noOptions") });
- return;
- }
-
- SettingElementGenerator settingElementGenerator = new SettingElementGenerator(optionsComboBox);
-
- foreach (SettingElement settingElement in pluginSettings.Settings)
- {
- DockPanel dockPanel = new()
- {
- LastChildFill = true,
- HorizontalAlignment = HorizontalAlignment.Stretch,
- Margin = new Thickness(0, 0, 0, 5)
- };
- _ = optionsPanel.Children.Add(dockPanel);
-
- TextBlock textBlock = new()
- {
- Text = string.IsNullOrWhiteSpace(settingElement.Name) ? string.Empty : $"{settingElement.Name}:",
- Padding = new Thickness(0, 0, 3, 0),
- VerticalAlignment = VerticalAlignment.Center
- };
-
- _ = dockPanel.Children.Add(textBlock);
- settingElementGenerator.Generate(settingElement, dockPanel, textBlock);
- }
- }
-
- #endregion Options
-
- internal void RestoreWindow()
- {
- for (int i = 0; i < 10; i++)
- {
- ShowInTaskbar = true;
- Visibility = Visibility.Visible;
- SystemCommands.RestoreWindow(this);
- Topmost = true;
- _ = Activate();
- Topmost = false;
- }
- }
-
- private void Quit()
- {
- blockWindowsClosing = false;
- Close();
- }
-
- private void OpenPluginsFolderButton_Click(object sender, RoutedEventArgs e)
- {
- _ = Process.Start("explorer.exe", App.PluginsPath);
- }
-
- private void ScrollViewer_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
- {
- ScrollViewer scv = (ScrollViewer)sender;
- scv.ScrollToVerticalOffset(scv.VerticalOffset - e.Delta);
- e.Handled = true;
- }
-
- #region Layout
-
- private readonly JsonSerializerOptions jsonSettingsOptions = new()
- {
- Converters =
- {
- new ColorJsonConverter()
- }
+ UseShellExecute = true,
+ FileName = uri
};
-
- private void LayoutsComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
- {
- if (loaded)
- {
- SaveSettings();
- LoadLayout(false);
- }
- }
-
- private void NewLayoutButton_Click(object sender, RoutedEventArgs e)
- {
- InputDialog inputDialog = new((string)FindResource("enterLayoutName"))
- {
- Owner = this
- };
-
- if (inputDialog.ShowDialog() == true)
- {
- if (Settings.Layouts.Any(l => l.Name.Trim() == inputDialog.ResponseText.Trim()))
- {
- _ = MessageBox.Show((string)FindResource("layoutAlreadyExists"), App.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
- return;
- }
-
- Settings.Layouts.Add(new Layout(inputDialog.ResponseText.Trim()));
- Settings.CurrentLayoutName = inputDialog.ResponseText.Trim();
- SaveSettings();
- }
- }
-
- private void RemoveLayoutButton_Click(object sender, RoutedEventArgs e)
- {
- if (Settings.Layouts.Count <= 1)
- {
- _ = MessageBox.Show((string)FindResource("cannotDeleteLastLayout"), App.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
- return;
- }
-
- MessageBoxResult result = MessageBox.Show((string)FindResource("confirmDeleteLayout"), App.AppName, MessageBoxButton.YesNo, MessageBoxImage.Question);
- if (result != MessageBoxResult.Yes)
- {
- return;
- }
-
- Settings.Layouts.Remove(Settings.CurrentLayout);
- SaveSettings();
- }
-
- private void SaveSettings()
- {
- if (!loaded)
- {
- return;
- }
-
- string json = JsonSerializer.Serialize(Settings, jsonSettingsOptions);
- File.WriteAllText(Path.Combine(App.ApplicationDataPath, "settings.json"), json);
- }
-
- private void LoadSettings()
- {
- if (!File.Exists(Path.Combine(App.ApplicationDataPath, "settings.json")))
- {
- Settings = new DesktopMagicSettings();
-
- Settings.Layouts.Add(new Layout((string)FindResource("default")));
- Settings.Themes.Add(new Theme((string)FindResource("default")));
-
- return;
- }
-
- string json = File.ReadAllText(Path.Combine(App.ApplicationDataPath, "settings.json"));
-
- Settings = JsonSerializer.Deserialize(json, jsonSettingsOptions) ?? new DesktopMagicSettings();
-
- if (Settings.Layouts.Count == 0)
- {
- Settings.Layouts.Add(new Layout((string)FindResource("default")));
- }
-
- if (Settings.Themes.Count == 0)
- {
- Settings.Themes.Add(new Theme((string)FindResource("default")));
- }
- }
-
- private void LoadLayout(bool minimize = true)
- {
- mainWindowDataContext.IsLoading = true;
- blockWindowsClosing = false;
-
- foreach (IPluginWindow window in Windows)
- {
- window.Close();
- }
-
- editCheckBox.IsChecked = false;
- EditCheckBox_Click(null, null);
- blockWindowsClosing = true;
- Windows.Clear();
- WindowNames.Clear();
- optionsComboBox.Items.Clear();
-
- bool showWindow = true;
-
- // Load plugins
- foreach (uint pluginId in plugins.Keys)
- {
- InternalPluginData internalPluginData = plugins[pluginId];
-
- // Add plugin to layout if it doesn't exist
- if (!Settings.CurrentLayout.Plugins.TryGetValue(pluginId, out PluginSettings? pluginSettings))
- {
- Settings.CurrentLayout.Plugins.Add(pluginId, new PluginSettings() { Name = internalPluginData.Metadata.Name });
-
- continue;
- }
-
- pluginSettings.Name = internalPluginData.Metadata.Name;
-
- if (pluginSettings.Enabled)
- {
- LoadPlugin(pluginId);
- }
-
- if (showWindow && pluginSettings.Enabled)
- {
- showWindow = false;
- }
- }
-
- // Remove plugins that are not loaded anymore
- foreach (uint pluginId in Settings.CurrentLayout.Plugins.Keys)
- {
- if (!plugins.ContainsKey(pluginId))
- {
- Settings.CurrentLayout.Plugins.Remove(pluginId);
- }
- }
-
- Settings.CurrentLayout.UpdatePlugins();
-
- if (!showWindow && minimize)
- {
- Close();
- }
- else
- {
- RestoreWindow();
- }
-
- mainWindowDataContext.IsLoading = false;
- }
-
- #endregion Layout
-
- private void UpdatePluginsButton_Click(object sender, RoutedEventArgs e)
- {
- LoadPlugins();
- LoadLayout(false);
- }
-
- private void NotifyIcon_MouseClick(object? sender, System.Windows.Forms.MouseEventArgs e)
- {
- if (e.Button == System.Windows.Forms.MouseButtons.Left)
- {
- RestoreWindow();
- }
- }
-
- private void GitHubButton_Click(object sender, RoutedEventArgs e)
- {
- string uri = "https://github.com/Stone-Red-Code/DesktopMagic";
- ProcessStartInfo psi = new ProcessStartInfo
- {
- UseShellExecute = true,
- FileName = uri
- };
- _ = Process.Start(psi);
- }
-
- private void PluginManagerButton_Click(object sender, RoutedEventArgs e)
- {
- PluginManager pluginManager = new PluginManager
- {
- Owner = this
- };
-
- pluginManager.ShowDialog();
- LoadPlugins();
- LoadLayout(Visibility != Visibility.Visible);
- }
+ _ = Process.Start(psi);
}
- internal class InternalPluginData(PluginMetadata pluginMetadata, PluginType pluginType, string directoryPath)
+ private void RequestFeatureNavigationViewItem_Click(object sender, RoutedEventArgs e)
{
- public PluginMetadata Metadata { get; set; } = pluginMetadata;
- public PluginType Type { get; set; } = pluginType;
- public string DirectoryPath { get; set; } = directoryPath;
-
+ string uri = "https://github.com/Stone-Red-Code/DesktopMagic/issues/new?template=feature_request.md";
+ ProcessStartInfo psi = new()
+ {
+ UseShellExecute = true,
+ FileName = uri
+ };
+ _ = Process.Start(psi);
}
- internal enum PluginType
+
+ private void NotifyIcon_LeftClick(Wpf.Ui.Tray.Controls.NotifyIcon sender, RoutedEventArgs e)
{
- DotNet,
- Web
+ RestoreWindow();
+ }
+
+ private void SettingsMenuItem_Click(object sender, RoutedEventArgs e)
+ {
+ RestoreWindow();
+ _ = NavigationView.Navigate(typeof(Pages.MainPage));
+ }
+
+ private void EditLayoutMenuItem_Click(object sender, RoutedEventArgs e)
+ {
+ _manager.SetEditMode(!_manager.IsEditMode);
+ }
+
+ private void QuitMenuItem_Click(object sender, RoutedEventArgs e)
+ {
+ Quit();
}
}
\ No newline at end of file
diff --git a/src/DesktopMagic/Manager.cs b/src/DesktopMagic/Manager.cs
new file mode 100644
index 0000000..ccbd0a3
--- /dev/null
+++ b/src/DesktopMagic/Manager.cs
@@ -0,0 +1,365 @@
+using DesktopMagic.BuiltInPlugins;
+using DesktopMagic.Helpers;
+using DesktopMagic.Plugins;
+using DesktopMagic.Settings;
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text.Json;
+using System.Windows;
+
+namespace DesktopMagic;
+
+///
+/// Singleton Manager class that handles global state, plugin management, and shared operations
+///
+public sealed class Manager
+{
+ private static Manager? _instance;
+ private static readonly object _lock = new();
+
+ public static Manager Instance
+ {
+ get
+ {
+ if (_instance == null)
+ {
+ lock (_lock)
+ {
+ _instance ??= new Manager();
+ }
+ }
+ return _instance;
+ }
+ }
+
+ // Plugin management
+ private readonly Dictionary _plugins = [];
+ private readonly Dictionary _builtInPlugins = new()
+ {
+ {new((string)App.LanguageDictionary["musicVisualizer"], 1) { Author = "Stone_Red" }, typeof(MusicVisualizerPlugin)},
+ {new((string)App.LanguageDictionary["time"],2) { Author = "Stone_Red" }, typeof(TimePlugin)},
+ {new((string)App.LanguageDictionary["date"],3) { Author = "Stone_Red" }, typeof(DatePlugin)},
+ {new((string)App.LanguageDictionary["cpuUsage"], 4) { Author = "Stone_Red" }, typeof(CpuMonitorPlugin)},
+ {new((string)App.LanguageDictionary["weather"], 5) { Author = "Stone_Red" }, typeof(WeatherPlugin)},
+ };
+
+ // Window management
+ public List PluginWindows { get; } = [];
+
+ public IReadOnlyDictionary Plugins => _plugins;
+
+ public bool BlockWindowsClosing { get; set; } = true;
+
+ // Edit mode tracking
+ private bool _isEditMode = false;
+ public bool IsEditMode => _isEditMode;
+
+ // Settings
+ public DesktopMagicSettings Settings { get; set; } = new();
+ public bool IsLoaded { get; set; } = false;
+
+ private readonly JsonSerializerOptions _jsonSettingsOptions = new()
+ {
+ Converters = { new ColorJsonConverter() }
+ };
+
+ // Events
+ public event Action? PluginsChanged;
+ public event Action? SettingsChanged;
+ public event Action? EditModeChanged;
+
+ private Manager()
+ {
+ // Private constructor for singleton
+ }
+
+ #region Plugin Management
+
+ public Dictionary GetPlugins() => new(_plugins);
+
+ public void LoadPlugins()
+ {
+ App.Logger.LogInfo("Loading plugins", source: "Manager");
+ _plugins.Clear();
+
+ // Load built-in plugins
+ foreach (var builtInPlugin in _builtInPlugins.Keys)
+ {
+ _plugins.Add(builtInPlugin.Id, new(builtInPlugin, PluginType.DotNet, string.Empty));
+ }
+
+ // Load external plugins
+ foreach (string directory in Directory.GetDirectories(App.PluginsPath))
+ {
+ string? pluginDllPath = Directory.GetFiles(directory, "main.dll").FirstOrDefault();
+ string? pluginHtmlPath = Directory.GetFiles(directory, "main.html").FirstOrDefault();
+ string? pluginMetadataPath = Directory.GetFiles(directory, "metadata.json").FirstOrDefault();
+
+ if (pluginDllPath is null && pluginHtmlPath is null)
+ {
+ App.Logger.LogError($"Plugin \"{directory}\" has no \"main.dll\" or \"main.html\"", source: "Manager");
+ continue;
+ }
+
+ if (pluginMetadataPath is null)
+ {
+ App.Logger.LogWarn($"Plugin \"{directory}\" has no \"metadata.json\"", source: "Manager");
+ continue;
+ }
+
+ PluginMetadata? pluginMetadata = JsonSerializer.Deserialize(File.ReadAllText(pluginMetadataPath));
+
+ if (pluginMetadata is null)
+ {
+ App.Logger.LogError($"Plugin \"{directory}\" has no valid \"metadata.json\"", source: "Manager");
+ continue;
+ }
+
+ if (_plugins.ContainsKey(pluginMetadata.Id))
+ {
+ App.Logger.LogError($"Plugin \"{directory}\" has the same id as another plugin", source: "Manager");
+ continue;
+ }
+
+ PluginType pluginType = pluginHtmlPath is not null ? PluginType.Web : PluginType.DotNet;
+
+ _plugins.Add(pluginMetadata.Id, new(pluginMetadata, pluginType, directory));
+ }
+
+ PluginsChanged?.Invoke();
+ App.Logger.LogInfo($"Loaded {_plugins.Count} plugins", source: "Manager");
+ }
+
+ public void LoadPlugin(uint pluginId, Action? onPluginLoaded = null)
+ {
+ if (!_plugins.TryGetValue(pluginId, out InternalPluginData? internalPluginData))
+ {
+ return;
+ }
+
+ if (!Settings.CurrentLayout.Plugins.TryGetValue(pluginId, out PluginSettings? pluginSettings))
+ {
+ pluginSettings = new PluginSettings();
+ Settings.CurrentLayout.Plugins.Add(pluginId, pluginSettings);
+ }
+
+ IPluginWindow? existingWindow = PluginWindows.FirstOrDefault(w => w.PluginMetadata.Id == internalPluginData.Metadata.Id);
+
+ if (existingWindow is not null || !pluginSettings.Enabled)
+ {
+ // Close the window if it's already open or disabled
+ if (existingWindow is not null)
+ {
+ try
+ {
+ BlockWindowsClosing = false;
+ existingWindow.Close();
+ BlockWindowsClosing = true;
+ PluginWindows.Remove(existingWindow);
+ }
+ catch (Exception ex)
+ {
+ App.Logger.LogError(ex.Message, source: "Manager");
+ }
+ }
+ return;
+ }
+
+ IPluginWindow window;
+
+ if (_builtInPlugins.TryGetValue(internalPluginData.Metadata, out Type? pluginType))
+ {
+ window = new PluginWindow((Api.Plugin)Activator.CreateInstance(pluginType)!, internalPluginData.Metadata, pluginSettings)
+ {
+ Title = internalPluginData.Metadata.Id.ToString()
+ };
+ }
+ else if (internalPluginData.Type == PluginType.Web)
+ {
+ window = new WebPluginWindow(internalPluginData.Metadata, pluginSettings, internalPluginData.DirectoryPath)
+ {
+ Title = internalPluginData.Metadata.Id.ToString()
+ };
+ }
+ else
+ {
+ window = new PluginWindow(internalPluginData.Metadata, pluginSettings, internalPluginData.DirectoryPath)
+ {
+ Title = internalPluginData.Metadata.Id.ToString()
+ };
+ }
+
+ Action? pluginLoadedHandler = null;
+ pluginLoadedHandler = () =>
+ {
+ onPluginLoaded?.Invoke(internalPluginData);
+ window.PluginLoaded -= pluginLoadedHandler;
+ };
+
+ Action exitHandler = () =>
+ {
+ PluginWindows.Remove(window);
+ BlockWindowsClosing = false;
+ window.Close();
+ BlockWindowsClosing = true;
+ pluginSettings.Enabled = false;
+ };
+
+ window.PluginLoaded += pluginLoadedHandler;
+ window.OnExit += exitHandler;
+
+ window.Show();
+ window.SetEditMode(_isEditMode);
+
+ PluginWindows.Add(window);
+ }
+
+ public void SetEditMode(bool editMode)
+ {
+ _isEditMode = editMode;
+ foreach (IPluginWindow window in PluginWindows)
+ {
+ window.SetEditMode(editMode);
+ }
+ EditModeChanged?.Invoke(editMode);
+ SaveSettings();
+ }
+
+ #endregion
+
+ #region Settings Management
+
+ public void LoadSettings()
+ {
+ App.Logger.LogInfo("Loading settings", source: "Manager");
+
+ if (!File.Exists(Path.Combine(App.ApplicationDataPath, "settings.json")))
+ {
+ Settings = new DesktopMagicSettings();
+ Settings.Layouts.Add(new Layout("Default"));
+ Settings.Themes.Add(new Theme("Default"));
+ return;
+ }
+
+ string json = File.ReadAllText(Path.Combine(App.ApplicationDataPath, "settings.json"));
+ Settings = JsonSerializer.Deserialize(json, _jsonSettingsOptions) ?? new DesktopMagicSettings();
+
+ if (Settings.Layouts.Count == 0)
+ {
+ Settings.Layouts.Add(new Layout("Default"));
+ }
+
+ if (Settings.Themes.Count == 0)
+ {
+ Settings.Themes.Add(new Theme("Default"));
+ }
+
+ SettingsChanged?.Invoke();
+ }
+
+ public void SaveSettings()
+ {
+ if (!IsLoaded)
+ {
+ return;
+ }
+
+ string json = JsonSerializer.Serialize(Settings, _jsonSettingsOptions);
+ File.WriteAllText(Path.Combine(App.ApplicationDataPath, "settings.json"), json);
+ App.Logger.LogInfo("Settings saved", source: "Manager");
+ SettingsChanged?.Invoke();
+ }
+
+ #endregion
+
+ #region Layout Management
+
+ public void LoadLayout(bool minimize = true, Action? onComplete = null)
+ {
+ App.Logger.LogInfo("Loading layout", source: "Manager");
+ BlockWindowsClosing = false;
+
+ foreach (IPluginWindow window in PluginWindows)
+ {
+ window.Close();
+ }
+
+ BlockWindowsClosing = true;
+ PluginWindows.Clear();
+
+ bool showWindow = true;
+
+ // Load plugins
+ foreach (uint pluginId in _plugins.Keys)
+ {
+ InternalPluginData internalPluginData = _plugins[pluginId];
+
+ // Add plugin to layout if it doesn't exist
+ if (!Settings.CurrentLayout.Plugins.TryGetValue(pluginId, out PluginSettings? pluginSettings))
+ {
+ Settings.CurrentLayout.Plugins.Add(pluginId, new PluginSettings() { Metadata = internalPluginData.Metadata });
+ continue;
+ }
+
+ pluginSettings.Metadata = internalPluginData.Metadata;
+
+ if (pluginSettings.Enabled)
+ {
+ LoadPlugin(pluginId);
+ }
+
+ if (showWindow && pluginSettings.Enabled)
+ {
+ showWindow = false;
+ }
+ }
+
+ // Remove plugins that are not loaded anymore
+ var pluginIdsToRemove = Settings.CurrentLayout.Plugins.Keys.Where(id => !_plugins.ContainsKey(id)).ToList();
+ foreach (uint pluginId in pluginIdsToRemove)
+ {
+ Settings.CurrentLayout.Plugins.Remove(pluginId);
+ }
+
+ Settings.CurrentLayout.UpdatePlugins();
+
+ if (minimize && !showWindow)
+ {
+ Application.Current.MainWindow.WindowState = WindowState.Minimized;
+ Application.Current.MainWindow.ShowInTaskbar = false;
+ }
+
+ onComplete?.Invoke();
+ App.Logger.LogInfo("Layout loaded", source: "Manager");
+ }
+
+ #endregion
+
+ #region Cleanup
+
+ public void CloseAllPluginWindows()
+ {
+ foreach (IPluginWindow window in PluginWindows)
+ {
+ window.Hide();
+ }
+ }
+
+ #endregion
+}
+
+public class InternalPluginData(PluginMetadata pluginMetadata, PluginType pluginType, string directoryPath)
+{
+ public PluginMetadata Metadata { get; set; } = pluginMetadata;
+ public PluginType Type { get; set; } = pluginType;
+ public string DirectoryPath { get; set; } = directoryPath;
+}
+
+public enum PluginType
+{
+ DotNet,
+ Web
+}
\ No newline at end of file
diff --git a/src/DesktopMagic/Pages/MainPage.xaml b/src/DesktopMagic/Pages/MainPage.xaml
new file mode 100644
index 0000000..752027b
--- /dev/null
+++ b/src/DesktopMagic/Pages/MainPage.xaml
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/DesktopMagic/Pages/MainPage.xaml.cs b/src/DesktopMagic/Pages/MainPage.xaml.cs
new file mode 100644
index 0000000..3a6dc29
--- /dev/null
+++ b/src/DesktopMagic/Pages/MainPage.xaml.cs
@@ -0,0 +1,261 @@
+using DesktopMagic.DataContexts;
+using DesktopMagic.Dialogs;
+using DesktopMagic.Helpers;
+using DesktopMagic.Plugins;
+using DesktopMagic.Settings;
+
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows;
+using System.Windows.Controls;
+
+namespace DesktopMagic.Pages;
+
+///
+/// Interaction logic for MainPage.xaml
+///
+public partial class MainPage : Page
+{
+ private readonly Manager _manager = Manager.Instance;
+ private readonly MainWindowDataContext _dataContext;
+ private bool _isLoadingLayout = false;
+
+ public MainPage()
+ {
+ InitializeComponent();
+
+ _dataContext = new MainWindowDataContext
+ {
+ Settings = _manager.Settings
+ };
+
+ DataContext = _dataContext;
+
+ // Subscribe to manager events
+ _manager.PluginsChanged += OnPluginsChanged;
+ _manager.EditModeChanged += OnEditModeChanged;
+
+ Loaded += MainPage_Loaded;
+ Unloaded += MainPage_Unloaded;
+ }
+
+ private void MainPage_Loaded(object sender, RoutedEventArgs e)
+ {
+ // Initialize edit checkbox state
+ editCheckBox.IsChecked = _manager.IsEditMode;
+ }
+
+ private void MainPage_Unloaded(object sender, RoutedEventArgs e)
+ {
+ // Unsubscribe from events
+ _manager.PluginsChanged -= OnPluginsChanged;
+ _manager.EditModeChanged -= OnEditModeChanged;
+ }
+
+ private void OnPluginsChanged()
+ {
+ Dispatcher.Invoke(() =>
+ {
+ // Refresh the UI if needed
+ _dataContext.Settings = _manager.Settings;
+ });
+ }
+
+ private void OnEditModeChanged(bool editMode)
+ {
+ Dispatcher.Invoke(() =>
+ {
+ editCheckBox.IsChecked = editMode;
+ });
+ }
+
+ private void EditCheckBox_Click(object sender, RoutedEventArgs e)
+ {
+ _manager.SetEditMode(editCheckBox.IsChecked == true);
+ }
+
+ private void PluginCheckBox_Click(object sender, RoutedEventArgs e)
+ {
+ if (sender is not Control checkBox)
+ {
+ return;
+ }
+
+ uint pluginId = uint.Parse(checkBox.Tag.ToString()!);
+
+ _manager.LoadPlugin(pluginId, (internalPluginData) =>
+ {
+ Dispatcher.Invoke(() =>
+ {
+ // Update the card expander to show options when enabling a plugin
+ Wpf.Ui.Controls.CardExpander? cardExpander = ((checkBox.Parent as FrameworkElement)?.Parent) as Wpf.Ui.Controls.CardExpander;
+
+ if (cardExpander is not null)
+ {
+ OptionsCardExpander_Expanded(cardExpander, new RoutedEventArgs());
+ }
+ });
+ });
+ }
+
+ private void ScrollViewer_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
+ {
+ if (sender is ScrollViewer scv)
+ {
+ scv.ScrollToVerticalOffset(scv.VerticalOffset - e.Delta);
+ e.Handled = true;
+ }
+ }
+
+ #region Layout Management
+
+ private void LayoutsComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ // Prevent recursive calls and only process if fully loaded
+ if (_isLoadingLayout || !_manager.IsLoaded || !IsLoaded)
+ {
+ return;
+ }
+
+ // Check if this is actually a user-initiated change
+ // by verifying that the removed and added items are different
+ if (e.RemovedItems.Count > 0 && e.AddedItems.Count > 0)
+ {
+ if (e.RemovedItems[0] == e.AddedItems[0])
+ {
+ return;
+ }
+ }
+
+ try
+ {
+ _isLoadingLayout = true;
+ _manager.SaveSettings();
+ _manager.LoadLayout(false);
+ }
+ finally
+ {
+ _isLoadingLayout = false;
+ }
+ }
+
+ private void NewLayoutButton_Click(object sender, RoutedEventArgs e)
+ {
+ InputDialog inputDialog = new((string)FindResource("enterLayoutName"))
+ {
+ Owner = Window.GetWindow(this)
+ };
+
+ if (inputDialog.ShowDialog() == true)
+ {
+ if (_manager.Settings.Layouts.Any(l => l.Name.Trim() == inputDialog.ResponseText.Trim()))
+ {
+ _ = System.Windows.MessageBox.Show((string)FindResource("layoutAlreadyExists"), App.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
+ return;
+ }
+
+ try
+ {
+ _isLoadingLayout = true;
+ _manager.Settings.Layouts.Add(new Layout(inputDialog.ResponseText.Trim()));
+ _manager.Settings.CurrentLayoutName = inputDialog.ResponseText.Trim();
+ _manager.SaveSettings();
+ }
+ finally
+ {
+ _isLoadingLayout = false;
+ }
+ }
+ }
+
+ private void RemoveLayoutButton_Click(object sender, RoutedEventArgs e)
+ {
+ if (_manager.Settings.Layouts.Count <= 1)
+ {
+ _ = System.Windows.MessageBox.Show((string)FindResource("cannotDeleteLastLayout"), App.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
+ return;
+ }
+
+ MessageBoxResult result = System.Windows.MessageBox.Show((string)FindResource("confirmDeleteLayout"), App.AppName, MessageBoxButton.YesNo, MessageBoxImage.Question);
+ if (result != MessageBoxResult.Yes)
+ {
+ return;
+ }
+
+ try
+ {
+ _isLoadingLayout = true;
+ _ = _manager.Settings.Layouts.Remove(_manager.Settings.CurrentLayout);
+ _manager.SaveSettings();
+ }
+ finally
+ {
+ _isLoadingLayout = false;
+ }
+ }
+
+ #endregion
+
+ private void OptionsCardExpander_Expanded(object sender, RoutedEventArgs e)
+ {
+ if (sender is not Wpf.Ui.Controls.CardExpander expander || expander.Tag is not KeyValuePair keyValuePair)
+ {
+ return;
+ }
+
+ PluginSettings? pluginSettings = keyValuePair.Value;
+ uint pluginId = keyValuePair.Key;
+
+ StackPanel optionsPanel = new StackPanel
+ {
+ Visibility = Visibility.Visible
+ };
+
+ expander.Content = optionsPanel;
+ optionsPanel.UpdateLayout();
+
+ // s.Input being null means the plugins has not been loaded yet but the settings are present in the saved configuration.
+ if (pluginSettings is null || pluginSettings.Settings.Count == 0 || pluginSettings.Settings.All(s => s.Input is null))
+ {
+ _ = optionsPanel.Children.Add(new TextBlock()
+ {
+ Text = (string)FindResource(pluginSettings?.Enabled == true ? "noOptions" : "enablePluginToConfigure")
+ });
+
+ return;
+ }
+
+ SettingElementGenerator settingElementGenerator = new SettingElementGenerator(pluginId);
+
+ foreach (SettingElement settingElement in pluginSettings.Settings)
+ {
+ Wpf.Ui.Controls.CardControl card = new()
+ {
+ Margin = new Thickness(0, 0, 0, 5),
+ Padding = new Thickness(5)
+ };
+
+ TextBlock textBlock = new()
+ {
+ Text = string.IsNullOrWhiteSpace(settingElement.Name) ? string.Empty : settingElement.Name,
+ Padding = new Thickness(0, 0, 3, 0),
+ VerticalAlignment = VerticalAlignment.Center,
+ FontWeight = FontWeights.SemiBold
+ };
+
+ card.Header = textBlock;
+
+ _ = optionsPanel.Children.Add(card);
+
+ Control? control = settingElementGenerator.Generate(settingElement, textBlock);
+
+ if (control is not null)
+ {
+ control.MinWidth = 200;
+ card.Content = control;
+ }
+ }
+
+ optionsPanel.UpdateLayout();
+ }
+}
diff --git a/src/DesktopMagic/Pages/ThemePage.xaml b/src/DesktopMagic/Pages/ThemePage.xaml
new file mode 100644
index 0000000..0b3ad60
--- /dev/null
+++ b/src/DesktopMagic/Pages/ThemePage.xaml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/DesktopMagic/Pages/ThemePage.xaml.cs b/src/DesktopMagic/Pages/ThemePage.xaml.cs
new file mode 100644
index 0000000..e7e3baf
--- /dev/null
+++ b/src/DesktopMagic/Pages/ThemePage.xaml.cs
@@ -0,0 +1,103 @@
+using DesktopMagic.DataContexts;
+using DesktopMagic.Dialogs;
+using DesktopMagic.Plugins;
+
+using System.Linq;
+using System.Windows;
+using System.Windows.Controls;
+
+namespace DesktopMagic.Pages;
+
+///
+/// Interaction logic for ThemePage.xaml
+///
+public partial class ThemePage : Page
+{
+ private readonly Manager _manager = Manager.Instance;
+ private readonly MainWindowDataContext _dataContext;
+
+ public ThemePage()
+ {
+ InitializeComponent();
+
+ _dataContext = new MainWindowDataContext
+ {
+ Settings = _manager.Settings
+ };
+
+ DataContext = _dataContext;
+
+ // Subscribe to manager events
+ _manager.SettingsChanged += OnSettingsChanged;
+
+ Unloaded += ThemePage_Unloaded;
+ }
+
+ private void ThemePage_Unloaded(object sender, RoutedEventArgs e)
+ {
+ // Unsubscribe from events
+ _manager.SettingsChanged -= OnSettingsChanged;
+ }
+
+ private void OnSettingsChanged()
+ {
+ Dispatcher.Invoke(() =>
+ {
+ _dataContext.Settings = _manager.Settings;
+ });
+ }
+
+ private void AddThemeButton_Click(object sender, RoutedEventArgs e)
+ {
+ InputDialog inputDialog = new((string)FindResource("enterThemeName"))
+ {
+ Owner = Window.GetWindow(this)
+ };
+
+ if (inputDialog.ShowDialog() == true)
+ {
+ if (_manager.Settings.Themes.Any(l => l.Name.Trim() == inputDialog.ResponseText.Trim()))
+ {
+ _ = System.Windows.MessageBox.Show((string)FindResource("themeAlreadyExists"), App.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
+ return;
+ }
+
+ _manager.Settings.Themes.Add(new Theme(inputDialog.ResponseText.Trim()));
+ _manager.Settings.CurrentLayout.CurrentThemeName = inputDialog.ResponseText.Trim();
+ _manager.SaveSettings();
+ }
+ }
+
+ private void DeleteThemeButton_Click(object sender, RoutedEventArgs e)
+ {
+ if (_manager.Settings.Themes.Count <= 1)
+ {
+ _ = System.Windows.MessageBox.Show((string)FindResource("cannotDeleteLastTheme"), App.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
+ return;
+ }
+
+ MessageBoxResult result = System.Windows.MessageBox.Show((string)FindResource("confirmDeleteTheme"), App.AppName, MessageBoxButton.YesNo, MessageBoxImage.Question);
+ if (result != MessageBoxResult.Yes)
+ {
+ return;
+ }
+
+ if (themesListBox.SelectedItem is Theme theme)
+ {
+ _ = _manager.Settings.Themes.Remove(theme);
+ _manager.SaveSettings();
+ }
+ }
+
+ private void ChangeThemeButton_Click(object sender, RoutedEventArgs e)
+ {
+ Theme theme = themesListBox.SelectedItem as Theme ?? _manager.Settings.CurrentLayout.Theme;
+
+ ThemeDialog themeDialog = new(theme.Name, theme, App.AppName)
+ {
+ Owner = Window.GetWindow(this)
+ };
+
+ _ = themeDialog.ShowDialog();
+ }
+}
diff --git a/src/DesktopMagic/Plugins/PluginEntry.xaml b/src/DesktopMagic/Plugins/PluginEntry.xaml
index d29b84a..f56e9e5 100644
--- a/src/DesktopMagic/Plugins/PluginEntry.xaml
+++ b/src/DesktopMagic/Plugins/PluginEntry.xaml
@@ -2,8 +2,8 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:local="clr-namespace:DesktopMagic.Plugins"
xmlns:dataContext="clr-namespace:DesktopMagic.DataContexts"
d:DataContext="{d:DesignInstance Type=dataContext:PluginEntryDataContext}"
@@ -12,52 +12,54 @@
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{DynamicResource MaterialDesignFont}"
Visibility="{Binding Visibility}">
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/DesktopMagic/Plugins/PluginManager.xaml b/src/DesktopMagic/Plugins/PluginManager.xaml
index 8031cac..1003f0f 100644
--- a/src/DesktopMagic/Plugins/PluginManager.xaml
+++ b/src/DesktopMagic/Plugins/PluginManager.xaml
@@ -1,24 +1,20 @@
-
+ d:DesignHeight="450"
+ d:DesignWidth="800"
+ ScrollViewer.CanContentScroll="False"
+ Title="{DynamicResource pluginManager}">
-
+
@@ -28,21 +24,58 @@
+
-
+
+
+
+
+
+
+
-
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
+
@@ -62,56 +95,33 @@
-
+
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/DesktopMagic/Plugins/PluginManager.xaml.cs b/src/DesktopMagic/Plugins/PluginManager.xaml.cs
index 3f3d9b3..2047371 100644
--- a/src/DesktopMagic/Plugins/PluginManager.xaml.cs
+++ b/src/DesktopMagic/Plugins/PluginManager.xaml.cs
@@ -8,7 +8,6 @@ using Modio.Models;
using System;
using System.Collections.Generic;
-using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
@@ -19,6 +18,7 @@ using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
+using System.Windows.Controls;
using System.Windows.Threading;
using System.Xml.Linq;
@@ -30,7 +30,7 @@ namespace DesktopMagic.Plugins;
///
/// Interaction logic for PluginManager.xaml
///
-public partial class PluginManager : Window
+public partial class PluginManager : Page
{
private const int ModIoGameId = 5665;
private const string ModIoApiKey = "88e6ea774c3a502b06114e7fee0829ac";
@@ -38,6 +38,9 @@ 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 Manager _manager = Manager.Instance;
+
+ private bool changed = false;
private readonly DispatcherTimer searchTimer = new()
{
@@ -72,55 +75,29 @@ public partial class PluginManager : Window
searchTimer.Stop();
await SearchAllPlugins(pluginManagerDataContext.AllPluginsSearchText);
};
+
+ Loaded += PluginManager_Loaded;
+ Unloaded += PluginManager_Unloaded;
}
- public async Task Remove(string pluginPath, uint id)
+ private async void PluginManager_Loaded(object sender, RoutedEventArgs e)
{
- App.Logger.LogInfo($"Removing plugin with ID {id} from path: {pluginPath}", source: "PluginManager");
- pluginManagerDataContext.IsLoading = true;
-
- PluginEntryDataContext? pluginEntryDataContext = pluginManagerDataContext.InstalledPlugins.FirstOrDefault(p => p.Id == id);
-
- if (Directory.Exists(pluginPath))
- {
- try
- {
- Directory.Delete(pluginPath, true);
- App.Logger.LogInfo($"Successfully deleted plugin directory: {pluginPath}", source: "PluginManager");
- }
- catch (Exception ex)
- {
- _ = MessageBox.Show(ex.Message, "Plugin Manager", MessageBoxButton.OK, MessageBoxImage.Error);
- App.Logger.LogError(ex.Message, source: "PluginManager");
- }
- }
-
- if (pluginEntryDataContext is not null)
- {
- _ = pluginManagerDataContext.InstalledPlugins.Remove(pluginEntryDataContext);
- App.Logger.LogInfo($"Removed plugin {id} from installed plugins list", source: "PluginManager");
- }
-
- if (pluginManagerDataContext.IsAuthenticated)
- {
- try
- {
- await modIoClient.Games[ModIoGameId].Mods.Unsubscribe(id);
- App.Logger.LogInfo($"Unsubscribed from plugin {id} on mod.io", source: "PluginManager");
- }
- catch (Exception ex)
- {
- App.Logger.LogError($"Failed to unsubscribe from plugin {id}: {ex.Message}", source: "PluginManager");
- }
- }
-
- pluginManagerDataContext.IsLoading = false;
+ await InitializePluginManager();
}
- protected override async void OnInitialized(EventArgs e)
+ private void PluginManager_Unloaded(object sender, RoutedEventArgs e)
{
- base.OnInitialized(e);
+ searchTimer.Stop();
+ if (changed)
+ {
+ _manager.LoadPlugins();
+ _manager.LoadLayout(Application.Current.MainWindow.Visibility != System.Windows.Visibility.Visible);
+ }
+ }
+
+ private async Task InitializePluginManager()
+ {
App.Logger.LogInfo("Initializing Plugin Manager", source: "PluginManager");
HashSet pluginIds = [];
@@ -197,9 +174,48 @@ public partial class PluginManager : Window
App.Logger.LogInfo("Plugin Manager initialization complete", source: "PluginManager");
}
- protected override void OnClosing(CancelEventArgs e)
+ public async Task Remove(string pluginPath, uint id)
{
- e.Cancel = pluginManagerDataContext.IsLoading;
+ App.Logger.LogInfo($"Removing plugin with ID {id} from path: {pluginPath}", source: "PluginManager");
+ pluginManagerDataContext.IsLoading = true;
+ changed = true;
+
+ PluginEntryDataContext? pluginEntryDataContext = pluginManagerDataContext.InstalledPlugins.FirstOrDefault(p => p.Id == id);
+
+ if (Directory.Exists(pluginPath))
+ {
+ try
+ {
+ Directory.Delete(pluginPath, true);
+ App.Logger.LogInfo($"Successfully deleted plugin directory: {pluginPath}", source: "PluginManager");
+ }
+ catch (Exception ex)
+ {
+ _ = MessageBox.Show(ex.Message, "Plugin Manager", MessageBoxButton.OK, MessageBoxImage.Error);
+ App.Logger.LogError(ex.Message, source: "PluginManager");
+ }
+ }
+
+ if (pluginEntryDataContext is not null)
+ {
+ _ = pluginManagerDataContext.InstalledPlugins.Remove(pluginEntryDataContext);
+ App.Logger.LogInfo($"Removed plugin {id} from installed plugins list", source: "PluginManager");
+ }
+
+ if (pluginManagerDataContext.IsAuthenticated)
+ {
+ try
+ {
+ await modIoClient.Games[ModIoGameId].Mods.Unsubscribe(id);
+ App.Logger.LogInfo($"Unsubscribed from plugin {id} on mod.io", source: "PluginManager");
+ }
+ catch (Exception ex)
+ {
+ App.Logger.LogError($"Failed to unsubscribe from plugin {id}: {ex.Message}", source: "PluginManager");
+ }
+ }
+
+ pluginManagerDataContext.IsLoading = false;
}
[GeneratedRegex(@"[^a-zA-Z0-9]")]
@@ -209,6 +225,7 @@ public partial class PluginManager : Window
{
App.Logger.LogInfo($"Installing plugin: {mod.Name} (ID: {mod.Id})", source: "PluginManager");
pluginManagerDataContext.IsLoading = true;
+ changed = true;
if (mod.Modfile?.Download?.BinaryUrl is null)
{
@@ -383,7 +400,7 @@ public partial class PluginManager : Window
InputDialog inputDialog = new((string)FindResource("enterPluginName"), "Plugin Manager")
{
- Owner = this,
+ Owner = Window.GetWindow(this),
};
if (inputDialog.ShowDialog() != true)
@@ -547,7 +564,7 @@ public class {pluginSafeName}Plugin : Plugin
{
InputDialog inputDialog = new((string)FindResource("enterModIoEmail"), "Plugin Manager")
{
- Owner = this,
+ Owner = Window.GetWindow(this),
};
if (inputDialog.ShowDialog() != true)
@@ -561,7 +578,7 @@ public class {pluginSafeName}Plugin : Plugin
inputDialog = new((string)FindResource("enterModIoAccessToken"), "Plugin Manager")
{
- Owner = this,
+ Owner = Window.GetWindow(this),
};
if (inputDialog.ShowDialog() != true)
diff --git a/src/DesktopMagic/Plugins/PluginWindow.xaml b/src/DesktopMagic/Plugins/PluginWindow.xaml
index 7372412..9d0533c 100644
--- a/src/DesktopMagic/Plugins/PluginWindow.xaml
+++ b/src/DesktopMagic/Plugins/PluginWindow.xaml
@@ -1,6 +1,7 @@
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/DesktopMagic/Plugins/PluginWindow.xaml.cs b/src/DesktopMagic/Plugins/PluginWindow.xaml.cs
index 44663a5..852b255 100644
--- a/src/DesktopMagic/Plugins/PluginWindow.xaml.cs
+++ b/src/DesktopMagic/Plugins/PluginWindow.xaml.cs
@@ -210,6 +210,8 @@ public partial class PluginWindow : Window, IPluginWindow
return;
}
PluginLoaded?.Invoke();
+
+ _ = Dispatcher.Invoke(() => busyMask.IsBusy = false);
}
private void ThemeChanged()
diff --git a/src/DesktopMagic/Plugins/WebPluginWindow.xaml b/src/DesktopMagic/Plugins/WebPluginWindow.xaml
index 00c9d6f..deb7d11 100644
--- a/src/DesktopMagic/Plugins/WebPluginWindow.xaml
+++ b/src/DesktopMagic/Plugins/WebPluginWindow.xaml
@@ -1,6 +1,7 @@
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
diff --git a/src/DesktopMagic/Plugins/WebPluginWindow.xaml.cs b/src/DesktopMagic/Plugins/WebPluginWindow.xaml.cs
index c491cbe..9c9f27b 100644
--- a/src/DesktopMagic/Plugins/WebPluginWindow.xaml.cs
+++ b/src/DesktopMagic/Plugins/WebPluginWindow.xaml.cs
@@ -192,6 +192,8 @@ public partial class WebPluginWindow : Window, IPluginWindow
App.Logger.LogInfo($"\"{PluginMetadata.Name}\" - WebView2 initialized successfully", source: "WebPlugin");
PluginLoaded?.Invoke();
+
+ busyMask.IsBusy = false;
}
catch (Exception ex)
{
diff --git a/src/DesktopMagic/Resources/Strings/StringResources.de.xaml b/src/DesktopMagic/Resources/Strings/StringResources.de.xaml
index 08847d5..96ca827 100644
--- a/src/DesktopMagic/Resources/Strings/StringResources.de.xaml
+++ b/src/DesktopMagic/Resources/Strings/StringResources.de.xaml
@@ -3,6 +3,9 @@
xmlns:col="clr-namespace:System.Collections;assembly=mscorlib"
xmlns:system="clr-namespace:System;assembly=mscorlib">
+ Entwickelt von Stone_Red
+ Bug Melden
+ Feature Anfragen
Linie
Spiegeln
Ordner
@@ -15,13 +18,15 @@
Mod.io Account E-Mail eingeben
Geben Sie Ihren mod.io Sicherheitscode ein
Bearbeitungsmodus umschalten
- Alle Plugins
- Installierte Plugins
- Neu Laden
+ Alle Plugins Suchen...
+ Installierte Plugins Suchen...
+ Plugins Neu Laden
Plugins Ordner
Plugins Manager
Neues Plugin erstellen
Pluginnamen eingeben
+ Plugins
+ Aktivieren Sie das Plugin, um seine Einstellungen zu konfigurieren.
Farbe:
Standard
Wollen sie das Programm wirklich schließen?
@@ -38,6 +43,7 @@
Neues Theme
Theme Löschen
Theme Ändern
+ Themes
Ok
Abbrechen
Möchten Sie dieses Layout wirklich löschen?
diff --git a/src/DesktopMagic/Resources/Strings/StringResources.en.xaml b/src/DesktopMagic/Resources/Strings/StringResources.en.xaml
index dc7ff01..703a1ad 100644
--- a/src/DesktopMagic/Resources/Strings/StringResources.en.xaml
+++ b/src/DesktopMagic/Resources/Strings/StringResources.en.xaml
@@ -3,6 +3,9 @@
xmlns:col="clr-namespace:System.Collections;assembly=mscorlib"
xmlns:system="clr-namespace:System;assembly=mscorlib">
+ Developed by Stone_Red
+ Report Bug
+ Request Feature
Line
Mirror
Folder
@@ -15,13 +18,15 @@
Enter your mod.io account E-mail
Enter your mod.io security code
Toggle Edit Mode
- All Plugins
- Installed Plugins
- Reload
+ Search All Plugins...
+ Search Installed Plugins...
+ Reload Plugins
Plugins Folder
Plugins Manager
Create New Plugin
Enter plugin name
+ Plugins
+ Enable the plugin to configure its settings.
Color:
Default
Do you really want to close the program?
@@ -38,6 +43,7 @@
New Theme
Delete Theme
Change Theme
+ Themes
Ok
Cancel
Do you really want to delete this layout?
diff --git a/src/DesktopMagic/Resources/Styles/ToggleSwitchContentLeftStyle.xaml b/src/DesktopMagic/Resources/Styles/ToggleSwitchContentLeftStyle.xaml
new file mode 100644
index 0000000..3420ca0
--- /dev/null
+++ b/src/DesktopMagic/Resources/Styles/ToggleSwitchContentLeftStyle.xaml
@@ -0,0 +1,131 @@
+
+
+ 40
+ 20
+ 1
+ 0,0,8,0
+
+
+
\ No newline at end of file
diff --git a/src/DesktopMagic/Settings/DesktopMagicSettings.cs b/src/DesktopMagic/Settings/DesktopMagicSettings.cs
index 62409e8..42fb981 100644
--- a/src/DesktopMagic/Settings/DesktopMagicSettings.cs
+++ b/src/DesktopMagic/Settings/DesktopMagicSettings.cs
@@ -8,7 +8,7 @@ using System.Text.Json.Serialization;
namespace DesktopMagic.Settings;
-internal class DesktopMagicSettings : INotifyPropertyChanged
+public class DesktopMagicSettings : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
diff --git a/src/DesktopMagic/Settings/Layout.cs b/src/DesktopMagic/Settings/Layout.cs
index 420f746..a92dff7 100644
--- a/src/DesktopMagic/Settings/Layout.cs
+++ b/src/DesktopMagic/Settings/Layout.cs
@@ -9,7 +9,7 @@ using System.Text.Json.Serialization;
namespace DesktopMagic.Settings;
-internal class Layout(string name) : INotifyPropertyChanged
+public class Layout(string name) : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
diff --git a/src/DesktopMagic/Settings/PluginSettings.cs b/src/DesktopMagic/Settings/PluginSettings.cs
index 0e67497..5655032 100644
--- a/src/DesktopMagic/Settings/PluginSettings.cs
+++ b/src/DesktopMagic/Settings/PluginSettings.cs
@@ -24,7 +24,7 @@ public class PluginSettings : INotifyPropertyChanged
// Only for internal use to show the name of the plugin in the main window
[JsonIgnore]
- public string Name { get; set; } = string.Empty;
+ public PluginMetadata Metadata { get; set; } = new();
[JsonIgnore]
public Theme Theme