mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
UI - Some VM restructure and added plugin VMs (WIP)
This commit is contained in:
parent
8ebd098186
commit
93cfc0e001
@ -26,4 +26,9 @@
|
|||||||
<HintPath>..\..\..\RGB.NET\bin\net5.0\RGB.NET.Core.dll</HintPath>
|
<HintPath>..\..\..\RGB.NET\bin\net5.0\RGB.NET.Core.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Update="Services\WindowService\ExceptionDialogView.axaml.cs">
|
||||||
|
<DependentUpon>%(Filename)</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -0,0 +1,2 @@
|
|||||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Cwindowservice/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||||
@ -1,8 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Artemis.UI.Avalonia.Shared.Utilities;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
|
using Button = Avalonia.Controls.Button;
|
||||||
|
|
||||||
namespace Artemis.UI.Avalonia.Shared.Services.Builders
|
namespace Artemis.UI.Avalonia.Shared.Services.Builders
|
||||||
{
|
{
|
||||||
@ -36,6 +38,19 @@ namespace Artemis.UI.Avalonia.Shared.Services.Builders
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a filter to the dialog
|
||||||
|
/// </summary>
|
||||||
|
public NotificationBuilder HavingButton(Action<NotificationButtonBuilder> configure)
|
||||||
|
{
|
||||||
|
NotificationButtonBuilder builder = new();
|
||||||
|
configure(builder);
|
||||||
|
_infoBar.ActionButton = builder.Build();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public NotificationBuilder WithSeverity(NotificationSeverity severity)
|
public NotificationBuilder WithSeverity(NotificationSeverity severity)
|
||||||
{
|
{
|
||||||
_infoBar.Severity = (InfoBarSeverity) severity;
|
_infoBar.Severity = (InfoBarSeverity) severity;
|
||||||
@ -71,6 +86,31 @@ namespace Artemis.UI.Avalonia.Shared.Services.Builders
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class NotificationButtonBuilder
|
||||||
|
{
|
||||||
|
private string _text = "Text";
|
||||||
|
private Action? _action;
|
||||||
|
|
||||||
|
public NotificationButtonBuilder WithText(string text)
|
||||||
|
{
|
||||||
|
_text = text;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotificationButtonBuilder WithAction(Action action)
|
||||||
|
{
|
||||||
|
_action = action;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IControl Build()
|
||||||
|
{
|
||||||
|
return _action != null
|
||||||
|
? new Button {Content = _text, Command = new DelegateCommand(_ => _action())}
|
||||||
|
: new Button {Content = _text};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public enum NotificationSeverity
|
public enum NotificationSeverity
|
||||||
{
|
{
|
||||||
Informational,
|
Informational,
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System.Threading.Tasks;
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Artemis.UI.Avalonia.Shared.Services.Builders;
|
using Artemis.UI.Avalonia.Shared.Services.Builders;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
|
||||||
@ -7,20 +8,27 @@ namespace Artemis.UI.Avalonia.Shared.Services.Interfaces
|
|||||||
public interface IWindowService : IArtemisSharedUIService
|
public interface IWindowService : IArtemisSharedUIService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a view model instance of type <typeparamref name="T" /> and shows its corresponding View as a window
|
/// Creates a view model instance of type <typeparamref name="T" /> and shows its corresponding View as a window
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of view model to create</typeparam>
|
/// <typeparam name="T">The type of view model to create</typeparam>
|
||||||
/// <returns>The created view model</returns>
|
/// <returns>The created view model</returns>
|
||||||
T ShowWindow<T>();
|
T ShowWindow<T>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Given a ViewModel, show its corresponding View as a window
|
/// Given a ViewModel, show its corresponding View as a window
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="viewModel">ViewModel to show the View for</param>
|
/// <param name="viewModel">ViewModel to show the View for</param>
|
||||||
void ShowWindow(object viewModel);
|
void ShowWindow(object viewModel);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Given a ViewModel, show its corresponding View as a Dialog
|
/// Shows a dialog displaying the given exception
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="title">The title of the dialog</param>
|
||||||
|
/// <param name="exception">The exception to display</param>
|
||||||
|
void ShowExceptionDialog(string title, Exception exception);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Given a ViewModel, show its corresponding View as a Dialog
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The return type</typeparam>
|
/// <typeparam name="T">The return type</typeparam>
|
||||||
/// <param name="viewModel">ViewModel to show the View for</param>
|
/// <param name="viewModel">ViewModel to show the View for</param>
|
||||||
@ -28,13 +36,13 @@ namespace Artemis.UI.Avalonia.Shared.Services.Interfaces
|
|||||||
Task<T> ShowDialogAsync<T>(object viewModel);
|
Task<T> ShowDialogAsync<T>(object viewModel);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an open file dialog, use the fluent API to configure it
|
/// Creates an open file dialog, use the fluent API to configure it
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The builder that can be used to configure the dialog</returns>
|
/// <returns>The builder that can be used to configure the dialog</returns>
|
||||||
OpenFileDialogBuilder CreateOpenFileDialog();
|
OpenFileDialogBuilder CreateOpenFileDialog();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a save file dialog, use the fluent API to configure it
|
/// Creates a save file dialog, use the fluent API to configure it
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The builder that can be used to configure the dialog</returns>
|
/// <returns>The builder that can be used to configure the dialog</returns>
|
||||||
SaveFileDialogBuilder CreateSaveFileDialog();
|
SaveFileDialogBuilder CreateSaveFileDialog();
|
||||||
|
|||||||
@ -0,0 +1,9 @@
|
|||||||
|
<Window xmlns="https://github.com/avaloniaui"
|
||||||
|
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"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Artemis.UI.Avalonia.Shared.Services.ExceptionDialogView"
|
||||||
|
Title="ExceptionDialogView">
|
||||||
|
Eh you got an exception but I didn't write the viewer yet :(
|
||||||
|
</Window>
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Avalonia.Shared.Services
|
||||||
|
{
|
||||||
|
public partial class ExceptionDialogView : ReactiveWindow<ExceptionDialogViewModel>
|
||||||
|
{
|
||||||
|
public ExceptionDialogView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
#if DEBUG
|
||||||
|
this.AttachDevTools();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Avalonia.Shared.Services
|
||||||
|
{
|
||||||
|
public class ExceptionDialogViewModel : ActivatableViewModelBase
|
||||||
|
{
|
||||||
|
public ExceptionDialogViewModel(string title, Exception exception)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,6 +14,7 @@ namespace Artemis.UI.Avalonia.Shared.Services
|
|||||||
internal class WindowService : IWindowService
|
internal class WindowService : IWindowService
|
||||||
{
|
{
|
||||||
private readonly IKernel _kernel;
|
private readonly IKernel _kernel;
|
||||||
|
private bool _exceptionDialogOpen;
|
||||||
|
|
||||||
public WindowService(IKernel kernel)
|
public WindowService(IKernel kernel)
|
||||||
{
|
{
|
||||||
@ -42,6 +43,23 @@ namespace Artemis.UI.Avalonia.Shared.Services
|
|||||||
window.Show();
|
window.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void ShowExceptionDialog(string title, Exception exception)
|
||||||
|
{
|
||||||
|
if (_exceptionDialogOpen)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_exceptionDialogOpen = true;
|
||||||
|
ShowDialogAsync<object>(new ExceptionDialogViewModel(title, exception)).GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_exceptionDialogOpen = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<T> ShowDialogAsync<T>(object viewModel)
|
public async Task<T> ShowDialogAsync<T>(object viewModel)
|
||||||
{
|
{
|
||||||
if (Application.Current.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime classic)
|
if (Application.Current.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime classic)
|
||||||
60
src/Artemis.UI.Avalonia.Shared/Utilities/DelegateCommand.cs
Normal file
60
src/Artemis.UI.Avalonia.Shared/Utilities/DelegateCommand.cs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Avalonia.Shared.Utilities
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides a command that simply calls a delegate when invoked
|
||||||
|
/// </summary>
|
||||||
|
public class DelegateCommand : ICommand
|
||||||
|
{
|
||||||
|
private readonly Predicate<object?>? _canExecute;
|
||||||
|
private readonly Action<object?> _execute;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the <see cref="DelegateCommand" /> class
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="execute">The delegate to execute</param>
|
||||||
|
public DelegateCommand(Action<object?> execute) : this(execute, null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the <see cref="DelegateCommand" /> class with a predicate indicating whether the command
|
||||||
|
/// can be executed
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="execute">The delegate to execute</param>
|
||||||
|
/// <param name="canExecute">The predicate that determines whether the command can execute</param>
|
||||||
|
public DelegateCommand(Action<object?> execute, Predicate<object?>? canExecute)
|
||||||
|
{
|
||||||
|
_execute = execute;
|
||||||
|
_canExecute = canExecute;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the <see cref="CanExecuteChanged" /> event
|
||||||
|
/// </summary>
|
||||||
|
public void RaiseCanExecuteChanged()
|
||||||
|
{
|
||||||
|
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public event EventHandler? CanExecuteChanged;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool CanExecute(object? parameter)
|
||||||
|
{
|
||||||
|
if (_canExecute == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return _canExecute(parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Execute(object? parameter)
|
||||||
|
{
|
||||||
|
_execute(parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,6 +11,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Remove="Assets\Images\home-banner.png" />
|
<None Remove="Assets\Images\home-banner.png" />
|
||||||
|
<None Remove="Screens\Settings\Tabs\Plugins\Views\PluginFeatureView.xaml" />
|
||||||
|
<None Remove="Screens\Settings\Tabs\Plugins\Views\PluginSettingsView.xaml" />
|
||||||
|
<None Remove="Screens\Settings\Tabs\Plugins\Views\PluginSettingsWindowView.xaml" />
|
||||||
<None Remove="Screens\SurfaceEditor\Views\ListDeviceView.xaml" />
|
<None Remove="Screens\SurfaceEditor\Views\ListDeviceView.xaml" />
|
||||||
<None Remove="Screens\SurfaceEditor\Views\SurfaceDeviceView.xaml" />
|
<None Remove="Screens\SurfaceEditor\Views\SurfaceDeviceView.xaml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@ -59,6 +62,9 @@
|
|||||||
<Compile Update="Screens\Root\Views\SidebarView.axaml.cs">
|
<Compile Update="Screens\Root\Views\SidebarView.axaml.cs">
|
||||||
<DependentUpon>%(Filename)</DependentUpon>
|
<DependentUpon>%(Filename)</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Update="Screens\Settings\Tabs\Plugins\Views\PluginsTabView.axaml.cs">
|
||||||
|
<DependentUpon>%(Filename)</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Update="Screens\Sidebar\Views\SidebarView.axaml.cs">
|
<Compile Update="Screens\Sidebar\Views\SidebarView.axaml.cs">
|
||||||
<DependentUpon>SidebarView.axaml</DependentUpon>
|
<DependentUpon>SidebarView.axaml</DependentUpon>
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
@ -77,6 +83,18 @@
|
|||||||
<Content Include="Assets\Images\Logo\bow.ico" />
|
<Content Include="Assets\Images\Logo\bow.ico" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Page Include="Screens\Settings\Tabs\Plugins\Views\PluginFeatureView.xaml">
|
||||||
|
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
<Page Include="Screens\Settings\Tabs\Plugins\Views\PluginSettingsView.xaml">
|
||||||
|
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
<Page Include="Screens\Settings\Tabs\Plugins\Views\PluginSettingsWindowView.xaml">
|
||||||
|
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
<Page Include="Screens\SurfaceEditor\Views\ListDeviceView.xaml">
|
<Page Include="Screens\SurfaceEditor\Views\ListDeviceView.xaml">
|
||||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
|||||||
@ -6,7 +6,7 @@ using Artemis.Core;
|
|||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
using Artemis.UI.Avalonia.Ninject.Factories;
|
using Artemis.UI.Avalonia.Ninject.Factories;
|
||||||
using Artemis.UI.Avalonia.Screens.Home.ViewModels;
|
using Artemis.UI.Avalonia.Screens.Home.ViewModels;
|
||||||
using Artemis.UI.Avalonia.Screens.Settings.ViewModels;
|
using Artemis.UI.Avalonia.Screens.Settings;
|
||||||
using Artemis.UI.Avalonia.Screens.SurfaceEditor.ViewModels;
|
using Artemis.UI.Avalonia.Screens.SurfaceEditor.ViewModels;
|
||||||
using Artemis.UI.Avalonia.Screens.Workshop.ViewModels;
|
using Artemis.UI.Avalonia.Screens.Workshop.ViewModels;
|
||||||
using Material.Icons;
|
using Material.Icons;
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Avalonia.Screens.Settings.Views.SettingsView">
|
x:Class="Artemis.UI.Avalonia.Screens.Settings.SettingsView">
|
||||||
<TabControl Margin="12" Items="{Binding SettingTabs}">
|
<TabControl Margin="12" Items="{Binding SettingTabs}">
|
||||||
<TabControl.ItemTemplate>
|
<TabControl.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
@ -1,8 +1,7 @@
|
|||||||
using Artemis.UI.Avalonia.Screens.Settings.ViewModels;
|
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Avalonia.Screens.Settings.Views
|
namespace Artemis.UI.Avalonia.Screens.Settings
|
||||||
{
|
{
|
||||||
public class SettingsView : ReactiveUserControl<SettingsViewModel>
|
public class SettingsView : ReactiveUserControl<SettingsViewModel>
|
||||||
{
|
{
|
||||||
@ -1,7 +1,8 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using Artemis.UI.Avalonia.Screens.Settings.Tabs.ViewModels;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Avalonia.Screens.Settings.ViewModels
|
namespace Artemis.UI.Avalonia.Screens.Settings
|
||||||
{
|
{
|
||||||
public class SettingsViewModel : MainScreenViewModel
|
public class SettingsViewModel : MainScreenViewModel
|
||||||
{
|
{
|
||||||
@ -0,0 +1,213 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.Core.Services;
|
||||||
|
using Artemis.UI.Avalonia.Shared.Services.Builders;
|
||||||
|
using Artemis.UI.Avalonia.Shared.Services.Interfaces;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Avalonia.Screens.Settings.Tabs.Plugins.ViewModels
|
||||||
|
{
|
||||||
|
public class PluginFeatureViewModel : ActivatableViewModelBase
|
||||||
|
{
|
||||||
|
private readonly ICoreService _coreService;
|
||||||
|
private readonly INotificationService _notificationService;
|
||||||
|
private readonly IPluginManagementService _pluginManagementService;
|
||||||
|
private readonly IWindowService _windowService;
|
||||||
|
private bool _enabling;
|
||||||
|
|
||||||
|
public PluginFeatureViewModel(PluginFeatureInfo pluginFeatureInfo,
|
||||||
|
bool showShield,
|
||||||
|
ICoreService coreService,
|
||||||
|
IWindowService windowService,
|
||||||
|
INotificationService notificationService,
|
||||||
|
IPluginManagementService pluginManagementService)
|
||||||
|
{
|
||||||
|
_coreService = coreService;
|
||||||
|
_windowService = windowService;
|
||||||
|
_notificationService = notificationService;
|
||||||
|
_pluginManagementService = pluginManagementService;
|
||||||
|
|
||||||
|
FeatureInfo = pluginFeatureInfo;
|
||||||
|
ShowShield = FeatureInfo.Plugin.Info.RequiresAdmin && showShield;
|
||||||
|
|
||||||
|
_pluginManagementService.PluginFeatureEnabling += OnFeatureEnabling;
|
||||||
|
_pluginManagementService.PluginFeatureEnabled += OnFeatureEnableStopped;
|
||||||
|
_pluginManagementService.PluginFeatureEnableFailed += OnFeatureEnableStopped;
|
||||||
|
|
||||||
|
FeatureInfo.Plugin.Enabled += PluginOnToggled;
|
||||||
|
FeatureInfo.Plugin.Disabled += PluginOnToggled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PluginFeatureInfo FeatureInfo { get; }
|
||||||
|
public Exception? LoadException => FeatureInfo.LoadException;
|
||||||
|
|
||||||
|
public bool ShowShield { get; }
|
||||||
|
|
||||||
|
public bool Enabling
|
||||||
|
{
|
||||||
|
get => _enabling;
|
||||||
|
set => this.RaiseAndSetIfChanged(ref _enabling, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsEnabled
|
||||||
|
{
|
||||||
|
get => FeatureInfo.Instance != null && FeatureInfo.Instance.IsEnabled;
|
||||||
|
set => Task.Run(() => UpdateEnabled(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanToggleEnabled => FeatureInfo.Plugin.IsEnabled && !FeatureInfo.AlwaysEnabled;
|
||||||
|
public bool CanInstallPrerequisites => FeatureInfo.Prerequisites.Any();
|
||||||
|
public bool CanRemovePrerequisites => FeatureInfo.Prerequisites.Any(p => p.UninstallActions.Any());
|
||||||
|
public bool IsPopupEnabled => CanInstallPrerequisites || CanRemovePrerequisites;
|
||||||
|
|
||||||
|
public void ShowLogsFolder()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Process.Start(Environment.GetEnvironmentVariable("WINDIR") + @"\explorer.exe", Path.Combine(Constants.DataFolder, "Logs"));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_windowService.ShowExceptionDialog("Welp, we couldn\'t open the logs folder for you", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ViewLoadException()
|
||||||
|
{
|
||||||
|
if (LoadException != null)
|
||||||
|
_windowService.ShowExceptionDialog("Feature failed to enable", LoadException);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InstallPrerequisites()
|
||||||
|
{
|
||||||
|
if (FeatureInfo.Prerequisites.Any())
|
||||||
|
await PluginPrerequisitesInstallDialogViewModel.Show(_dialogService, new List<IPrerequisitesSubject> {FeatureInfo});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RemovePrerequisites()
|
||||||
|
{
|
||||||
|
if (FeatureInfo.Prerequisites.Any(p => p.UninstallActions.Any()))
|
||||||
|
{
|
||||||
|
await PluginPrerequisitesUninstallDialogViewModel.Show(_dialogService, new List<IPrerequisitesSubject> {FeatureInfo});
|
||||||
|
this.RaisePropertyChanged(nameof(IsEnabled));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
_pluginManagementService.PluginFeatureEnabling -= OnFeatureEnabling;
|
||||||
|
_pluginManagementService.PluginFeatureEnabled -= OnFeatureEnableStopped;
|
||||||
|
_pluginManagementService.PluginFeatureEnableFailed -= OnFeatureEnableStopped;
|
||||||
|
|
||||||
|
FeatureInfo.Plugin.Enabled -= PluginOnToggled;
|
||||||
|
FeatureInfo.Plugin.Disabled -= PluginOnToggled;
|
||||||
|
}
|
||||||
|
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task UpdateEnabled(bool enable)
|
||||||
|
{
|
||||||
|
if (IsEnabled == enable)
|
||||||
|
{
|
||||||
|
this.RaisePropertyChanged(nameof(IsEnabled));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FeatureInfo.Instance == null)
|
||||||
|
{
|
||||||
|
this.RaisePropertyChanged(nameof(IsEnabled));
|
||||||
|
_notificationService.CreateNotification()
|
||||||
|
.WithMessage($"Feature '{FeatureInfo.Name}' is in a broken state and cannot enable.")
|
||||||
|
.HavingButton(b => b.WithText("View logs").WithAction(ShowLogsFolder))
|
||||||
|
.WithSeverity(NotificationSeverity.Error)
|
||||||
|
.Show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enable)
|
||||||
|
{
|
||||||
|
Enabling = true;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (FeatureInfo.Plugin.Info.RequiresAdmin && !_coreService.IsElevated)
|
||||||
|
{
|
||||||
|
bool confirmed = await _dialogService.ShowConfirmDialog("Enable feature", "The plugin of this feature requires admin rights, are you sure you want to enable it?");
|
||||||
|
if (!confirmed)
|
||||||
|
{
|
||||||
|
this.RaisePropertyChanged(nameof(IsEnabled));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if all prerequisites are met async
|
||||||
|
if (!FeatureInfo.ArePrerequisitesMet())
|
||||||
|
{
|
||||||
|
await PluginPrerequisitesInstallDialogViewModel.Show(_dialogService, new List<IPrerequisitesSubject> {FeatureInfo});
|
||||||
|
if (!FeatureInfo.ArePrerequisitesMet())
|
||||||
|
{
|
||||||
|
this.RaisePropertyChanged(nameof(IsEnabled));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Run(() => _pluginManagementService.EnablePluginFeature(FeatureInfo.Instance!, true));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_notificationService.CreateNotification()
|
||||||
|
.WithMessage($"Failed to enable '{FeatureInfo.Name}'.\r\n{e.Message}")
|
||||||
|
.HavingButton(b => b.WithText("View logs").WithAction(ShowLogsFolder))
|
||||||
|
.WithSeverity(NotificationSeverity.Error)
|
||||||
|
.Show();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Enabling = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pluginManagementService.DisablePluginFeature(FeatureInfo.Instance, true);
|
||||||
|
this.RaisePropertyChanged(nameof(IsEnabled));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnFeatureEnabling(object? sender, PluginFeatureEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.PluginFeature != FeatureInfo.Instance)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Enabling = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnFeatureEnableStopped(object? sender, PluginFeatureEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.PluginFeature != FeatureInfo.Instance)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Enabling = false;
|
||||||
|
|
||||||
|
this.RaisePropertyChanged(nameof(IsEnabled));
|
||||||
|
this.RaisePropertyChanged(nameof(LoadException));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PluginOnToggled(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
this.RaisePropertyChanged(nameof(CanToggleEnabled));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,325 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.Core.Services;
|
||||||
|
using Artemis.UI.Avalonia.Screens.Settings.Tabs.Plugins.ViewModels;
|
||||||
|
using Artemis.UI.Ninject.Factories;
|
||||||
|
using Artemis.UI.Screens.Plugins;
|
||||||
|
using Artemis.UI.Shared.Services;
|
||||||
|
using Ninject;
|
||||||
|
using Stylet;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
||||||
|
{
|
||||||
|
public class PluginSettingsViewModel : Conductor<PluginFeatureViewModel>.Collection.AllActive
|
||||||
|
{
|
||||||
|
private readonly ICoreService _coreService;
|
||||||
|
private readonly IDialogService _dialogService;
|
||||||
|
private readonly IMessageService _messageService;
|
||||||
|
private readonly IPluginManagementService _pluginManagementService;
|
||||||
|
private readonly ISettingsVmFactory _settingsVmFactory;
|
||||||
|
private readonly IWindowManager _windowManager;
|
||||||
|
private bool _canInstallPrerequisites;
|
||||||
|
private bool _canRemovePrerequisites;
|
||||||
|
private bool _enabling;
|
||||||
|
private bool _isSettingsPopupOpen;
|
||||||
|
private Plugin _plugin;
|
||||||
|
|
||||||
|
public PluginSettingsViewModel(Plugin plugin,
|
||||||
|
ISettingsVmFactory settingsVmFactory,
|
||||||
|
ICoreService coreService,
|
||||||
|
IWindowManager windowManager,
|
||||||
|
IDialogService dialogService,
|
||||||
|
IPluginManagementService pluginManagementService,
|
||||||
|
IMessageService messageService)
|
||||||
|
{
|
||||||
|
Plugin = plugin;
|
||||||
|
|
||||||
|
_settingsVmFactory = settingsVmFactory;
|
||||||
|
_coreService = coreService;
|
||||||
|
_windowManager = windowManager;
|
||||||
|
_dialogService = dialogService;
|
||||||
|
_pluginManagementService = pluginManagementService;
|
||||||
|
_messageService = messageService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Plugin Plugin
|
||||||
|
{
|
||||||
|
get => _plugin;
|
||||||
|
set => SetAndNotify(ref _plugin, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Enabling
|
||||||
|
{
|
||||||
|
get => _enabling;
|
||||||
|
set => SetAndNotify(ref _enabling, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Type => Plugin.GetType().BaseType?.Name ?? Plugin.GetType().Name;
|
||||||
|
public bool CanOpenSettings => IsEnabled && Plugin.ConfigurationDialog != null;
|
||||||
|
|
||||||
|
public bool IsEnabled
|
||||||
|
{
|
||||||
|
get => Plugin.IsEnabled;
|
||||||
|
set => Task.Run(() => UpdateEnabled(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsSettingsPopupOpen
|
||||||
|
{
|
||||||
|
get => _isSettingsPopupOpen;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!SetAndNotify(ref _isSettingsPopupOpen, value)) return;
|
||||||
|
CheckPrerequisites();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanInstallPrerequisites
|
||||||
|
{
|
||||||
|
get => _canInstallPrerequisites;
|
||||||
|
set => SetAndNotify(ref _canInstallPrerequisites, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanRemovePrerequisites
|
||||||
|
{
|
||||||
|
get => _canRemovePrerequisites;
|
||||||
|
set => SetAndNotify(ref _canRemovePrerequisites, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OpenSettings()
|
||||||
|
{
|
||||||
|
PluginConfigurationDialog configurationViewModel = (PluginConfigurationDialog) Plugin.ConfigurationDialog;
|
||||||
|
if (configurationViewModel == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PluginConfigurationViewModel viewModel = (PluginConfigurationViewModel) Plugin.Kernel.Get(configurationViewModel.Type);
|
||||||
|
_windowManager.ShowWindow(new PluginSettingsWindowViewModel(viewModel));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_dialogService.ShowExceptionDialog("An exception occured while trying to show the plugin's settings window", e);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OpenPluginDirectory()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Process.Start(Environment.GetEnvironmentVariable("WINDIR") + @"\explorer.exe", Plugin.Directory.FullName);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_dialogService.ShowExceptionDialog("Welp, we couldn't open the device's plugin folder for you", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Reload()
|
||||||
|
{
|
||||||
|
bool wasEnabled = IsEnabled;
|
||||||
|
|
||||||
|
_pluginManagementService.UnloadPlugin(Plugin);
|
||||||
|
Items.Clear();
|
||||||
|
|
||||||
|
Plugin = _pluginManagementService.LoadPlugin(Plugin.Directory);
|
||||||
|
foreach (PluginFeatureInfo pluginFeatureInfo in Plugin.Features)
|
||||||
|
Items.Add(_settingsVmFactory.CreatePluginFeatureViewModel(pluginFeatureInfo, false));
|
||||||
|
|
||||||
|
if (wasEnabled)
|
||||||
|
await UpdateEnabled(true);
|
||||||
|
|
||||||
|
_messageService.ShowMessage("Reloaded plugin.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InstallPrerequisites()
|
||||||
|
{
|
||||||
|
List<IPrerequisitesSubject> subjects = new() {Plugin.Info};
|
||||||
|
subjects.AddRange(Plugin.Features.Where(f => f.AlwaysEnabled));
|
||||||
|
|
||||||
|
if (subjects.Any(s => s.Prerequisites.Any()))
|
||||||
|
await PluginPrerequisitesInstallDialogViewModel.Show(_dialogService, subjects);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RemovePrerequisites(bool forPluginRemoval = false)
|
||||||
|
{
|
||||||
|
List<IPrerequisitesSubject> subjects = new() {Plugin.Info};
|
||||||
|
subjects.AddRange(!forPluginRemoval ? Plugin.Features.Where(f => f.AlwaysEnabled) : Plugin.Features);
|
||||||
|
|
||||||
|
if (subjects.Any(s => s.Prerequisites.Any(p => p.UninstallActions.Any())))
|
||||||
|
{
|
||||||
|
await PluginPrerequisitesUninstallDialogViewModel.Show(_dialogService, subjects, forPluginRemoval ? "SKIP, REMOVE PLUGIN" : "CANCEL");
|
||||||
|
NotifyOfPropertyChange(nameof(IsEnabled));
|
||||||
|
NotifyOfPropertyChange(nameof(CanOpenSettings));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RemoveSettings()
|
||||||
|
{
|
||||||
|
bool confirmed = await _dialogService.ShowConfirmDialog("Clear plugin settings", "Are you sure you want to clear the settings of this plugin?");
|
||||||
|
if (!confirmed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool wasEnabled = IsEnabled;
|
||||||
|
|
||||||
|
if (IsEnabled)
|
||||||
|
await UpdateEnabled(false);
|
||||||
|
|
||||||
|
_pluginManagementService.RemovePluginSettings(Plugin);
|
||||||
|
|
||||||
|
if (wasEnabled)
|
||||||
|
await UpdateEnabled(true);
|
||||||
|
|
||||||
|
_messageService.ShowMessage("Cleared plugin settings.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Remove()
|
||||||
|
{
|
||||||
|
bool confirmed = await _dialogService.ShowConfirmDialog("Remove plugin", "Are you sure you want to remove this plugin?");
|
||||||
|
if (!confirmed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If the plugin or any of its features has uninstall actions, offer to run these
|
||||||
|
List<IPrerequisitesSubject> subjects = new() {Plugin.Info};
|
||||||
|
subjects.AddRange(Plugin.Features);
|
||||||
|
if (subjects.Any(s => s.Prerequisites.Any(p => p.UninstallActions.Any())))
|
||||||
|
await RemovePrerequisites(true);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_pluginManagementService.RemovePlugin(Plugin, false);
|
||||||
|
((PluginSettingsTabViewModel) Parent).GetPluginInstances();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_dialogService.ShowExceptionDialog("Failed to remove plugin", e);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
_messageService.ShowMessage("Removed plugin.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShowLogsFolder()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Process.Start(Environment.GetEnvironmentVariable("WINDIR") + @"\explorer.exe", Path.Combine(Constants.DataFolder, "Logs"));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_dialogService.ShowExceptionDialog("Welp, we couldn\'t open the logs folder for you", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OpenUri(Uri uri)
|
||||||
|
{
|
||||||
|
Core.Utilities.OpenUrl(uri.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PluginManagementServiceOnPluginToggled(object sender, PluginEventArgs e)
|
||||||
|
{
|
||||||
|
NotifyOfPropertyChange(nameof(IsEnabled));
|
||||||
|
NotifyOfPropertyChange(nameof(CanOpenSettings));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task UpdateEnabled(bool enable)
|
||||||
|
{
|
||||||
|
if (IsEnabled == enable)
|
||||||
|
{
|
||||||
|
NotifyOfPropertyChange(nameof(IsEnabled));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enable)
|
||||||
|
{
|
||||||
|
Enabling = true;
|
||||||
|
|
||||||
|
if (Plugin.Info.RequiresAdmin && !_coreService.IsElevated)
|
||||||
|
{
|
||||||
|
bool confirmed = await _dialogService.ShowConfirmDialog("Enable plugin", "This plugin requires admin rights, are you sure you want to enable it?");
|
||||||
|
if (!confirmed)
|
||||||
|
{
|
||||||
|
CancelEnable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if all prerequisites are met async
|
||||||
|
List<IPrerequisitesSubject> subjects = new() {Plugin.Info};
|
||||||
|
subjects.AddRange(Plugin.Features.Where(f => f.AlwaysEnabled || f.EnabledInStorage));
|
||||||
|
|
||||||
|
if (subjects.Any(s => !s.ArePrerequisitesMet()))
|
||||||
|
{
|
||||||
|
await PluginPrerequisitesInstallDialogViewModel.Show(_dialogService, subjects);
|
||||||
|
if (!subjects.All(s => s.ArePrerequisitesMet()))
|
||||||
|
{
|
||||||
|
CancelEnable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Run(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_pluginManagementService.EnablePlugin(Plugin, true, true);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_messageService.ShowMessage($"Failed to enable plugin {Plugin.Info.Name}\r\n{e.Message}", "VIEW LOGS", ShowLogsFolder);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Enabling = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_pluginManagementService.DisablePlugin(Plugin, true);
|
||||||
|
|
||||||
|
NotifyOfPropertyChange(nameof(IsEnabled));
|
||||||
|
NotifyOfPropertyChange(nameof(CanOpenSettings));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CancelEnable()
|
||||||
|
{
|
||||||
|
Enabling = false;
|
||||||
|
NotifyOfPropertyChange(nameof(IsEnabled));
|
||||||
|
NotifyOfPropertyChange(nameof(CanOpenSettings));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckPrerequisites()
|
||||||
|
{
|
||||||
|
CanInstallPrerequisites = Plugin.Info.Prerequisites.Any() ||
|
||||||
|
Plugin.Features.Where(f => f.AlwaysEnabled).Any(f => f.Prerequisites.Any());
|
||||||
|
CanRemovePrerequisites = Plugin.Info.Prerequisites.Any(p => p.UninstallActions.Any()) ||
|
||||||
|
Plugin.Features.Where(f => f.AlwaysEnabled).Any(f => f.Prerequisites.Any(p => p.UninstallActions.Any()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Overrides of Screen
|
||||||
|
|
||||||
|
protected override void OnInitialActivate()
|
||||||
|
{
|
||||||
|
foreach (PluginFeatureInfo pluginFeatureInfo in Plugin.Features)
|
||||||
|
Items.Add(_settingsVmFactory.CreatePluginFeatureViewModel(pluginFeatureInfo, false));
|
||||||
|
|
||||||
|
_pluginManagementService.PluginDisabled += PluginManagementServiceOnPluginToggled;
|
||||||
|
_pluginManagementService.PluginEnabled += PluginManagementServiceOnPluginToggled;
|
||||||
|
base.OnInitialActivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnClose()
|
||||||
|
{
|
||||||
|
_pluginManagementService.PluginDisabled -= PluginManagementServiceOnPluginToggled;
|
||||||
|
_pluginManagementService.PluginEnabled -= PluginManagementServiceOnPluginToggled;
|
||||||
|
base.OnClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
using System;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Stylet;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
||||||
|
{
|
||||||
|
public class PluginSettingsWindowViewModel : Conductor<PluginConfigurationViewModel>
|
||||||
|
{
|
||||||
|
private readonly PluginConfigurationViewModel _configurationViewModel;
|
||||||
|
|
||||||
|
public PluginSettingsWindowViewModel(PluginConfigurationViewModel configurationViewModel)
|
||||||
|
{
|
||||||
|
_configurationViewModel = configurationViewModel ?? throw new ArgumentNullException(nameof(configurationViewModel));
|
||||||
|
Plugin = configurationViewModel.Plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Plugin Plugin { get; }
|
||||||
|
|
||||||
|
protected override void OnInitialActivate()
|
||||||
|
{
|
||||||
|
ActiveItem = _configurationViewModel;
|
||||||
|
ActiveItem.Closed += ActiveItemOnClosed;
|
||||||
|
|
||||||
|
base.OnInitialActivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ActiveItemOnClosed(object sender, CloseEventArgs e)
|
||||||
|
{
|
||||||
|
ActiveItem.Closed -= ActiveItemOnClosed;
|
||||||
|
RequestClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
namespace Artemis.UI.Avalonia.Screens.Settings.Tabs.ViewModels
|
||||||
|
{
|
||||||
|
public class PluginsTabViewModel : ActivatableViewModelBase
|
||||||
|
{
|
||||||
|
public PluginsTabViewModel()
|
||||||
|
{
|
||||||
|
DisplayName = "Plugins";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
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"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Artemis.UI.Avalonia.Screens.Settings.Tabs.Plugins.Views.PluginFeatureView">
|
||||||
|
Welcome to Avalonia!
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Avalonia.Screens.Settings.Tabs.Plugins.Views
|
||||||
|
{
|
||||||
|
public partial class PluginFeatureView : UserControl
|
||||||
|
{
|
||||||
|
public PluginFeatureView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,106 @@
|
|||||||
|
<UserControl x:Class="Artemis.UI.Screens.Settings.Tabs.Plugins.PluginFeatureView"
|
||||||
|
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:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="clr-namespace:Artemis.UI.Screens.Settings.Tabs.Plugins"
|
||||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
|
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||||
|
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||||
|
xmlns:viewModels="clr-namespace:Artemis.UI.Avalonia.Screens.Settings.Tabs.Plugins.ViewModels"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
|
d:DataContext="{d:DesignInstance viewModels:PluginFeatureViewModel}">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary
|
||||||
|
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.PopupBox.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
<shared:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||||
|
</ResourceDictionary>
|
||||||
|
</UserControl.Resources>
|
||||||
|
<Grid Margin="-3 -8">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="30" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<!-- Icon column -->
|
||||||
|
<shared:ArtemisIcon Grid.Column="0"
|
||||||
|
Icon="{Binding FeatureInfo.ResolvedIcon}"
|
||||||
|
Width="20"
|
||||||
|
Height="20"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Visibility="{Binding LoadException, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted, FallbackValue=Collapsed}" />
|
||||||
|
|
||||||
|
<Button Grid.Column="0"
|
||||||
|
Margin="-8"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Visibility="{Binding LoadException, Converter={StaticResource NullToVisibilityConverter}, FallbackValue=Collapsed}"
|
||||||
|
Style="{StaticResource MaterialDesignIconButton}"
|
||||||
|
Foreground="#E74C4C"
|
||||||
|
ToolTip="An exception occurred while enabling this feature, click to view"
|
||||||
|
Command="{s:Action ViewLoadException}">
|
||||||
|
<materialDesign:PackIcon Kind="AlertCircle" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<!-- Display name column -->
|
||||||
|
<TextBlock Grid.Column="1"
|
||||||
|
Text="{Binding FeatureInfo.Name}"
|
||||||
|
Style="{StaticResource MaterialDesignTextBlock}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
ToolTip="{Binding FeatureInfo.Description}" />
|
||||||
|
|
||||||
|
<!-- Enable toggle column -->
|
||||||
|
<StackPanel Grid.Column="2"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Margin="8"
|
||||||
|
Visibility="{Binding Enabling, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay, FallbackValue=Collapsed}"
|
||||||
|
Orientation="Horizontal"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
ToolTip="This feature cannot be disabled without disabling the whole plugin"
|
||||||
|
ToolTipService.IsEnabled="{Binding FeatureInfo.AlwaysEnabled}">
|
||||||
|
<materialDesign:PackIcon Kind="ShieldHalfFull"
|
||||||
|
ToolTip="Plugin requires admin rights"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Margin="0 0 5 0"
|
||||||
|
Visibility="{Binding ShowShield, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" />
|
||||||
|
<CheckBox Style="{StaticResource MaterialDesignCheckBox}"
|
||||||
|
IsChecked="{Binding IsEnabled}"
|
||||||
|
IsEnabled="{Binding CanToggleEnabled}">
|
||||||
|
Feature enabled
|
||||||
|
</CheckBox>
|
||||||
|
|
||||||
|
<materialDesign:PopupBox Style="{StaticResource MaterialDesignToolPopupBox}"
|
||||||
|
Margin="0 -4 -10 -4"
|
||||||
|
Foreground="{StaticResource MaterialDesignBody}"
|
||||||
|
IsEnabled="{Binding IsPopupEnabled}">
|
||||||
|
<StackPanel>
|
||||||
|
<Button Command="{s:Action InstallPrerequisites}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<materialDesign:PackIcon Kind="CheckAll" Margin="0 0 10 0 " VerticalAlignment="Center" />
|
||||||
|
<TextBlock VerticalAlignment="Center">Install prerequisites</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<Button Command="{s:Action RemovePrerequisites}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<materialDesign:PackIcon Kind="Delete" Margin="0 0 10 0 " VerticalAlignment="Center" />
|
||||||
|
<TextBlock VerticalAlignment="Center">Remove prerequisites</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
</StackPanel>
|
||||||
|
</materialDesign:PopupBox>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Grid.Column="2" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="7"
|
||||||
|
Visibility="{Binding Enabling, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay, FallbackValue=Collapsed}">
|
||||||
|
<ProgressBar Style="{StaticResource MaterialDesignCircularProgressBar}" Value="0" IsIndeterminate="True" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
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"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Artemis.UI.Avalonia.Screens.Settings.Tabs.Plugins.Views.PluginSettingsView">
|
||||||
|
Welcome to Avalonia!
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Avalonia.Screens.Settings.Tabs.Plugins.Views
|
||||||
|
{
|
||||||
|
public partial class PluginSettingsView : UserControl
|
||||||
|
{
|
||||||
|
public PluginSettingsView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,209 @@
|
|||||||
|
<UserControl x:Class="Artemis.UI.Screens.Settings.Tabs.Plugins.PluginSettingsView"
|
||||||
|
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:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
|
xmlns:devices="clr-namespace:Artemis.UI.Screens.Settings.Tabs.Plugins"
|
||||||
|
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
|
||||||
|
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||||
|
xmlns:behaviors="clr-namespace:Artemis.UI.Behaviors"
|
||||||
|
d:DataContext="{d:DesignInstance devices:PluginSettingsViewModel}"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.PopupBox.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
<shared:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||||
|
</ResourceDictionary>
|
||||||
|
</UserControl.Resources>
|
||||||
|
<materialDesign:Card Width="900">
|
||||||
|
<Grid Margin="8">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="4*" />
|
||||||
|
<ColumnDefinition Width="5*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Grid Grid.Row="0" Margin="0 10">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="80" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<shared:ArtemisIcon Icon="{Binding Plugin.Info.ResolvedIcon}"
|
||||||
|
Width="48"
|
||||||
|
Height="48"
|
||||||
|
Margin="0 5 0 0"
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.RowSpan="3"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Top" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="1" Grid.Row="0" Style="{StaticResource MaterialDesignBody2TextBlock}"
|
||||||
|
behaviors:HighlightTermBehavior.TermToBeHighlighted="{Binding Parent.SearchPluginInput}"
|
||||||
|
behaviors:HighlightTermBehavior.Text="{Binding Plugin.Info.Name}"
|
||||||
|
behaviors:HighlightTermBehavior.HighlightForeground="{StaticResource Primary600Foreground}"
|
||||||
|
behaviors:HighlightTermBehavior.HighlightBackground="{StaticResource Primary600}" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="1"
|
||||||
|
Grid.Row="1"
|
||||||
|
Style="{StaticResource MaterialDesignBody2TextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}"
|
||||||
|
Text="{Binding Plugin.Info.Author}"
|
||||||
|
Visibility="{Binding Plugin.Info.Author, Converter={StaticResource NullToVisibilityConverter}, Mode=OneWay}" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="1"
|
||||||
|
Grid.Row="2"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
behaviors:HighlightTermBehavior.TermToBeHighlighted="{Binding Parent.SearchPluginInput}"
|
||||||
|
behaviors:HighlightTermBehavior.Text="{Binding Plugin.Info.Description}"
|
||||||
|
behaviors:HighlightTermBehavior.HighlightForeground="{StaticResource Primary600Foreground}"
|
||||||
|
behaviors:HighlightTermBehavior.HighlightBackground="{StaticResource Primary600}"
|
||||||
|
Style="{StaticResource MaterialDesignTextBlock}"
|
||||||
|
Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid Grid.Row="1" Grid.Column="0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<StackPanel VerticalAlignment="Bottom" Orientation="Horizontal">
|
||||||
|
<Button VerticalAlignment="Bottom"
|
||||||
|
Style="{StaticResource MaterialDesignRaisedButton}"
|
||||||
|
ToolTip="Open the plugins settings window"
|
||||||
|
Margin="4"
|
||||||
|
Command="{s:Action OpenSettings}">
|
||||||
|
SETTINGS
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<materialDesign:PopupBox Style="{StaticResource MaterialDesignToolPopupBox}"
|
||||||
|
Padding="2 0 2 0"
|
||||||
|
Foreground="{StaticResource MaterialDesignBody}"
|
||||||
|
IsPopupOpen="{Binding IsSettingsPopupOpen, Mode=TwoWay}">
|
||||||
|
<StackPanel>
|
||||||
|
<Button Command="{s:Action OpenPluginDirectory}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<materialDesign:PackIcon Kind="FolderOpen" Margin="0 0 10 0 " VerticalAlignment="Center" />
|
||||||
|
<TextBlock VerticalAlignment="Center">Open plugin directory</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<Button Command="{s:Action Reload}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<materialDesign:PackIcon Kind="Reload" Margin="0 0 10 0 " VerticalAlignment="Center" />
|
||||||
|
<TextBlock VerticalAlignment="Center">Reload plugin</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<Separator />
|
||||||
|
<Button Command="{s:Action InstallPrerequisites}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<materialDesign:PackIcon Kind="CheckAll" Margin="0 0 10 0 " VerticalAlignment="Center" />
|
||||||
|
<TextBlock VerticalAlignment="Center">Install prerequisites</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<Button Command="{s:Action RemovePrerequisites}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<materialDesign:PackIcon Kind="Delete" Margin="0 0 10 0 " VerticalAlignment="Center" />
|
||||||
|
<TextBlock VerticalAlignment="Center">Remove prerequisites</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<Separator />
|
||||||
|
<Button Command="{s:Action RemoveSettings}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<materialDesign:PackIcon Kind="DatabaseRemove" Margin="0 0 10 0 " VerticalAlignment="Center" />
|
||||||
|
<TextBlock VerticalAlignment="Center">Clear plugin settings</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<Button Command="{s:Action Remove}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<materialDesign:PackIcon Kind="DeleteForever" Margin="0 0 10 0 " VerticalAlignment="Center" />
|
||||||
|
<TextBlock VerticalAlignment="Center">Remove plugin</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
</StackPanel>
|
||||||
|
</materialDesign:PopupBox>
|
||||||
|
|
||||||
|
<Button Height="40"
|
||||||
|
Width="40"
|
||||||
|
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||||
|
ToolTip="{Binding Plugin.Info.Website}"
|
||||||
|
Visibility="{Binding Plugin.Info.Website, Converter={StaticResource NullToVisibilityConverter}, Mode=OneWay}"
|
||||||
|
Command="{s:Action OpenUri}"
|
||||||
|
CommandParameter="{Binding Plugin.Info.Website}">
|
||||||
|
<materialDesign:PackIcon Kind="Web" Width="20" Height="20" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button Height="40"
|
||||||
|
Width="40"
|
||||||
|
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||||
|
ToolTip="{Binding Plugin.Info.Repository}"
|
||||||
|
Visibility="{Binding Plugin.Info.Repository, Converter={StaticResource NullToVisibilityConverter}, Mode=OneWay}"
|
||||||
|
Command="{s:Action OpenUri}"
|
||||||
|
CommandParameter="{Binding Plugin.Info.Repository}">
|
||||||
|
<materialDesign:PackIcon Kind="Git" Width="20" Height="20" />
|
||||||
|
</Button>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<CheckBox Grid.Row="0"
|
||||||
|
Grid.Column="1"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Bottom"
|
||||||
|
Margin="8"
|
||||||
|
Visibility="{Binding Enabling, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}"
|
||||||
|
Style="{StaticResource MaterialDesignAccentCheckBox}" IsChecked="{Binding IsEnabled}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock>Plugin enabled</TextBlock>
|
||||||
|
<materialDesign:PackIcon Kind="ShieldHalfFull"
|
||||||
|
Margin="5 0 0 0"
|
||||||
|
ToolTip="Plugin requires admin rights"
|
||||||
|
Visibility="{Binding Plugin.Info.RequiresAdmin, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" />
|
||||||
|
</StackPanel>
|
||||||
|
</CheckBox>
|
||||||
|
|
||||||
|
<ProgressBar Grid.Row="0"
|
||||||
|
Grid.Column="1"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Bottom"
|
||||||
|
Margin="8"
|
||||||
|
Visibility="{Binding Enabling, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}"
|
||||||
|
Style="{StaticResource MaterialDesignCircularProgressBar}" Value="0"
|
||||||
|
IsIndeterminate="True" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Border Grid.Column="1" Grid.Row="0" Grid.RowSpan="2" BorderBrush="{StaticResource MaterialDesignDivider}" BorderThickness="1 0 0 0" Margin="10 0 0 0" Padding="10 0 0 0">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<TextBlock Margin="10 10 0 5" Style="{StaticResource MaterialDesignBody2TextBlock}">Plugin features</TextBlock>
|
||||||
|
<ListBox Grid.Row="1"
|
||||||
|
MaxHeight="135"
|
||||||
|
ItemsSource="{Binding Items}"
|
||||||
|
HorizontalContentAlignment="Stretch"
|
||||||
|
VirtualizingPanel.ScrollUnit="Pixel">
|
||||||
|
<b:Interaction.Behaviors>
|
||||||
|
<shared:ScrollParentWhenAtMax />
|
||||||
|
</b:Interaction.Behaviors>
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<ContentControl s:View.Model="{Binding IsAsync=True}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" />
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
</materialDesign:Card>
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
<Window xmlns="https://github.com/avaloniaui"
|
||||||
|
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"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Artemis.UI.Avalonia.Screens.Settings.Tabs.Plugins.Views.PluginSettingsWindowView"
|
||||||
|
Title="PluginSettingsWindowView">
|
||||||
|
Welcome to Avalonia!
|
||||||
|
</Window>
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Avalonia.Screens.Settings.Tabs.Plugins.Views
|
||||||
|
{
|
||||||
|
public partial class PluginSettingsWindowView : Window
|
||||||
|
{
|
||||||
|
public PluginSettingsWindowView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
#if DEBUG
|
||||||
|
this.AttachDevTools();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
<controls:MaterialWindow x:Class="Artemis.UI.Screens.Settings.Tabs.Plugins.PluginSettingsWindowView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
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:local="clr-namespace:Artemis.UI.Screens.Settings.Tabs.Plugins"
|
||||||
|
xmlns:controls="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
|
||||||
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
|
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Title="Plugin Configuration | Artemis"
|
||||||
|
Background="{DynamicResource MaterialDesignPaper}"
|
||||||
|
FontFamily="pack://application:,,,/MaterialDesignThemes.Wpf;component/Resources/Roboto/#Roboto"
|
||||||
|
UseLayoutRounding="True"
|
||||||
|
Width="800"
|
||||||
|
Height="800"
|
||||||
|
d:DesignHeight="800"
|
||||||
|
d:DesignWidth="800"
|
||||||
|
d:DataContext="{d:DesignInstance local:PluginSettingsWindowViewModel}"
|
||||||
|
Icon="/Resources/Images/Logo/bow.ico">
|
||||||
|
<materialDesign:DialogHost IsTabStop="False"
|
||||||
|
Focusable="False"
|
||||||
|
Identifier="PluginSettingsDialog"
|
||||||
|
DialogTheme="Inherit">
|
||||||
|
<DockPanel>
|
||||||
|
<controls:AppBar Type="Dense" Title="{Binding ActiveItem.Plugin.Info.Name}" DockPanel.Dock="Top" Margin="-18 0 0 0" ShowShadow="False">
|
||||||
|
<controls:AppBar.AppIcon>
|
||||||
|
<shared:ArtemisIcon Icon="{Binding Plugin.Info.ResolvedIcon}"
|
||||||
|
Margin="0 5 0 0"
|
||||||
|
Width="20"
|
||||||
|
Height="20"
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.RowSpan="3"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Top" />
|
||||||
|
</controls:AppBar.AppIcon>
|
||||||
|
</controls:AppBar>
|
||||||
|
|
||||||
|
<ContentControl s:View.Model="{Binding ActiveItem}" />
|
||||||
|
</DockPanel>
|
||||||
|
</materialDesign:DialogHost>
|
||||||
|
</controls:MaterialWindow>
|
||||||
@ -3,6 +3,6 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Avalonia.Screens.Settings.Views.PluginsTabView">
|
x:Class="Artemis.UI.Avalonia.Screens.Settings.Tabs.Views.PluginsTabView">
|
||||||
Welcome to Avalonia!
|
Welcome to Avalonia!
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -1,8 +1,7 @@
|
|||||||
using Avalonia;
|
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
|
|
||||||
namespace Artemis.UI.Avalonia.Screens.Settings.Views
|
namespace Artemis.UI.Avalonia.Screens.Settings.Tabs.Views
|
||||||
{
|
{
|
||||||
public partial class PluginsTabView : UserControl
|
public partial class PluginsTabView : UserControl
|
||||||
{
|
{
|
||||||
@ -6,7 +6,7 @@ using Avalonia.Media.Imaging;
|
|||||||
using Flurl.Http;
|
using Flurl.Http;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Avalonia.Screens.Settings.ViewModels
|
namespace Artemis.UI.Avalonia.Screens.Settings.Tabs.ViewModels
|
||||||
{
|
{
|
||||||
public class AboutTabViewModel : ActivatableViewModelBase
|
public class AboutTabViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
namespace Artemis.UI.Avalonia.Screens.Settings.Tabs.ViewModels
|
||||||
|
{
|
||||||
|
public class DevicesTabViewModel : ActivatableViewModelBase
|
||||||
|
{
|
||||||
|
public DevicesTabViewModel()
|
||||||
|
{
|
||||||
|
DisplayName = "Devices";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,7 +14,7 @@ using Artemis.UI.Avalonia.Services.Interfaces;
|
|||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
|
|
||||||
namespace Artemis.UI.Avalonia.Screens.Settings.ViewModels
|
namespace Artemis.UI.Avalonia.Screens.Settings.Tabs.ViewModels
|
||||||
{
|
{
|
||||||
public class GeneralTabViewModel : ActivatableViewModelBase
|
public class GeneralTabViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
@ -6,7 +6,7 @@
|
|||||||
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||||
mc:Ignorable="d" d:DesignWidth="1000" d:DesignHeight="1400"
|
mc:Ignorable="d" d:DesignWidth="1000" d:DesignHeight="1400"
|
||||||
x:Class="Artemis.UI.Avalonia.Screens.Settings.Views.AboutTabView">
|
x:Class="Artemis.UI.Avalonia.Screens.Settings.Tabs.Views.AboutTabView">
|
||||||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
||||||
<StackPanel Margin="15" MaxWidth="800">
|
<StackPanel Margin="15" MaxWidth="800">
|
||||||
<Grid RowDefinitions="*,*" ColumnDefinitions="Auto,*,Auto">
|
<Grid RowDefinitions="*,*" ColumnDefinitions="Auto,*,Auto">
|
||||||
@ -1,10 +1,8 @@
|
|||||||
using Artemis.UI.Avalonia.Screens.Settings.ViewModels;
|
using Artemis.UI.Avalonia.Screens.Settings.Tabs.ViewModels;
|
||||||
using Avalonia;
|
|
||||||
using Avalonia.Controls;
|
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Avalonia.Screens.Settings.Views
|
namespace Artemis.UI.Avalonia.Screens.Settings.Tabs.Views
|
||||||
{
|
{
|
||||||
public partial class AboutTabView : ReactiveUserControl<AboutTabViewModel>
|
public partial class AboutTabView : ReactiveUserControl<AboutTabViewModel>
|
||||||
{
|
{
|
||||||
@ -3,6 +3,6 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Avalonia.Screens.Settings.Views.DevicesTabView">
|
x:Class="Artemis.UI.Avalonia.Screens.Settings.Tabs.Views.DevicesTabView">
|
||||||
Welcome to Avalonia!
|
Welcome to Avalonia!
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -1,8 +1,7 @@
|
|||||||
using Avalonia;
|
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
|
|
||||||
namespace Artemis.UI.Avalonia.Screens.Settings.Views
|
namespace Artemis.UI.Avalonia.Screens.Settings.Tabs.Views
|
||||||
{
|
{
|
||||||
public partial class DevicesTabView : UserControl
|
public partial class DevicesTabView : UserControl
|
||||||
{
|
{
|
||||||
@ -7,7 +7,7 @@
|
|||||||
xmlns:layerBrushes="clr-namespace:Artemis.Core.LayerBrushes;assembly=Artemis.Core"
|
xmlns:layerBrushes="clr-namespace:Artemis.Core.LayerBrushes;assembly=Artemis.Core"
|
||||||
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||||
mc:Ignorable="d" d:DesignWidth="1000" d:DesignHeight="2400"
|
mc:Ignorable="d" d:DesignWidth="1000" d:DesignHeight="2400"
|
||||||
x:Class="Artemis.UI.Avalonia.Screens.Settings.Views.GeneralTabView">
|
x:Class="Artemis.UI.Avalonia.Screens.Settings.Tabs.Views.GeneralTabView">
|
||||||
|
|
||||||
<StackPanel Margin="15" MaxWidth="1000">
|
<StackPanel Margin="15" MaxWidth="1000">
|
||||||
<!-- General settings -->
|
<!-- General settings -->
|
||||||
@ -1,10 +1,8 @@
|
|||||||
using Artemis.UI.Avalonia.Screens.Settings.ViewModels;
|
using Artemis.UI.Avalonia.Screens.Settings.Tabs.ViewModels;
|
||||||
using Avalonia;
|
|
||||||
using Avalonia.Controls;
|
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Avalonia.Screens.Settings.Views
|
namespace Artemis.UI.Avalonia.Screens.Settings.Tabs.Views
|
||||||
{
|
{
|
||||||
public partial class GeneralTabView : ReactiveUserControl<GeneralTabViewModel>
|
public partial class GeneralTabView : ReactiveUserControl<GeneralTabViewModel>
|
||||||
{
|
{
|
||||||
@ -1,16 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Artemis.UI.Avalonia.Screens.Settings.ViewModels
|
|
||||||
{
|
|
||||||
public class DevicesTabViewModel : ActivatableViewModelBase
|
|
||||||
{
|
|
||||||
public DevicesTabViewModel()
|
|
||||||
{
|
|
||||||
DisplayName = "Devices";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Artemis.UI.Avalonia.Screens.Settings.ViewModels
|
|
||||||
{
|
|
||||||
public class PluginsTabViewModel : ActivatableViewModelBase
|
|
||||||
{
|
|
||||||
public PluginsTabViewModel()
|
|
||||||
{
|
|
||||||
DisplayName = "Plugins";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user