Plugins - Added platform support

Settings - Fixed updating issues in plugin tab
UI - Don't initialize in design mode
UI - Move ReactiveCoreWindow to Artemis.Shared
Window service - Return window created by ShowWindow
Window service - Added CreateOpenFileDialog API
This commit is contained in:
Robert committed 2022-07-22 20:28:07 +02:00
1 parent e385165200
commit 75d85985a9
37 files changed
+600 -375

No files matched your search

+14 -14
View File
@@ -3,8 +3,8 @@
<OutputType>Library</OutputType>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ApplicationIcon/>
<StartupObject/>
<ApplicationIcon />
<StartupObject />
<OutputPath>bin\</OutputPath>
<PlatformTarget>x64</PlatformTarget>
<Platforms>x64</Platforms>
@@ -15,20 +15,20 @@
<ItemGroup>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.15"/>
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.15"/>
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.15"/>
<PackageReference Include="Avalonia.Xaml.Behaviors" Version="0.10.14"/>
<PackageReference Include="DynamicData" Version="7.8.6"/>
<PackageReference Include="FluentAvaloniaUI" Version="1.4.1"/>
<PackageReference Include="Material.Icons.Avalonia" Version="1.0.2"/>
<PackageReference Include="ReactiveUI" Version="17.1.50"/>
<PackageReference Include="ReactiveUI.Validation" Version="2.2.1"/>
<PackageReference Include="RGB.NET.Core" Version="1.0.0-prerelease.32"/>
<PackageReference Include="SkiaSharp" Version="2.88.1-preview.1"/>
<PackageReference Include="Avalonia" Version="0.10.15" />
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.15" />
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.15" />
<PackageReference Include="Avalonia.Xaml.Behaviors" Version="0.10.14" />
<PackageReference Include="DynamicData" Version="7.8.6" />
<PackageReference Include="FluentAvaloniaUI" Version="1.4.1" />
<PackageReference Include="Material.Icons.Avalonia" Version="1.0.2" />
<PackageReference Include="ReactiveUI" Version="17.1.50" />
<PackageReference Include="ReactiveUI.Validation" Version="2.2.1" />
<PackageReference Include="RGB.NET.Core" Version="1.0.0-prerelease.32" />
<PackageReference Include="SkiaSharp" Version="2.88.1-preview.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj"/>
<ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="Controls\HotkeyBox.axaml.cs">
@@ -0,0 +1,63 @@
using System;
using Avalonia;
using Avalonia.Controls;
using FluentAvalonia.UI.Controls;
using ReactiveUI;
namespace Artemis.UI.Shared
{
/// <summary>
/// A ReactiveUI <see cref="Window" /> that implements the <see cref="IViewFor{TViewModel}" /> interface and will
/// activate your ViewModel automatically if the view model implements <see cref="IActivatableViewModel" />. When
/// the DataContext property changes, this class will update the ViewModel property with the new DataContext value,
/// and vice versa.
/// </summary>
/// <typeparam name="TViewModel">ViewModel type.</typeparam>
public class ReactiveCoreWindow<TViewModel> : CoreWindow, IViewFor<TViewModel> where TViewModel : class
{
public static readonly StyledProperty<TViewModel?> ViewModelProperty = AvaloniaProperty
.Register<ReactiveCoreWindow<TViewModel>, TViewModel?>(nameof(ViewModel));
/// <summary>
/// Initializes a new instance of the <see cref="ReactiveCoreWindow{TViewModel}" /> class.
/// </summary>
public ReactiveCoreWindow()
{
// This WhenActivated block calls ViewModel's WhenActivated
// block if the ViewModel implements IActivatableViewModel.
this.WhenActivated(disposables => { });
this.GetObservable(DataContextProperty).Subscribe(OnDataContextChanged);
this.GetObservable(ViewModelProperty).Subscribe(OnViewModelChanged);
}
private void OnDataContextChanged(object? value)
{
if (value is TViewModel viewModel)
ViewModel = viewModel;
else
ViewModel = null;
}
private void OnViewModelChanged(object? value)
{
if (value == null)
ClearValue(DataContextProperty);
else if (DataContext != value) DataContext = value;
}
/// <summary>
/// The ViewModel.
/// </summary>
public TViewModel? ViewModel
{
get => GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object? IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (TViewModel?) value;
}
}
}
@@ -0,0 +1,54 @@
using System.Threading.Tasks;
using Avalonia.Controls;
namespace Artemis.UI.Shared.Services.Builders;
/// <summary>
/// Represents a builder that can create a <see cref="OpenFolderDialog" />.
/// </summary>
public class OpenFolderDialogBuilder
{
private readonly OpenFolderDialog _openFolderDialog;
private readonly Window _parent;
/// <summary>
/// Creates a new instance of the <see cref="OpenFolderDialogBuilder" /> class.
/// </summary>
/// <param name="parent">The parent window that will host the dialog.</param>
internal OpenFolderDialogBuilder(Window parent)
{
_parent = parent;
_openFolderDialog = new OpenFolderDialog();
}
/// <summary>
/// Set the title of the dialog
/// </summary>
public OpenFolderDialogBuilder WithTitle(string? title)
{
_openFolderDialog.Title = title;
return this;
}
/// <summary>
/// Set the initial directory of the dialog
/// </summary>
public OpenFolderDialogBuilder WithDirectory(string? directory)
{
_openFolderDialog.Directory = directory;
return this;
}
/// <summary>
/// Asynchronously shows the folder dialog.
/// </summary>
/// <returns>
/// A task that on completion returns an array containing the full path to the selected
/// folder, or null if the dialog was canceled.
/// </returns>
public async Task<string?> ShowAsync()
{
return await _openFolderDialog.ShowAsync(_parent);
}
}
@@ -22,7 +22,7 @@ namespace Artemis.UI.Shared.Services
/// Given a ViewModel, show its corresponding View as a window
/// </summary>
/// <param name="viewModel">ViewModel to show the View for</param>
void ShowWindow(object viewModel);
Window ShowWindow(object viewModel);
/// <summary>
/// Shows a dialog displaying the given exception
@@ -61,6 +61,12 @@ namespace Artemis.UI.Shared.Services
/// </returns>
Task<bool> ShowConfirmContentDialog(string title, string message, string confirm = "Confirm", string? cancel = "Cancel");
/// <summary>
/// Creates an open folder dialog, use the fluent API to configure it
/// </summary>
/// <returns>The builder that can be used to configure the dialog</returns>
OpenFolderDialogBuilder CreateOpenFolderDialog();
/// <summary>
/// Creates an open file dialog, use the fluent API to configure it
/// </summary>
@@ -30,7 +30,7 @@ namespace Artemis.UI.Shared.Services
return viewModel;
}
public void ShowWindow(object viewModel)
public Window ShowWindow(object viewModel)
{
Window? parent = GetCurrentWindow();
@@ -49,6 +49,8 @@ namespace Artemis.UI.Shared.Services
window.Show(parent);
else
window.Show();
return window;
}
public async Task<TResult> ShowDialogAsync<TViewModel, TResult>(params (string name, object? value)[] parameters) where TViewModel : DialogViewModelBase<TResult>
@@ -86,7 +88,6 @@ namespace Artemis.UI.Shared.Services
Window window = (Window) Activator.CreateInstance(type)!;
window.DataContext = viewModel;
viewModel.CloseRequested += (_, args) => window.Close(args.Result);
viewModel.CancelRequested += (_, _) => window.Close();
return await window.ShowDialog<TResult>(parent);
}
@@ -118,6 +119,14 @@ namespace Artemis.UI.Shared.Services
throw new ArtemisSharedUIException("Can't show a content dialog without any windows being shown.");
return new ContentDialogBuilder(_kernel, currentWindow);
}
public OpenFolderDialogBuilder CreateOpenFolderDialog()
{
Window? currentWindow = GetCurrentWindow();
if (currentWindow == null)
throw new ArtemisSharedUIException("Can't show an open folder dialog without any windows being shown.");
return new OpenFolderDialogBuilder(currentWindow);
}
public OpenFileDialogBuilder CreateOpenFileDialog()
{
@@ -19,7 +19,7 @@
<Setter Property="MaxHeight" Value="0" />
</KeyFrame>
<KeyFrame Cue="100%">
<Setter Property="MaxHeight" Value="50" />
<Setter Property="MaxHeight" Value="600" />
</KeyFrame>
</Animation>
</Style.Animations>
+1 -10
View File
@@ -51,17 +51,8 @@ public abstract class DialogViewModelBase<TResult> : ValidatableViewModelBase
{
CloseRequested?.Invoke(this, new DialogClosedEventArgs<TResult>(result));
}
/// <summary>
/// Closes the dialog without a result
/// </summary>
public void Cancel()
{
CancelRequested?.Invoke(this, EventArgs.Empty);
}
internal event EventHandler<DialogClosedEventArgs<TResult>>? CloseRequested;
internal event EventHandler? CancelRequested;
}
/// <summary>