UI - Implemented tray icon

UI - Moved dialog service to the shared UI project
UI - Implemented autorun
This commit is contained in:
SpoinkyNL committed 2020-02-23 12:37:30 +01:00
1 parent b3f6aef101
commit 5710acb321
34 files changed
+344 -57

No files matched your search

@@ -19,9 +19,12 @@
<DebugType>pdbonly</DebugType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AvalonEdit" Version="6.0.1" />
<PackageReference Include="Humanizer.Core" Version="2.7.9" />
<PackageReference Include="MaterialDesignThemes" Version="3.0.1" />
<PackageReference Include="Ninject" Version="3.3.4" />
<PackageReference Include="SkiaSharp" Version="1.68.2-preview.29" />
<PackageReference Include="Stylet" Version="1.3.1" />
<PackageReference Include="System.Buffers" Version="4.5.0" />
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.7.0" />
@@ -0,0 +1,23 @@
<UserControl x:Class="Artemis.UI.Shared.Screens.Dialogs.ConfirmDialogView"
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:s="https://github.com/canton7/Stylet"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:dialogs="clr-namespace:Artemis.UI.Shared.Screens.Dialogs"
mc:Ignorable="d"
d:DesignHeight="163.274" d:DesignWidth="254.425"
d:DataContext="{d:DesignInstance dialogs:ConfirmDialogViewModel}">
<StackPanel Margin="16">
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" Text="{Binding Header}" TextWrapping="Wrap" />
<TextBlock Style="{StaticResource MaterialDesignBody1TextBlock}" Margin="0 20 0 20" Text="{Binding Text}" TextWrapping="Wrap" />
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Style="{StaticResource MaterialDesignFlatButton}" IsCancel="True" Margin="0 8 8 0"
Command="{s:Action Cancel}" Content="{Binding CancelText}" />
<Button Style="{StaticResource MaterialDesignFlatButton}" IsDefault="True" Margin="0 8 0 0"
Command="{s:Action Confirm}" Content="{Binding ConfirmText}" />
</StackPanel>
</StackPanel>
</UserControl>
@@ -0,0 +1,30 @@
using Artemis.UI.Shared.Services.Dialog;
namespace Artemis.UI.Shared.Screens.Dialogs
{
public class ConfirmDialogViewModel : DialogViewModelBase
{
public ConfirmDialogViewModel(string header, string text, string confirmText, string cancelText)
{
Header = header;
Text = text;
ConfirmText = confirmText;
CancelText = cancelText;
}
public string Header { get; }
public string Text { get; }
public string ConfirmText { get; }
public string CancelText { get; }
public void Confirm()
{
Session.Close(true);
}
public void Cancel()
{
Session.Close(false);
}
}
}
@@ -0,0 +1,34 @@
<UserControl x:Class="Artemis.UI.Shared.Screens.Dialogs.ExceptionDialogView"
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:s="https://github.com/canton7/Stylet"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:dialogs="clr-namespace:Artemis.UI.Shared.Screens.Dialogs"
xmlns:avalonedit="http://icsharpcode.net/sharpdevelop/avalonedit"
mc:Ignorable="d"
d:DesignHeight="163.274" d:DesignWidth="254.425"
d:DataContext="{d:DesignInstance dialogs:ExceptionDialogViewModel}">
<StackPanel Margin="16">
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" Text="{Binding Header}" TextWrapping="Wrap" />
<TextBlock Style="{StaticResource MaterialDesignBody1TextBlock}" Margin="0 20 0 20" Text="{Binding Exception.Message}" TextWrapping="Wrap" />
<Separator></Separator>
<TextBlock Style="{StaticResource MaterialDesignBody1TextBlock}" Text="Stack trace" TextWrapping="Wrap" FontWeight="Bold" Margin="20 5 0 0"/>
<avalonedit:TextEditor SyntaxHighlighting="C#"
FontFamily="Consolas"
FontSize="10pt"
IsReadOnly="True"
Document="{Binding Document}"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
Margin="0 10"/>
<Separator></Separator>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Style="{StaticResource MaterialDesignFlatButton}" IsDefault="True" Margin="0 8 0 0"
Command="{s:Action Close}" Content="Close" />
</StackPanel>
</StackPanel>
</UserControl>
@@ -0,0 +1,27 @@
using System;
using Artemis.UI.Shared.Services.Dialog;
using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.Document;
namespace Artemis.UI.Shared.Screens.Dialogs
{
public class ExceptionDialogViewModel : DialogViewModelBase
{
public ExceptionDialogViewModel(string message, Exception exception)
{
Header = message;
Exception = exception;
Document = new TextDocument(new StringTextSource(exception.StackTrace));
}
public string Header { get; }
public Exception Exception { get; }
public IDocument Document { get; set; }
public void Close()
{
Session.Close();
}
}
}
@@ -0,0 +1,111 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Artemis.UI.Shared.Screens.Dialogs;
using Artemis.UI.Shared.Services.Interfaces;
using MaterialDesignThemes.Wpf;
using Ninject;
using Ninject.Parameters;
using Stylet;
namespace Artemis.UI.Shared.Services.Dialog
{
public class DialogService : IDialogService
{
private readonly IKernel _kernel;
private readonly IViewManager _viewManager;
public DialogService(IKernel kernel, IViewManager viewManager)
{
_kernel = kernel;
_viewManager = viewManager;
}
public async Task<bool> ShowConfirmDialog(string header, string text, string confirmText = "Confirm", string cancelText = "Cancel")
{
var arguments = new IParameter[]
{
new ConstructorArgument("header", header),
new ConstructorArgument("text", text),
new ConstructorArgument("confirmText", confirmText.ToUpper()),
new ConstructorArgument("cancelText", cancelText.ToUpper())
};
var result = await ShowDialog<ConfirmDialogViewModel>(arguments);
return (bool) result;
}
public async Task<bool> ShowConfirmDialogAt(string identifier, string header, string text, string confirmText = "Confirm", string cancelText = "Cancel")
{
var arguments = new IParameter[]
{
new ConstructorArgument("header", header),
new ConstructorArgument("text", text),
new ConstructorArgument("confirmText", confirmText.ToUpper()),
new ConstructorArgument("cancelText", cancelText.ToUpper())
};
var result = await ShowDialogAt<ConfirmDialogViewModel>(identifier, arguments);
return (bool) result;
}
public async Task<object> ShowDialog<T>() where T : DialogViewModelBase
{
return await ShowDialog("RootDialog", _kernel.Get<T>());
}
public Task<object> ShowDialog<T>(Dictionary<string, object> parameters) where T : DialogViewModelBase
{
if (parameters == null)
throw new ArgumentNullException(nameof(parameters));
var paramsArray = parameters.Select(kv => new ConstructorArgument(kv.Key, kv.Value)).Cast<IParameter>().ToArray();
return ShowDialog<T>(paramsArray);
}
public async Task<object> ShowDialog<T>(IParameter[] parameters) where T : DialogViewModelBase
{
if (parameters == null) throw new ArgumentNullException(nameof(parameters));
return await ShowDialog("RootDialog", _kernel.Get<T>(parameters));
}
public async Task<object> ShowDialogAt<T>(string identifier) where T : DialogViewModelBase
{
return await ShowDialog(identifier, _kernel.Get<T>());
}
public async Task<object> ShowDialogAt<T>(string identifier, Dictionary<string, object> parameters) where T : DialogViewModelBase
{
if (parameters == null)
throw new ArgumentNullException(nameof(parameters));
var paramsArray = parameters.Select(kv => new ConstructorArgument(kv.Key, kv.Value)).Cast<IParameter>().ToArray();
return await ShowDialogAt<T>(identifier, paramsArray);
}
public async Task<object> ShowDialogAt<T>(string identifier, IParameter[] parameters) where T : DialogViewModelBase
{
if (parameters == null) throw new ArgumentNullException(nameof(parameters));
return await ShowDialog(identifier, _kernel.Get<T>(parameters));
}
public async Task ShowExceptionDialog(string message, Exception exception)
{
var arguments = new IParameter[]
{
new ConstructorArgument("message", message),
new ConstructorArgument("exception", exception)
};
await Execute.OnUIThreadAsync(async () => await ShowDialog<ExceptionDialogViewModel>(arguments));
}
private async Task<object> ShowDialog(string identifier, DialogViewModelBase viewModel)
{
var view = _viewManager.CreateViewForModel(viewModel);
_viewManager.BindViewToModel(view, viewModel);
if (identifier == null)
return await DialogHost.Show(view, viewModel.OnDialogOpened, viewModel.OnDialogClosed);
return await DialogHost.Show(view, identifier, viewModel.OnDialogOpened, viewModel.OnDialogClosed);
}
}
}
@@ -0,0 +1,28 @@
using MaterialDesignThemes.Wpf;
using Stylet;
namespace Artemis.UI.Shared.Services.Dialog
{
public abstract class DialogViewModelBase : ValidatingModelBase
{
protected DialogViewModelBase(IModelValidator validator) : base(validator)
{
}
protected DialogViewModelBase()
{
}
public DialogViewModelHost DialogViewModelHost { get; set; }
public DialogSession Session { get; private set; }
public void OnDialogOpened(object sender, DialogOpenedEventArgs e)
{
Session = e.Session;
}
public virtual void OnDialogClosed(object sender, DialogClosingEventArgs e)
{
}
}
}
@@ -0,0 +1,28 @@
using MaterialDesignThemes.Wpf;
using Stylet;
namespace Artemis.UI.Shared.Services.Dialog
{
public class DialogViewModelHost : PropertyChangedBase
{
private readonly IViewManager _viewManager;
public DialogViewModelHost(IViewManager viewManager)
{
_viewManager = viewManager;
}
public DialogViewModelBase ActiveDialogViewModel { get; set; }
public bool IsOpen { get; set; }
public void OpenDialog(DialogViewModelBase viewModel, string dialogIdentifier)
{
var view = _viewManager.CreateViewForModel(viewModel);
DialogHost.Show(view, dialogIdentifier, viewModel.OnDialogClosed);
viewModel.DialogViewModelHost = this;
ActiveDialogViewModel = viewModel;
IsOpen = true;
}
}
}
@@ -0,0 +1,7 @@
namespace Artemis.UI.Shared.Services.Interfaces
{
// ReSharper disable once InconsistentNaming
public interface IArtemisSharedUIService
{
}
}
@@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Artemis.UI.Shared.Services.Dialog;
using MaterialDesignThemes.Wpf;
using Ninject.Parameters;
namespace Artemis.UI.Shared.Services.Interfaces
{
public interface IDialogService : IArtemisSharedUIService
{
/// <summary>
/// Shows a confirm dialog on the dialog host provided in <see cref="identifier" />.
/// </summary>
/// <param name="header">The title of the dialog</param>
/// <param name="text">The body text of the dialog</param>
/// <param name="confirmText">The text of the confirm button, defaults to "Confirm"</param>
/// <param name="cancelText">The text of the cancel button, defaults to "Cancel"</param>
/// <returns>A task that resolves to true if confirmed and false if cancelled</returns>
Task<bool> ShowConfirmDialog(string header, string text, string confirmText = "Confirm", string cancelText = "Cancel");
/// <summary>
/// Shows a confirm dialog on the dialog host provided in <see cref="identifier" />.
/// </summary>
/// <param name="identifier">
/// The identifier of the <see cref="DialogHost" /> to use eg.
/// <code>&lt;materialDesign:DialogHost Identifier="MyDialogHost"&gt;</code>
/// </param>
/// <param name="header">The title of the dialog</param>
/// <param name="text">The body text of the dialog</param>
/// <param name="confirmText">The text of the confirm button, defaults to "Confirm"</param>
/// <param name="cancelText">The text of the cancel button, defaults to "Cancel"</param>
/// <returns>A task that resolves to true if confirmed and false if cancelled</returns>
Task<bool> ShowConfirmDialogAt(string identifier, string header, string text, string confirmText = "Confirm", string cancelText = "Cancel");
/// <summary>
/// Shows a dialog by initializing a view model implementing <see cref="DialogViewModelBase" />
/// </summary>
/// <typeparam name="T">The type of the view model</typeparam>
/// <returns>A task resolving to the result of the dialog's <see cref="DialogSession" /></returns>
Task<object> ShowDialog<T>() where T : DialogViewModelBase;
/// <summary>
/// Shows a dialog by initializing a view model implementing <see cref="DialogViewModelBase" /> with arguments passed
/// to the view models constructor
/// </summary>
/// <typeparam name="T">The type of the view model</typeparam>
/// <param name="parameters">A dictionary of constructor arguments to pass to the view model</param>
/// <returns>A task resolving to the result of the dialog's <see cref="DialogSession" /></returns>
Task<object> ShowDialog<T>(Dictionary<string, object> parameters) where T : DialogViewModelBase;
/// <summary>
/// Shows a dialog by initializing a view model implementing <see cref="DialogViewModelBase" /> using an array of
/// Ninject <see cref="IParameter" />, requires you to reference Ninject
/// </summary>
/// <typeparam name="T">The type of the view model</typeparam>
/// <param name="parameters">An array of Ninject <see cref="IParameter" /> to pass to the view model during activation</param>
/// <returns>A task resolving to the result of the dialog's <see cref="DialogSession" /></returns>
Task<object> ShowDialog<T>(IParameter[] parameters) where T : DialogViewModelBase;
/// <summary>
/// Shows a dialog by initializing a view model implementing <see cref="DialogViewModelBase" />
/// </summary>
/// <typeparam name="T">The type of the view model</typeparam>
/// <param name="identifier">
/// The identifier of the <see cref="DialogHost" /> to use eg.
/// <code>&lt;materialDesign:DialogHost Identifier="MyDialogHost"&gt;</code>
/// </param>
/// <returns>A task resolving to the result of the dialog's <see cref="DialogSession" /></returns>
Task<object> ShowDialogAt<T>(string identifier) where T : DialogViewModelBase;
/// <summary>
/// Shows a dialog by initializing a view model implementing <see cref="DialogViewModelBase" /> with arguments passed
/// to the view models constructor
/// </summary>
/// <typeparam name="T">The type of the view model</typeparam>
/// <param name="identifier">
/// The identifier of the <see cref="DialogHost" /> to use eg.
/// <code>&lt;materialDesign:DialogHost Identifier="MyDialogHost"&gt;</code>
/// </param>
/// <param name="parameters">A dictionary of constructor arguments to pass to the view model</param>
/// <returns>A task resolving to the result of the dialog's <see cref="DialogSession" /></returns>
Task<object> ShowDialogAt<T>(string identifier, Dictionary<string, object> parameters) where T : DialogViewModelBase;
/// <summary>
/// Shows a dialog by initializing a view model implementing <see cref="DialogViewModelBase" /> using an array of
/// Ninject <see cref="IParameter" />, requires you to reference Ninject
/// </summary>
/// <typeparam name="T">The type of the view model</typeparam>
/// <param name="identifier">
/// The identifier of the <see cref="DialogHost" /> to use eg.
/// <code>&lt;materialDesign:DialogHost Identifier="MyDialogHost"&gt;</code>
/// </param>
/// <param name="parameters">An array of Ninject <see cref="IParameter" /> to pass to the view model during activation</param>
/// <returns>A task resolving to the result of the dialog's <see cref="DialogSession" /></returns>
Task<object> ShowDialogAt<T>(string identifier, IParameter[] parameters) where T : DialogViewModelBase;
/// <summary>
/// Shows a dialog displaying the provided message and exception. Does not handle, log or throw the exception.
/// </summary>
/// <param name="message">The message to display in the dialog title</param>
/// <param name="exception">The exception to display. The exception message and stacktrace will be shown.</param>
/// <returns>A task resolving when the dialog is closed</returns>
Task ShowExceptionDialog(string message, Exception exception);
}
}