1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Window Service - Always provide current window as parent

Plugins - Allow self-binding of unregistered services
Plugins UI - Style settings window
This commit is contained in:
Robert 2021-11-13 00:23:09 +01:00
parent 26639ca8fd
commit b963aa0909
13 changed files with 92 additions and 47 deletions

View File

@ -1,5 +1,4 @@
using System.IO; using Artemis.Core.Services;
using Artemis.Core.Services;
using Artemis.Storage; using Artemis.Storage;
using Artemis.Storage.Migrations.Interfaces; using Artemis.Storage.Migrations.Interfaces;
using Artemis.Storage.Repositories.Interfaces; using Artemis.Storage.Repositories.Interfaces;

View File

@ -16,6 +16,7 @@ using McMaster.NETCore.Plugins;
using Ninject; using Ninject;
using Ninject.Extensions.ChildKernel; using Ninject.Extensions.ChildKernel;
using Ninject.Parameters; using Ninject.Parameters;
using Ninject.Planning.Bindings.Resolvers;
using RGB.NET.Core; using RGB.NET.Core;
using Serilog; using Serilog;
@ -410,6 +411,9 @@ namespace Artemis.Core.Services
// Create the Ninject child kernel and load the module // Create the Ninject child kernel and load the module
plugin.Kernel = new ChildKernel(_kernel, new PluginModule(plugin)); plugin.Kernel = new ChildKernel(_kernel, new PluginModule(plugin));
// The kernel used by Core is unforgiving about missing bindings, no need to be so hard on plugin devs
plugin.Kernel.Components.Add<IMissingBindingResolver, SelfBindingResolver>();
OnPluginEnabling(new PluginEventArgs(plugin)); OnPluginEnabling(new PluginEventArgs(plugin));
plugin.SetEnabled(true); plugin.SetEnabled(true);

View File

@ -5,6 +5,7 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ApplicationIcon /> <ApplicationIcon />
<StartupObject /> <StartupObject />
<OutputPath>bin\</OutputPath>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DocumentationFile>C:\Repos\Artemis\src\Artemis.UI.Avalonia.Shared\Artemis.UI.Avalonia.Shared.xml</DocumentationFile> <DocumentationFile>C:\Repos\Artemis\src\Artemis.UI.Avalonia.Shared\Artemis.UI.Avalonia.Shared.xml</DocumentationFile>

View File

@ -282,9 +282,14 @@
Gets the plugin this configuration view model is associated with Gets the plugin this configuration view model is associated with
</summary> </summary>
</member> </member>
<member name="P:Artemis.UI.Avalonia.Shared.PluginConfigurationViewModel.Close"> <member name="M:Artemis.UI.Avalonia.Shared.PluginConfigurationViewModel.Close">
<summary> <summary>
A command that closes the window Closes the window hosting the view model
</summary>
</member>
<member name="E:Artemis.UI.Avalonia.Shared.PluginConfigurationViewModel.CloseRequested">
<summary>
Occurs when the the window hosting the view model should close
</summary> </summary>
</member> </member>
<member name="T:Artemis.UI.Avalonia.Shared.Services.Builders.FileDialogFilterBuilder"> <member name="T:Artemis.UI.Avalonia.Shared.Services.Builders.FileDialogFilterBuilder">

View File

@ -1,6 +1,5 @@
using System.Reactive; using System;
using Artemis.Core; using Artemis.Core;
using ReactiveUI;
namespace Artemis.UI.Avalonia.Shared namespace Artemis.UI.Avalonia.Shared
{ {
@ -16,7 +15,6 @@ namespace Artemis.UI.Avalonia.Shared
protected PluginConfigurationViewModel(Plugin plugin) protected PluginConfigurationViewModel(Plugin plugin)
{ {
Plugin = plugin; Plugin = plugin;
Close = ReactiveCommand.Create(() => { });
} }
/// <summary> /// <summary>
@ -25,8 +23,16 @@ namespace Artemis.UI.Avalonia.Shared
public Plugin Plugin { get; } public Plugin Plugin { get; }
/// <summary> /// <summary>
/// A command that closes the window /// Closes the window hosting the view model
/// </summary> /// </summary>
public ReactiveCommand<Unit, Unit> Close { get; } public void Close()
{
CloseRequested?.Invoke(this, EventArgs.Empty);
}
/// <summary>
/// Occurs when the the window hosting the view model should close
/// </summary>
public event EventHandler? CloseRequested;
} }
} }

View File

@ -33,6 +33,8 @@ namespace Artemis.UI.Avalonia.Shared.Services
public void ShowWindow(object viewModel) public void ShowWindow(object viewModel)
{ {
Window parent = GetCurrentWindow();
string name = viewModel.GetType().FullName!.Split('`')[0].Replace("ViewModel", "View"); string name = viewModel.GetType().FullName!.Split('`')[0].Replace("ViewModel", "View");
Type? type = viewModel.GetType().Assembly.GetType(name); Type? type = viewModel.GetType().Assembly.GetType(name);
@ -48,7 +50,7 @@ namespace Artemis.UI.Avalonia.Shared.Services
Window window = (Window) Activator.CreateInstance(type)!; Window window = (Window) Activator.CreateInstance(type)!;
window.DataContext = viewModel; window.DataContext = viewModel;
window.Show(); window.Show(parent);
} }
public async Task<TResult> ShowDialogAsync<TViewModel, TResult>(params (string name, object value)[] parameters) where TViewModel : DialogViewModelBase<TResult> public async Task<TResult> ShowDialogAsync<TViewModel, TResult>(params (string name, object value)[] parameters) where TViewModel : DialogViewModelBase<TResult>
@ -72,10 +74,7 @@ namespace Artemis.UI.Avalonia.Shared.Services
public async Task<TResult> ShowDialogAsync<TResult>(DialogViewModelBase<TResult> viewModel) public async Task<TResult> ShowDialogAsync<TResult>(DialogViewModelBase<TResult> viewModel)
{ {
if (Application.Current.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime classic) Window parent = GetCurrentWindow();
{
throw new ArtemisSharedUIException("Can't show a dialog when application lifetime is not IClassicDesktopStyleApplicationLifetime.");
}
string name = viewModel.GetType().FullName!.Split('`')[0].Replace("ViewModel", "View"); string name = viewModel.GetType().FullName!.Split('`')[0].Replace("ViewModel", "View");
Type? type = viewModel.GetType().Assembly.GetType(name); Type? type = viewModel.GetType().Assembly.GetType(name);
@ -92,7 +91,6 @@ namespace Artemis.UI.Avalonia.Shared.Services
Window window = (Window) Activator.CreateInstance(type)!; Window window = (Window) Activator.CreateInstance(type)!;
window.DataContext = viewModel; window.DataContext = viewModel;
Window parent = classic.Windows.FirstOrDefault(w => w.IsActive) ?? classic.MainWindow;
return await window.ShowDialog<TResult>(parent); return await window.ShowDialog<TResult>(parent);
} }

View File

@ -42,6 +42,8 @@ namespace Artemis.UI.Avalonia
private void InitializeNinject() private void InitializeNinject()
{ {
_kernel = new StandardKernel(); _kernel = new StandardKernel();
_kernel.Settings.InjectNonPublic = true;
_kernel.Load<CoreModule>(); _kernel.Load<CoreModule>();
_kernel.Load<UIModule>(); _kernel.Load<UIModule>();
_kernel.Load<SharedUIModule>(); _kernel.Load<SharedUIModule>();

View File

@ -3,6 +3,7 @@
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputPath>bin\</OutputPath>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DocumentationFile></DocumentationFile> <DocumentationFile></DocumentationFile>

View File

@ -8,10 +8,13 @@
Title="Artemis | Device Properties" Title="Artemis | Device Properties"
Width="1250" Width="1250"
Height="900" Height="900"
ExtendClientAreaToDecorationsHint="True" WindowStartupLocation="CenterOwner"
Padding="0 32 0 0"> ExtendClientAreaToDecorationsHint="True">
<Grid ColumnDefinitions="*,0,1.5*" > <Grid>
<Grid Grid.Column="0" Name="DeviceDisplayGrid" > <TextBlock Margin="10" IsHitTestVisible="False" Text="Artemis | Device Properties" />
<Grid Margin="0 32 0 0" ColumnDefinitions="*,0,1.5*">
<Grid Grid.Column="0" Name="DeviceDisplayGrid">
<Grid.Background> <Grid.Background>
<VisualBrush TileMode="Tile" Stretch="Uniform" DestinationRect="0,0,25,25"> <VisualBrush TileMode="Tile" Stretch="Uniform" DestinationRect="0,0,25,25">
<VisualBrush.Visual> <VisualBrush.Visual>
@ -32,10 +35,10 @@
ShowColors="True" ShowColors="True"
Margin="20" /> Margin="20" />
<StackPanel Orientation="Horizontal" <StackPanel Orientation="Horizontal"
VerticalAlignment="Bottom" VerticalAlignment="Bottom"
HorizontalAlignment="Left" HorizontalAlignment="Left"
Margin="15" Margin="15"
IsVisible="{Binding Device.Layout.RgbLayout.Author, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"> IsVisible="{Binding Device.Layout.RgbLayout.Author, Converter={x:Static StringConverters.IsNotNullOrEmpty}}">
<TextBlock Classes="h5" Text="Device layout by " /> <TextBlock Classes="h5" Text="Device layout by " />
<TextBlock Classes="h5" FontWeight="Bold" Text="{Binding Device.Layout.RgbLayout.Author}" /> <TextBlock Classes="h5" FontWeight="Bold" Text="{Binding Device.Layout.RgbLayout.Author}" />
@ -43,23 +46,25 @@
</Grid> </Grid>
<GridSplitter Grid.Column="1" Width="15" Margin="-15 0 0 0" Background="Transparent" HorizontalAlignment="Stretch"/> <GridSplitter Grid.Column="1" Width="15" Margin="-15 0 0 0" Background="Transparent" HorizontalAlignment="Stretch" />
<Border Grid.Column="2" Classes="card" CornerRadius="10 0 0 0"> <Border Grid.Column="2" Classes="card" CornerRadius="10 0 0 0">
<TabControl Items="{Binding Tabs}"> <TabControl Items="{Binding Tabs}">
<TabControl.ItemTemplate> <TabControl.ItemTemplate>
<DataTemplate> <DataTemplate>
<TextBlock Text="{Binding DisplayName}" /> <TextBlock Text="{Binding DisplayName}" />
</DataTemplate> </DataTemplate>
</TabControl.ItemTemplate> </TabControl.ItemTemplate>
<TabControl.ContentTemplate> <TabControl.ContentTemplate>
<DataTemplate> <DataTemplate>
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"> <ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<ContentControl Content="{Binding}" Margin="0 10 0 0"/> <ContentControl Content="{Binding}" Margin="0 10 0 0" />
</ScrollViewer> </ScrollViewer>
</DataTemplate> </DataTemplate>
</TabControl.ContentTemplate> </TabControl.ContentTemplate>
</TabControl> </TabControl>
</Border> </Border>
</Grid>
</Grid> </Grid>
</Window> </Window>

View File

@ -4,6 +4,14 @@
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.Plugins.Views.PluginSettingsWindowView" x:Class="Artemis.UI.Avalonia.Screens.Plugins.Views.PluginSettingsWindowView"
Title="{Binding DisplayName}"> Title="{Binding DisplayName}"
<ContentControl Content="{Binding ConfigurationViewModel}"></ContentControl> ExtendClientAreaToDecorationsHint="True"
Width="800"
Height="800"
WindowStartupLocation="CenterOwner">
<Grid>
<TextBlock Margin="10" IsHitTestVisible="False" Text="{Binding DisplayName}"></TextBlock>
<ContentControl Margin="0 32 0 0" Content="{Binding ConfigurationViewModel}"></ContentControl>
</Grid>
</Window> </Window>

View File

@ -1,7 +1,7 @@
using System; using System;
using System.Reactive.Disposables;
using Artemis.UI.Avalonia.Screens.Plugins.ViewModels; using Artemis.UI.Avalonia.Screens.Plugins.ViewModels;
using Avalonia; using Avalonia;
using Avalonia.Controls.Mixins;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI; using Avalonia.ReactiveUI;
using ReactiveUI; using ReactiveUI;
@ -17,7 +17,22 @@ namespace Artemis.UI.Avalonia.Screens.Plugins.Views
this.AttachDevTools(); this.AttachDevTools();
#endif #endif
this.WhenActivated(disposables => { ViewModel!.ConfigurationViewModel.Close.Subscribe(_ => Close()).DisposeWith(disposables); }); this.WhenActivated(disposables =>
{
ViewModel!.ConfigurationViewModel.CloseRequested += ConfigurationViewModelOnCloseRequested;
Disposable.Create(HandleDeactivation).DisposeWith(disposables);
}
);
}
private void HandleDeactivation()
{
ViewModel!.ConfigurationViewModel.CloseRequested -= ConfigurationViewModelOnCloseRequested;
}
private void ConfigurationViewModelOnCloseRequested(object? sender, EventArgs e)
{
Close();
} }
private void InitializeComponent() private void InitializeComponent()

View File

@ -13,7 +13,7 @@
<ContentControl Grid.Column="0" Content="{Binding SidebarViewModel}" /> <ContentControl Grid.Column="0" Content="{Binding SidebarViewModel}" />
<Border Classes="router-container" Grid.Column="1" Margin="0 10 0 0"> <Border Classes="router-container" Grid.Column="1" Margin="0 40 0 0">
<reactiveUi:RoutedViewHost Router="{Binding Router}"> <reactiveUi:RoutedViewHost Router="{Binding Router}">
<reactiveUi:RoutedViewHost.PageTransition> <reactiveUi:RoutedViewHost.PageTransition>
<CrossFade Duration="0.1" /> <CrossFade Duration="0.1" />

View File

@ -11,8 +11,9 @@ namespace Artemis.UI.Avalonia
public IControl Build(object data) public IControl Build(object data)
{ {
string name = data.GetType().FullName!.Split('`')[0].Replace("ViewModel", "View"); Type dataType = data.GetType();
Type? type = Type.GetType(name); string name = dataType.FullName!.Split('`')[0].Replace("ViewModel", "View");
Type? type = dataType.Assembly.GetType(name);
if (type != null) if (type != null)
return (Control) Activator.CreateInstance(type)!; return (Control) Activator.CreateInstance(type)!;