mirror of
https://github.com/Stone-Red-Code/DesktopMagic.git
synced 2026-09-04 00:46:12 +02:00
Add search functionality to plugin manager and improve UX
This commit is contained in:
@@ -1,13 +1,19 @@
|
||||
using DesktopMagic.Plugins;
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace DesktopMagic.DataContexts;
|
||||
|
||||
internal class PluginEntryDataContext(PluginMetadata pluginMetadata, ICommand command, bool installed = false)
|
||||
internal class PluginEntryDataContext(PluginMetadata pluginMetadata, ICommand command, bool installed = false) : INotifyPropertyChanged
|
||||
{
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
private bool isVisible = true;
|
||||
|
||||
public string Name => pluginMetadata.Name;
|
||||
|
||||
public string? Description => pluginMetadata.Description;
|
||||
@@ -24,4 +30,22 @@ internal class PluginEntryDataContext(PluginMetadata pluginMetadata, ICommand co
|
||||
public Visibility InstallButtonVisibility => installed ? Visibility.Collapsed : Visibility.Visible;
|
||||
|
||||
public Visibility RemoveButtonVisibility => installed ? Visibility.Visible : Visibility.Collapsed;
|
||||
|
||||
public bool IsVisible
|
||||
{
|
||||
get => isVisible;
|
||||
set
|
||||
{
|
||||
isVisible = value;
|
||||
OnPropertyChanged();
|
||||
OnPropertyChanged(nameof(Visibility));
|
||||
}
|
||||
}
|
||||
|
||||
public Visibility Visibility => IsVisible ? Visibility.Visible : Visibility.Collapsed;
|
||||
|
||||
private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
@@ -8,17 +8,19 @@ internal class PluginManagerDataContext : INotifyPropertyChanged
|
||||
{
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
private string allPluginsSearchText = string.Empty;
|
||||
private string installedPluginsSearchText = string.Empty;
|
||||
private bool isLoading = true;
|
||||
private bool isSearching;
|
||||
public ObservableCollection<PluginEntryDataContext> AllPlugins { get; } = [];
|
||||
public ObservableCollection<PluginEntryDataContext> InstalledPlugins { get; } = [];
|
||||
|
||||
private bool _isLoading;
|
||||
|
||||
public bool IsLoading
|
||||
{
|
||||
get => _isLoading;
|
||||
get => isLoading;
|
||||
set
|
||||
{
|
||||
_isLoading = value;
|
||||
isLoading = value;
|
||||
OnPropertyChanged();
|
||||
OnPropertyChanged(nameof(IsNotLoading));
|
||||
}
|
||||
@@ -26,6 +28,36 @@ internal class PluginManagerDataContext : INotifyPropertyChanged
|
||||
|
||||
public bool IsNotLoading => !IsLoading;
|
||||
|
||||
public bool IsSearching
|
||||
{
|
||||
get => isSearching;
|
||||
set
|
||||
{
|
||||
isSearching = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public string AllPluginsSearchText
|
||||
{
|
||||
get => allPluginsSearchText;
|
||||
set
|
||||
{
|
||||
allPluginsSearchText = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public string InstalledPluginsSearchText
|
||||
{
|
||||
get => installedPluginsSearchText;
|
||||
set
|
||||
{
|
||||
installedPluginsSearchText = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
protected void OnPropertyChanged([CallerMemberName] string? name = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
<ApplicationIcon>icon.ico</ApplicationIcon>
|
||||
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
|
||||
<Authors>Stone_Red</Authors>
|
||||
<Version>0.0.4.0</Version>
|
||||
<Version>1.0.0.0</Version>
|
||||
<PackageProjectUrl>https://github.com/Stone-Red-Code/DesktopMagic</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/Stone-Red-Code/DesktopMagic</RepositoryUrl>
|
||||
<AssemblyVersion>0.0.4.0</AssemblyVersion>
|
||||
<FileVersion>0.0.4.0</FileVersion>
|
||||
<AssemblyVersion>1.0.0.0</AssemblyVersion>
|
||||
<FileVersion>1.0.0.0</FileVersion>
|
||||
<TargetFramework>net8.0-windows7.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -15,7 +15,7 @@ public partial class ColorDialog : Window
|
||||
{
|
||||
public System.Drawing.Color ResultColor { get; private set; }
|
||||
|
||||
public Brush ResultBrush { get; private set; }
|
||||
public Brush ResultBrush { get; private set; } = Brushes.Transparent;
|
||||
|
||||
public ColorDialog(string content, System.Drawing.Color defaultColor, string title = "ColorDialog")
|
||||
{
|
||||
|
||||
@@ -573,15 +573,16 @@ namespace DesktopMagic
|
||||
// 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());
|
||||
Settings.CurrentLayout.Plugins.Add(pluginId, new PluginSettings() { Name = internalPluginData.Metadata.Name });
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
InternalPluginData internalPluginData = plugins[pluginId];
|
||||
pluginSettings.Name = internalPluginData.Metadata.Name;
|
||||
|
||||
if (pluginSettings.Enabled)
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
Background="{DynamicResource MaterialDesignPaper}"
|
||||
FontFamily="{DynamicResource MaterialDesignFont}">
|
||||
FontFamily="{DynamicResource MaterialDesignFont}"
|
||||
Visibility="{Binding Visibility}">
|
||||
<Grid Background="White" Margin="10">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
@@ -36,7 +37,7 @@
|
||||
|
||||
<StackPanel Grid.Row="1" Grid.ColumnSpan="2">
|
||||
<Label Content="{Binding Name}" FontSize="20" />
|
||||
<Label Content="{Binding Description}" />
|
||||
<TextBlock Text="{Binding Description}" TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -33,9 +33,11 @@
|
||||
|
||||
<Label Content="All plugins" FontSize="20" />
|
||||
|
||||
<TextBox Grid.Row="1" materialDesign:HintAssist.Hint="Search..." materialDesign:TextFieldAssist.HasLeadingIcon="True" materialDesign:TextFieldAssist.LeadingIcon="Search" />
|
||||
<TextBox Grid.Row="1" Text="{Binding AllPluginsSearchText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" TextChanged="AllPluginsSearchTextBox_TextChanged" materialDesign:HintAssist.Hint="Search..." materialDesign:TextFieldAssist.HasLeadingIcon="True" materialDesign:TextFieldAssist.LeadingIcon="Search" />
|
||||
|
||||
<ItemsControl Grid.Row="2" ItemsSource="{Binding AllPlugins}">
|
||||
<busyIndicator:BusyMask Grid.Row="2" IsBusy="{Binding IsSearching}" IndicatorType="Ring" BusyContent="Searching..." BusyContentMargin="0,50,0,0" IsBusyAtStartup="False">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||
<ItemsControl ItemsSource="{Binding AllPlugins}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border BorderBrush="LightGray" BorderThickness="1">
|
||||
@@ -43,11 +45,28 @@
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
<ItemsControl.Style>
|
||||
<Style TargetType="ItemsControl">
|
||||
<Style.Triggers>
|
||||
<Trigger Property="HasItems" Value="false">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<TextBlock Text="No plugins found!" FontSize="20" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ItemsControl.Style>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</busyIndicator:BusyMask>
|
||||
|
||||
<Label Grid.Column="1" Content="Installed plugins" FontSize="20" />
|
||||
|
||||
<TextBox Grid.Row="1" Grid.Column="1" materialDesign:HintAssist.Hint="Search..." materialDesign:TextFieldAssist.HasLeadingIcon="True" materialDesign:TextFieldAssist.LeadingIcon="Search" />
|
||||
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding InstalledPluginsSearchText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" TextChanged="InstalledPluginsSearchTextBox_TextChanged" materialDesign:HintAssist.Hint="Search..." materialDesign:TextFieldAssist.HasLeadingIcon="True" materialDesign:TextFieldAssist.LeadingIcon="Search" />
|
||||
|
||||
<ItemsControl Grid.Row="2" Grid.Column="1" ItemsSource="{Binding InstalledPlugins}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
@@ -57,11 +76,26 @@
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
<ItemsControl.Style>
|
||||
<Style TargetType="ItemsControl">
|
||||
<Style.Triggers>
|
||||
<Trigger Property="HasItems" Value="false">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<TextBlock Text="No plugins found!" FontSize="20" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ItemsControl.Style>
|
||||
</ItemsControl>
|
||||
|
||||
<DockPanel Grid.Row="3" Grid.ColumnSpan="2">
|
||||
<Image Source="{StaticResource ModioLogoBlueDark}" Height="30" HorizontalAlignment="Left" />
|
||||
</DockPanel>
|
||||
<Border Grid.Row="3" Grid.ColumnSpan="2" Padding="0 5 0 0" BorderThickness="0 2 0 0" BorderBrush="DarkGray">
|
||||
<Image Source="{StaticResource ModioLogoBlueDark}" Cursor="Hand" Height="30" MouseUp="Image_MouseUp" HorizontalAlignment="Left" />
|
||||
</Border>
|
||||
</Grid>
|
||||
</busyIndicator:BusyMask>
|
||||
</Window>
|
||||
@@ -2,6 +2,7 @@
|
||||
using DesktopMagic.Helpers;
|
||||
|
||||
using Modio.NET;
|
||||
using Modio.NET.Filters;
|
||||
using Modio.NET.Models;
|
||||
|
||||
using System;
|
||||
@@ -15,6 +16,7 @@ using System.Net.Http;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
|
||||
using File = System.IO.File;
|
||||
using Path = System.IO.Path;
|
||||
@@ -26,17 +28,28 @@ namespace DesktopMagic.Plugins;
|
||||
/// </summary>
|
||||
public partial class PluginManager : Window
|
||||
{
|
||||
private const int modIoGameId = 5665;
|
||||
private readonly Client client = new Client(new Credentials("88e6ea774c3a502b06114e7fee0829ac"));
|
||||
private readonly HttpClient httpClient = new();
|
||||
|
||||
private readonly PluginManagerDataContext pluginManagerDataContext = new();
|
||||
private readonly string pluginsPath = Path.Combine(App.ApplicationDataPath, "Plugins");
|
||||
|
||||
private readonly DispatcherTimer searchTimer = new()
|
||||
{
|
||||
Interval = TimeSpan.FromMilliseconds(300),
|
||||
};
|
||||
|
||||
public PluginManager()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
DataContext = pluginManagerDataContext;
|
||||
searchTimer.Tick += async (sender, e) =>
|
||||
{
|
||||
searchTimer.Stop();
|
||||
await SearchAllPlugins(pluginManagerDataContext.AllPluginsSearchText);
|
||||
};
|
||||
}
|
||||
|
||||
public void Remove(string pluginPath, uint? id)
|
||||
@@ -81,7 +94,9 @@ public partial class PluginManager : Window
|
||||
}
|
||||
}
|
||||
|
||||
IAsyncEnumerable<Mod> mods = client.Games[5665].Mods.Search().ToEnumerableAsync();
|
||||
Filter filter = ModFilter.Popular.Desc().Limit(100);
|
||||
|
||||
IAsyncEnumerable<Mod> mods = client.Games[modIoGameId].Mods.Search(filter).ToEnumerableAsync();
|
||||
await foreach (Mod mod in mods)
|
||||
{
|
||||
if (pluginIds.Contains(mod.Id))
|
||||
@@ -91,6 +106,8 @@ public partial class PluginManager : Window
|
||||
|
||||
pluginManagerDataContext.AllPlugins.Add(new PluginEntryDataContext(new(mod), new CommandHandler(async () => await Install(mod))));
|
||||
}
|
||||
|
||||
pluginManagerDataContext.IsLoading = false;
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
@@ -102,8 +119,6 @@ public partial class PluginManager : Window
|
||||
{
|
||||
pluginManagerDataContext.IsLoading = true;
|
||||
|
||||
Debug.WriteLine(mod.Modfile?.Download?.BinaryUrl + " | " + pluginsPath);
|
||||
|
||||
if (mod.Modfile?.Download?.BinaryUrl is null)
|
||||
{
|
||||
return;
|
||||
@@ -149,4 +164,65 @@ public partial class PluginManager : Window
|
||||
|
||||
pluginManagerDataContext.IsLoading = false;
|
||||
}
|
||||
|
||||
private void Image_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
{
|
||||
string uri = "https://mod.io/g/DesktopMagic";
|
||||
ProcessStartInfo psi = new ProcessStartInfo
|
||||
{
|
||||
UseShellExecute = true,
|
||||
FileName = uri
|
||||
};
|
||||
_ = Process.Start(psi);
|
||||
}
|
||||
|
||||
private void AllPluginsSearchTextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
|
||||
{
|
||||
pluginManagerDataContext.IsSearching = true;
|
||||
searchTimer.Stop();
|
||||
searchTimer.Start();
|
||||
}
|
||||
|
||||
private void InstalledPluginsSearchTextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(pluginManagerDataContext.InstalledPluginsSearchText))
|
||||
{
|
||||
foreach (PluginEntryDataContext pluginEntryDataContext in pluginManagerDataContext.InstalledPlugins)
|
||||
{
|
||||
pluginEntryDataContext.IsVisible = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (PluginEntryDataContext pluginEntryDataContext in pluginManagerDataContext.InstalledPlugins)
|
||||
{
|
||||
pluginEntryDataContext.IsVisible = pluginEntryDataContext.Name.Contains(pluginManagerDataContext.InstalledPluginsSearchText, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SearchAllPlugins(string searchString)
|
||||
{
|
||||
pluginManagerDataContext.AllPlugins.Clear();
|
||||
|
||||
if (!searchString.Contains('*'))
|
||||
{
|
||||
searchString = $"*{searchString.Trim()}*";
|
||||
}
|
||||
|
||||
Filter filter = ModFilter.Name.Like($"{searchString}").And(ModFilter.Popular.Desc()).Limit(100);
|
||||
|
||||
IAsyncEnumerable<Mod> mods = client.Games[modIoGameId].Mods.Search(filter).ToEnumerableAsync();
|
||||
await foreach (Mod mod in mods)
|
||||
{
|
||||
if (pluginManagerDataContext.InstalledPlugins.Any(p => p.Id == mod.Id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
pluginManagerDataContext.AllPlugins.Add(new PluginEntryDataContext(new(mod), new CommandHandler(async () => await Install(mod))));
|
||||
}
|
||||
|
||||
pluginManagerDataContext.IsSearching = false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user