mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Plugins - Added importing
This commit is contained in:
parent
f89e7d43fe
commit
b875e3d366
1
src/.idea/.idea.Artemis/.idea/avalonia.xml
generated
1
src/.idea/.idea.Artemis/.idea/avalonia.xml
generated
@ -75,6 +75,7 @@
|
||||
<entry key="Artemis.UI/Screens/Root/SplashView.axaml" value="Artemis.UI.Windows/Artemis.UI.Windows.csproj" />
|
||||
<entry key="Artemis.UI/Screens/Settings/Tabs/AboutTabView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||
<entry key="Artemis.UI/Screens/Settings/Tabs/GeneralTabView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||
<entry key="Artemis.UI/Screens/Settings/Tabs/PluginsTabView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||
<entry key="Artemis.UI/Screens/Sidebar/ContentDialogs/SidebarCategoryEditView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||
<entry key="Artemis.UI/Screens/Sidebar/Dialogs/ModuleActivationRequirementView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||
<entry key="Artemis.UI/Screens/Sidebar/Dialogs/ModuleActivationRequirementsView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||
|
||||
@ -476,6 +476,7 @@ namespace Artemis.Core.Services
|
||||
lock (_plugins)
|
||||
{
|
||||
_plugins.Remove(plugin);
|
||||
OnPluginUnloaded(new PluginEventArgs(plugin));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2,12 +2,15 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:settings="clr-namespace:Artemis.UI.Screens.Settings"
|
||||
mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="450"
|
||||
x:Class="Artemis.UI.Screens.Settings.PluginsTabView">
|
||||
x:Class="Artemis.UI.Screens.Settings.PluginsTabView"
|
||||
x:DataType="settings:PluginsTabViewModel">
|
||||
<Grid RowDefinitions="Auto,*" ColumnDefinitions="*,*" Width="900">
|
||||
<TextBox Grid.Row="0" Grid.Column="0" Text="{Binding SearchPluginInput}" Watermark="Search plugins" Margin="0 10" />
|
||||
<TextBox Grid.Row="0" Grid.Column="0" Classes="clearButton" Text="{CompiledBinding SearchPluginInput}" Watermark="Search plugins" Margin="0 10" />
|
||||
<Button Grid.Row="0" Grid.Column="1" Classes="accent" Command="{CompiledBinding ImportPlugin}" HorizontalAlignment="Right">Import plugin</Button>
|
||||
<ScrollViewer Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
||||
<ItemsControl Items="{Binding Plugins}" />
|
||||
<ItemsControl Items="{CompiledBinding Plugins}" />
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading.Tasks;
|
||||
@ -14,6 +15,8 @@ using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Artemis.UI.Shared.Services.Builders;
|
||||
using Avalonia.Threading;
|
||||
using DynamicData;
|
||||
using DynamicData.Binding;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Settings
|
||||
@ -35,13 +38,34 @@ namespace Artemis.UI.Screens.Settings
|
||||
_settingsVmFactory = settingsVmFactory;
|
||||
|
||||
DisplayName = "Plugins";
|
||||
Plugins = new ObservableCollection<PluginSettingsViewModel>();
|
||||
|
||||
this.WhenAnyValue(x => x.SearchPluginInput).Throttle(TimeSpan.FromMilliseconds(100)).Subscribe(SearchPlugins);
|
||||
this.WhenActivated((CompositeDisposable _) => GetPluginInstances());
|
||||
SourceList<Plugin> plugins = new();
|
||||
IObservable<Func<Plugin, bool>> pluginFilter = this.WhenAnyValue(vm => vm.SearchPluginInput).Throttle(TimeSpan.FromMilliseconds(100)).Select(CreatePredicate);
|
||||
|
||||
plugins.Connect()
|
||||
.Filter(pluginFilter)
|
||||
.Sort(SortExpressionComparer<Plugin>.Ascending(p => p.Info.Name))
|
||||
.TransformAsync(p => Dispatcher.UIThread.InvokeAsync(() => _settingsVmFactory.CreatePluginSettingsViewModel(p), DispatcherPriority.Background))
|
||||
.Bind(out ReadOnlyObservableCollection<PluginSettingsViewModel> pluginViewModels)
|
||||
.Subscribe();
|
||||
Plugins = pluginViewModels;
|
||||
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
plugins.AddRange(_pluginManagementService.GetAllPlugins());
|
||||
Observable.FromEventPattern<PluginEventArgs>(x => _pluginManagementService.PluginLoaded += x, x => _pluginManagementService.PluginLoaded -= x)
|
||||
.Subscribe(a => plugins.Add(a.EventArgs.Plugin))
|
||||
.DisposeWith(d);
|
||||
Observable.FromEventPattern<PluginEventArgs>(x => _pluginManagementService.PluginUnloaded += x, x => _pluginManagementService.PluginUnloaded -= x)
|
||||
.Subscribe(a => plugins.Remove(a.EventArgs.Plugin))
|
||||
.DisposeWith(d);
|
||||
Disposable.Create(() => plugins.Clear()).DisposeWith(d);
|
||||
});
|
||||
ImportPlugin = ReactiveCommand.CreateFromTask(ExecuteImportPlugin);
|
||||
}
|
||||
|
||||
public ObservableCollection<PluginSettingsViewModel> Plugins { get; }
|
||||
public ReadOnlyObservableCollection<PluginSettingsViewModel> Plugins { get; }
|
||||
public ReactiveCommand<Unit, Unit> ImportPlugin { get; }
|
||||
|
||||
public string? SearchPluginInput
|
||||
{
|
||||
@ -54,71 +78,43 @@ namespace Artemis.UI.Screens.Settings
|
||||
Utilities.OpenUrl(url);
|
||||
}
|
||||
|
||||
public async Task ImportPlugin()
|
||||
private async Task ExecuteImportPlugin()
|
||||
{
|
||||
string[]? files = await _windowService.CreateOpenFileDialog().WithTitle("Import Artemis plugin").HavingFilter(f => f.WithExtension("zip").WithName("ZIP files")).ShowAsync();
|
||||
if (files == null)
|
||||
return;
|
||||
|
||||
// Take the actual import off of the UI thread
|
||||
await Task.Run(() =>
|
||||
try
|
||||
{
|
||||
Plugin plugin = _pluginManagementService.ImportPlugin(files[0]);
|
||||
|
||||
GetPluginInstances();
|
||||
SearchPluginInput = plugin.Info.Name;
|
||||
|
||||
// Wait for the VM to be created asynchronously (it would be better to respond to some event here)
|
||||
await Task.Delay(200);
|
||||
// Enable it via the VM to enable the prerequisite dialog
|
||||
PluginSettingsViewModel? pluginViewModel = Plugins.FirstOrDefault(i => i.Plugin == plugin);
|
||||
if (pluginViewModel is {IsEnabled: false})
|
||||
pluginViewModel.IsEnabled = true;
|
||||
|
||||
_notificationService.CreateNotification()
|
||||
.WithTitle("Success")
|
||||
.WithMessage($"Imported plugin: {plugin.Info.Name}")
|
||||
.WithTitle("Plugin imported")
|
||||
.WithMessage($"Added the '{plugin.Info.Name}' plugin")
|
||||
.WithSeverity(NotificationSeverity.Success)
|
||||
.Show();
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _windowService.ShowConfirmContentDialog("Failed to import plugin", "Make sure the selected ZIP file is a valid Artemis plugin.\r\n" + e.Message, "Close", null);
|
||||
}
|
||||
}
|
||||
|
||||
public void GetPluginInstances()
|
||||
private Func<Plugin, bool> CreatePredicate(string? text)
|
||||
{
|
||||
Plugins.Clear();
|
||||
Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
_instances = _pluginManagementService.GetAllPlugins()
|
||||
.Select(p => _settingsVmFactory.CreatePluginSettingsViewModel(p))
|
||||
.OrderBy(i => i.Plugin.Info.Name)
|
||||
.ToList();
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
return _ => true;
|
||||
|
||||
SearchPlugins(SearchPluginInput);
|
||||
}, DispatcherPriority.Background);
|
||||
}
|
||||
|
||||
private void SearchPlugins(string? searchPluginInput)
|
||||
{
|
||||
if (_instances == null)
|
||||
return;
|
||||
|
||||
List<PluginSettingsViewModel> instances = _instances;
|
||||
string? search = searchPluginInput?.ToLower();
|
||||
if (!string.IsNullOrWhiteSpace(search))
|
||||
instances = instances.Where(i => i.Plugin.Info.Name.ToLower().Contains(search) ||
|
||||
i.Plugin.Info.Description != null && i.Plugin.Info.Description.ToLower().Contains(search)).ToList();
|
||||
|
||||
foreach (PluginSettingsViewModel pluginSettingsViewModel in instances)
|
||||
{
|
||||
if (!Plugins.Contains(pluginSettingsViewModel))
|
||||
Plugins.Add(pluginSettingsViewModel);
|
||||
}
|
||||
|
||||
foreach (PluginSettingsViewModel pluginSettingsViewModel in Plugins.ToList())
|
||||
{
|
||||
if (!instances.Contains(pluginSettingsViewModel))
|
||||
Plugins.Remove(pluginSettingsViewModel);
|
||||
}
|
||||
|
||||
Plugins.Sort(i => i.Plugin.Info.Name);
|
||||
return data => data.Info.Name.Contains(text, StringComparison.InvariantCultureIgnoreCase) ||
|
||||
(data.Info.Description != null && data.Info.Description.Contains(text, StringComparison.InvariantCultureIgnoreCase));
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user