diff --git a/src/DesktopMagic/App.xaml b/src/DesktopMagic/App.xaml index cbf40f7..2931262 100644 --- a/src/DesktopMagic/App.xaml +++ b/src/DesktopMagic/App.xaml @@ -9,6 +9,7 @@ + diff --git a/src/DesktopMagic/DataContexts/ModEntryDataContext.cs b/src/DesktopMagic/DataContexts/ModEntryDataContext.cs deleted file mode 100644 index 14f57d2..0000000 --- a/src/DesktopMagic/DataContexts/ModEntryDataContext.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Modio.NET.Models; - -using System; -using System.Windows.Input; - -namespace DesktopMagic.DataContexts; -internal class ModEntryDataContext(Mod mod, ICommand installCommand) -{ - public string Name => mod.Name!; - - public string Description => mod.DescriptionPlaintext!; - - public string? Logo => mod.Logo?.Thumb320x180?.ToString(); - - public DateTime FormattedDateAdded => DateTimeOffset.FromUnixTimeSeconds(mod.DateAdded).LocalDateTime; - public DateTime FormattedDateUpdated => DateTimeOffset.FromUnixTimeSeconds(mod.DateUpdated).LocalDateTime; - - public ICommand InstallCommand => installCommand; -} diff --git a/src/DesktopMagic/DataContexts/PluginEntryDataContext.cs b/src/DesktopMagic/DataContexts/PluginEntryDataContext.cs new file mode 100644 index 0000000..6e35dfa --- /dev/null +++ b/src/DesktopMagic/DataContexts/PluginEntryDataContext.cs @@ -0,0 +1,27 @@ +using DesktopMagic.Plugins; + +using System; +using System.Windows; +using System.Windows.Input; + +namespace DesktopMagic.DataContexts; + +internal class PluginEntryDataContext(PluginMetadata pluginMetadata, ICommand command, bool installed = false) +{ + public string Name => pluginMetadata.Name; + + public string? Description => pluginMetadata.Description; + + public string? Logo => pluginMetadata.IconUri?.ToString(); + + public DateTime? FormattedDateAdded => pluginMetadata.Added; + public DateTime? FormattedDateUpdated => pluginMetadata.Updated; + + public uint Id => pluginMetadata.Id; + + public ICommand Command => command; + + public Visibility InstallButtonVisibility => installed ? Visibility.Collapsed : Visibility.Visible; + + public Visibility RemoveButtonVisibility => installed ? Visibility.Visible : Visibility.Collapsed; +} \ No newline at end of file diff --git a/src/DesktopMagic/DataContexts/PluginManagerDataContext.cs b/src/DesktopMagic/DataContexts/PluginManagerDataContext.cs index 67abb77..b253214 100644 --- a/src/DesktopMagic/DataContexts/PluginManagerDataContext.cs +++ b/src/DesktopMagic/DataContexts/PluginManagerDataContext.cs @@ -3,14 +3,31 @@ using System.ComponentModel; using System.Runtime.CompilerServices; namespace DesktopMagic.DataContexts; + internal class PluginManagerDataContext : INotifyPropertyChanged { public event PropertyChangedEventHandler? PropertyChanged; - public ObservableCollection Mods { get; } = []; + public ObservableCollection AllPlugins { get; } = []; + public ObservableCollection InstalledPlugins { get; } = []; + + private bool _isLoading; + + public bool IsLoading + { + get => _isLoading; + set + { + _isLoading = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(IsNotLoading)); + } + } + + public bool IsNotLoading => !IsLoading; protected void OnPropertyChanged([CallerMemberName] string? name = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } -} +} \ No newline at end of file diff --git a/src/DesktopMagic/DesktopMagic.csproj b/src/DesktopMagic/DesktopMagic.csproj index a73e875..363cd88 100644 --- a/src/DesktopMagic/DesktopMagic.csproj +++ b/src/DesktopMagic/DesktopMagic.csproj @@ -28,6 +28,7 @@ + diff --git a/src/DesktopMagic/GlobalSuppressions.cs b/src/DesktopMagic/GlobalSuppressions.cs index 2691b65..f210155 100644 --- a/src/DesktopMagic/GlobalSuppressions.cs +++ b/src/DesktopMagic/GlobalSuppressions.cs @@ -7,6 +7,4 @@ using System.Diagnostics.CodeAnalysis; [assembly: SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "Windows only application")] [assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "No need to")] -[assembly: SuppressMessage("Minor Code Smell", "S1075:URIs should not be hardcoded", Justification = "")] -[assembly: SuppressMessage("Minor Code Smell", "S3604:Member initializer values should not be redundant", Justification = "False postives")] -[assembly: SuppressMessage("Critical Code Smell", "S2696:Instance members should not write to \"static\" fields", Justification = "", Scope = "member", Target = "~P:DesktopMagic.MainWindowDataContext.Settings")] \ No newline at end of file +[assembly: SuppressMessage("Minor Code Smell", "S1075:URIs should not be hardcoded", Justification = "")] \ No newline at end of file diff --git a/src/DesktopMagic/MainWindow.xaml b/src/DesktopMagic/MainWindow.xaml index eb8c587..1099839 100644 --- a/src/DesktopMagic/MainWindow.xaml +++ b/src/DesktopMagic/MainWindow.xaml @@ -7,7 +7,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:DesktopMagic" xmlns:dataContext="clr-namespace:DesktopMagic.DataContexts" - d:DataContext="{d:DesignInstance Type=dataContext:PluginManagerDataContext}" + d:DataContext="{d:DesignInstance Type=dataContext:MainWindowDataContext}" Closing="Window_Closing" Closed="Window_Closed" ShowInTaskbar="True" @@ -48,7 +48,7 @@ - + @@ -56,7 +56,7 @@ - + diff --git a/src/DesktopMagic/MainWindow.xaml.cs b/src/DesktopMagic/MainWindow.xaml.cs index 064bac4..2cf0032 100644 --- a/src/DesktopMagic/MainWindow.xaml.cs +++ b/src/DesktopMagic/MainWindow.xaml.cs @@ -5,6 +5,8 @@ using DesktopMagic.Helpers; using DesktopMagic.Plugins; using DesktopMagic.Settings; +using Stone_Red_Utilities.StringExtentions; + using System; using System.Collections.Generic; using System.Diagnostics; @@ -26,12 +28,12 @@ namespace DesktopMagic private readonly MainWindowDataContext mainWindowDataContext = new(); - private readonly Dictionary builtInPlugins = new() + private readonly Dictionary builtInPlugins = new() { - {"Music Visualizer", typeof(MusicVisualizerPlugin)}, - {"Time", typeof(TimePlugin)}, - {"Date", typeof(DatePlugin)}, - {"Cpu Usage", typeof(CpuMonitorPlugin)} + {new("Music Visualizer", 1), typeof(MusicVisualizerPlugin)}, + {new("Time",2), typeof(TimePlugin)}, + {new("Date",3), typeof(DatePlugin)}, + {new("Cpu Usage", 4), typeof(CpuMonitorPlugin)} }; private bool loaded = false; @@ -76,7 +78,7 @@ namespace DesktopMagic #region Load - private readonly List pluginNames = []; + private readonly Dictionary plugins = []; private void Window_Loaded(object sender, RoutedEventArgs e) { @@ -109,44 +111,41 @@ namespace DesktopMagic private void LoadPlugins() { - pluginNames.Clear(); + plugins.Clear(); - pluginNames.AddRange(builtInPlugins.Keys); + foreach (var buildInPlugin in builtInPlugins.Keys) + { + plugins.Add(buildInPlugin.Id, new(buildInPlugin, string.Empty)); + } string pluginsPath = App.ApplicationDataPath + "\\Plugins"; - foreach (string fileName in Directory.GetFiles(pluginsPath, "*.dll")) - { - string pluginName = fileName[(fileName.LastIndexOf('\\') + 1)..].Replace(fileName[fileName.LastIndexOf('.')..], ""); - try - { - _ = Directory.CreateDirectory(Path.Combine(pluginsPath, pluginName)); - File.Move(fileName, $"{pluginsPath}\\{pluginName}\\{pluginName}.dll"); - } - catch (Exception ex) - { - App.Logger.Log(ex.Message, "Main", LogSeverity.Error); - } - } - foreach (string directory in Directory.GetDirectories(pluginsPath)) { - foreach (string fileName in Directory.GetFiles(directory).Where(s => s.EndsWith(".dll", StringComparison.InvariantCulture))) + string? pluginDllPath = Directory.GetFiles(directory, "main.dll").FirstOrDefault(); + string? pluginMetadataPath = Directory.GetFiles(directory, "metadata.json").FirstOrDefault(); + + if (pluginDllPath is null) { - string badChars = ",#-<>?!=()*,. "; - string pluginName = fileName[(fileName.LastIndexOf('\\') + 1)..].Replace(fileName[fileName.LastIndexOf('.')..], ""); - string clearPluginName = pluginName; - - if (pluginName == directory[(directory.LastIndexOf('\\') + 1)..]) - { - foreach (char c in badChars) - { - clearPluginName = clearPluginName.Replace(c, '_'); - } - - pluginNames.Add(pluginName); - } + App.Logger.Log($"Plugin \"{directory}\" has no \"main.dll\"", "Main", LogSeverity.Error); + continue; } + + if (pluginMetadataPath is null) + { + App.Logger.Log($"Plugin \"{directory}\" has no \"metadata.json\"", "Main", LogSeverity.Warn); + continue; + } + + PluginMetadata? pluginMetadata = JsonSerializer.Deserialize(File.ReadAllText(pluginMetadataPath)); + + if (pluginMetadata is null) + { + App.Logger.Log($"Plugin \"{directory}\" has no valid \"metadata.json\"", "Main", LogSeverity.Error); + continue; + } + + plugins.Add(pluginMetadata.Id, new(pluginMetadata, directory)); } } @@ -167,31 +166,36 @@ namespace DesktopMagic return; } - LoadPlugin(checkBox.Content.ToString() ?? string.Empty); + LoadPlugin(uint.Parse(checkBox.Tag.ToString()!)); } - private void LoadPlugin(string pluginName) + private void LoadPlugin(uint pluginId) { - if (!Settings.CurrentLayout.Plugins.TryGetValue(pluginName, out PluginSettings? pluginSettings)) + if (!plugins.TryGetValue(pluginId, out InternalPluginData? internalPluginData)) + { + return; + } + + if (!Settings.CurrentLayout.Plugins.TryGetValue(pluginId, out PluginSettings? pluginSettings)) { pluginSettings = new PluginSettings(); - Settings.CurrentLayout.Plugins.Add(pluginName, pluginSettings); + Settings.CurrentLayout.Plugins.Add(pluginId, pluginSettings); } PluginWindow window; - if (builtInPlugins.TryGetValue(pluginName, out Type? pluginType)) + if (builtInPlugins.TryGetValue(internalPluginData.Metadata, out Type? pluginType)) { - window = new PluginWindow((DesktopMagic.Api.Plugin)Activator.CreateInstance(pluginType)!, pluginName, pluginSettings) + window = new PluginWindow((Api.Plugin)Activator.CreateInstance(pluginType)!, internalPluginData.Metadata, pluginSettings) { - Title = pluginName + Title = internalPluginData.Metadata.Name }; } else { - window = new PluginWindow(pluginName, pluginSettings) + window = new PluginWindow(internalPluginData.Metadata, pluginSettings, internalPluginData.DirectoryPath) { - Title = pluginName + Title = internalPluginData.Metadata.Name }; } @@ -208,12 +212,12 @@ namespace DesktopMagic { Dispatcher.Invoke(() => { - if (!optionsComboBox.Items.Contains(pluginName)) + if (!optionsComboBox.Items.Contains(internalPluginData.Metadata)) { - _ = optionsComboBox.Items.Add(pluginName); + _ = optionsComboBox.Items.Add(internalPluginData.Metadata); } optionsComboBox.SelectedIndex = -1; - optionsComboBox.SelectedIndex = optionsComboBox.Items.IndexOf(pluginName); + optionsComboBox.SelectedIndex = optionsComboBox.Items.IndexOf(internalPluginData.Metadata); window.PluginLoaded -= onPluginLoaded; }); }; @@ -326,7 +330,7 @@ namespace DesktopMagic return; } - bool success = Settings.CurrentLayout.Plugins.TryGetValue(optionsComboBox.SelectedItem.ToString()!, out Settings.PluginSettings? pluginSettings); + 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") }); @@ -561,19 +565,22 @@ namespace DesktopMagic bool showWindow = true; // Load plugins - foreach (string pluginName in pluginNames) + foreach (uint pluginId in plugins.Keys) { // Add plugin to layout if it doesn't exist - if (!Settings.CurrentLayout.Plugins.TryGetValue(pluginName, out PluginSettings? pluginSettings)) + if (!Settings.CurrentLayout.Plugins.TryGetValue(pluginId, out PluginSettings? pluginSettings)) { - Settings.CurrentLayout.Plugins.Add(pluginName, new PluginSettings()); + Settings.CurrentLayout.Plugins.Add(pluginId, new PluginSettings()); continue; } + InternalPluginData internalPluginData = plugins[pluginId]; + pluginSettings.Name = internalPluginData.Metadata.Name; + if (pluginSettings.Enabled) { - LoadPlugin(pluginName); + LoadPlugin(pluginId); } if (showWindow && pluginSettings.Enabled) @@ -583,11 +590,11 @@ namespace DesktopMagic } // Remove plugins that are not loaded anymore - foreach (string pluginName in Settings.CurrentLayout.Plugins.Keys) + foreach (uint pluginId in Settings.CurrentLayout.Plugins.Keys) { - if (!pluginNames.Contains(pluginName)) + if (!plugins.ContainsKey(pluginId)) { - Settings.CurrentLayout.Plugins.Remove(pluginName); + Settings.CurrentLayout.Plugins.Remove(pluginId); } } @@ -646,6 +653,7 @@ namespace DesktopMagic PluginManager pluginManager = new PluginManager(); pluginManager.ShowDialog(); LoadPlugins(); + LoadLayout(false); } private void SetLanguageDictionary() @@ -664,4 +672,10 @@ namespace DesktopMagic Resources.MergedDictionaries.Add(dict); } } + + internal class InternalPluginData(PluginMetadata pluginMetadata, string directoryPath) + { + public PluginMetadata Metadata { get; set; } = pluginMetadata; + public string DirectoryPath { get; set; } = directoryPath; + } } \ No newline at end of file diff --git a/src/DesktopMagic/Plugins/ModEntry.xaml b/src/DesktopMagic/Plugins/ModEntry.xaml index 0a877b2..a48cbd9 100644 --- a/src/DesktopMagic/Plugins/ModEntry.xaml +++ b/src/DesktopMagic/Plugins/ModEntry.xaml @@ -1,41 +1,42 @@  - - + + - - + + - + - -