diff --git a/src/Artemis.UI.Avalonia.Shared/Artemis.UI.Avalonia.Shared.xml b/src/Artemis.UI.Avalonia.Shared/Artemis.UI.Avalonia.Shared.xml
index 9f20fca3a..dd63d4ca4 100644
--- a/src/Artemis.UI.Avalonia.Shared/Artemis.UI.Avalonia.Shared.xml
+++ b/src/Artemis.UI.Avalonia.Shared/Artemis.UI.Avalonia.Shared.xml
@@ -129,15 +129,33 @@
Gets or sets the currently displayed icon as either a or an
- pointing
- to an SVG
+ pointing to an SVG
+
+
+
+
+ Gets or sets the watermark of the hotkey box when it is empty.
+
+
+
+
+ Gets or sets a boolean indicating whether the watermark should float above the hotkey box when it is not empty.
Gets or sets the currently displayed icon as either a or an
- pointing
- to an SVG
+ pointing to an SVG
+
+
+
+
+ Gets or sets the watermark of the hotkey box when it is empty.
+
+
+
+
+ Gets or sets a boolean indicating whether the watermark should float above the hotkey box when it is not empty.
@@ -704,6 +722,16 @@
+
+
+ Represents a default data model display view.
+
+
+
+
+ Creates a new instance of the class.
+
+
Represents the default data model display view model that is used when no display viewmodel specific for the type
@@ -824,6 +852,127 @@
Occurs when the the window hosting the view model should close
+
+
+ Represents a builder that can be used to create Fluent UI dialogs.
+
+
+
+
+ Changes the title of the dialog.
+
+ The new title.
+ The builder that can be used to further build the dialog.
+
+
+
+ Changes the content of the dialog.
+
+ The new content.
+ The builder that can be used to further build the dialog.
+
+
+
+ Changes the default button of the dialog that is pressed on enter.
+
+ The default button.
+ The builder that can be used to further build the dialog.
+
+
+
+ Changes the primary button of the dialog.
+
+ An action to configure the button.
+ The builder that can be used to further build the dialog.
+
+
+
+ Changes the secondary button of the dialog.
+
+ An action to configure the button.
+ The builder that can be used to further build the dialog.
+
+
+
+ Changes the text of the close button of the dialog.
+
+ The new text.
+ The builder that can be used to further build the dialog.
+
+
+
+ Changes the view model of the content dialog, hosting it inside the dialog.
+
+ The type of the view model to host.
+ The resulting view model.
+ Optional parameters to pass to the constructor of the view model, case and order sensitive.
+ The builder that can be used to further build the dialog.
+
+
+
+ Asynchronously shows the content dialog.
+
+ A task containing the result of the content dialog.
+ Thrown when the parent window does not contain a panel at its root.
+
+
+
+ Represents a content dialog button.
+
+
+
+
+ No button.
+
+
+
+
+ The primary button.
+
+
+
+
+ The secondary button.
+
+
+
+
+ The close button.
+
+
+
+
+ Represents a builder that can be used to create buttons inside content dialogs.
+
+
+
+
+ Changes text message of the button.
+
+ The new text.
+ The notification builder that can be used to further build the button.
+
+
+
+ Changes action that is called when the button is clicked.
+
+ The action to call when the button is clicked.
+ The builder that can be used to further build the button.
+
+
+
+ Changes command that is called when the button is clicked.
+
+ The command to call when the button is clicked.
+ The builder that can be used to further build the button.
+
+
+
+ Changes parameter of the command that is called when the button is clicked.
+
+ The parameter of the command to call when the button is clicked.
+ The builder that can be used to further build the button.
+
Represents a builder that can create a .
@@ -894,7 +1043,7 @@
- Changes the action button of the dialog.
+ Changes the action button of the notification.
An action to configure the button.
The notification builder that can be used to further build the notification.
@@ -921,20 +1070,58 @@
Changes action that is called when the button is clicked.
The action to call when the button is clicked.
- The notification builder that can be used to further build the button.
+ The builder that can be used to further build the button.
Changes command that is called when the button is clicked.
The command to call when the button is clicked.
- The notification builder that can be used to further build the button.
+ The builder that can be used to further build the button.
+
+
+
+ Changes parameter of the command that is called when the button is clicked.
+
+ The parameter of the command to call when the button is clicked.
+ The builder that can be used to further build the button.
+
+
+
+ Represents a severity of a notification.
+
+
+
+
+ A severity for informational messages.
+
+
+
+
+ A severity for success messages.
+
+
+
+
+ A severity for warning messages.
+
+
+
+
+ A severity for error messages.
+
Represents a builder that can create a .
+
+
+ Creates a new instance of the class.
+
+ The parent window that will host the dialog.
+
Indicate that the user can select multiple files.
@@ -962,7 +1149,7 @@
- Shows the file dialog
+ Asynchronously shows the file dialog.
A task that on completion returns an array containing the full path to the selected
@@ -974,6 +1161,12 @@
Represents a builder that can create a .
+
+
+ Creates a new instance of the class.
+
+ The parent window that will host the notification.
+
Set the title of the dialog
@@ -1001,7 +1194,7 @@
- Shows the save file dialog.
+ Asynchronously shows the save file dialog.
A task that on completion contains the full path of the save location, or null if the
@@ -1111,29 +1304,46 @@
A function to call whenever the input was updated (submitted or not)
The most appropriate input view model for the provided
+
+
+ A service that can be used to create notifications in either the application or on the desktop.
+
+
+
+
+ Creates an in-app notification using a builder.
+
+ A builder used to configure and show the notification.
+
+
+
+ A service that can be used to show windows and dialogs.
+
+
- Creates a view model instance of type and shows its corresponding View as a window
+ Creates a view model instance of type and shows its corresponding View as a
+ window
The type of view model to createThe created view model
- Given a ViewModel, show its corresponding View as a window
+ Given a ViewModel, show its corresponding View as a window
ViewModel to show the View for
- Shows a dialog displaying the given exception
+ Shows a dialog displaying the given exception
The title of the dialog
The exception to display
- Given an existing ViewModel, show its corresponding View as a Dialog
+ Given an existing ViewModel, show its corresponding View as a Dialog
The return type
ViewModel to show the View for
@@ -1141,7 +1351,8 @@
- Creates a view model instance of type and shows its corresponding View as a Dialog
+ Creates a view model instance of type and shows its corresponding View as a
+ Dialog
The view model typeThe return type
@@ -1149,35 +1360,38 @@
- Shows a content dialog asking the user to confirm an action
+ Shows a content dialog asking the user to confirm an action
The title of the dialog
The message of the dialog
The text of the confirm button
- The text of the cancel button, if the cancel button will not be shown
- A task containing the result of the dialog, if confirmed; otherwise
+ The text of the cancel button, if the cancel button will not be shown
+
+ A task containing the result of the dialog, if confirmed; otherwise
+
+
- Creates an open file dialog, use the fluent API to configure it
+ Creates an open file dialog, use the fluent API to configure it
The builder that can be used to configure the dialog
- Creates a save file dialog, use the fluent API to configure it
+ Creates a save file dialog, use the fluent API to configure it
The builder that can be used to configure the dialog
- Creates a content dialog, use the fluent API to configure it
+ Creates a content dialog, use the fluent API to configure it
The builder that can be used to configure the dialog
- Gets the current window of the application
+ Gets the current window of the application
The current window of the application
@@ -1212,6 +1426,11 @@
Occurs when the main window has been closed
+
+
+ A service that can be used to manage the state of the main window.
+
+
Gets a boolean indicating whether the main window is currently open
diff --git a/src/Avalonia/Artemis.UI.Shared/Controls/HotkeyBox.axaml.cs b/src/Avalonia/Artemis.UI.Shared/Controls/HotkeyBox.axaml.cs
index 1b1983b75..af95c86e1 100644
--- a/src/Avalonia/Artemis.UI.Shared/Controls/HotkeyBox.axaml.cs
+++ b/src/Avalonia/Artemis.UI.Shared/Controls/HotkeyBox.axaml.cs
@@ -88,22 +88,26 @@ namespace Artemis.UI.Shared.Controls
///
/// Gets or sets the currently displayed icon as either a or an
- /// pointing
- /// to an SVG
+ /// pointing to an SVG
///
public static readonly StyledProperty HotkeyProperty =
AvaloniaProperty.Register(nameof(Hotkey), defaultBindingMode: BindingMode.TwoWay, notifying: HotkeyChanging);
+ ///
+ /// Gets or sets the watermark of the hotkey box when it is empty.
+ ///
public static readonly StyledProperty WatermarkProperty =
AvaloniaProperty.Register(nameof(Watermark));
+ ///
+ /// Gets or sets a boolean indicating whether the watermark should float above the hotkey box when it is not empty.
+ ///
public static readonly StyledProperty UseFloatingWatermarkProperty =
AvaloniaProperty.Register(nameof(UseFloatingWatermark));
///
/// Gets or sets the currently displayed icon as either a or an
- /// pointing
- /// to an SVG
+ /// pointing to an SVG
///
public Hotkey? Hotkey
{
@@ -111,12 +115,18 @@ namespace Artemis.UI.Shared.Controls
set => SetValue(HotkeyProperty, value);
}
+ ///
+ /// Gets or sets the watermark of the hotkey box when it is empty.
+ ///
public string? Watermark
{
get => GetValue(WatermarkProperty);
set => SetValue(WatermarkProperty, value);
}
+ ///
+ /// Gets or sets a boolean indicating whether the watermark should float above the hotkey box when it is not empty.
+ ///
public bool UseFloatingWatermark
{
get => GetValue(UseFloatingWatermarkProperty);
diff --git a/src/Avalonia/Artemis.UI.Shared/Converters/ColorToSKColorConverter.cs b/src/Avalonia/Artemis.UI.Shared/Converters/ColorToSKColorConverter.cs
index bbd323daa..b09052e65 100644
--- a/src/Avalonia/Artemis.UI.Shared/Converters/ColorToSKColorConverter.cs
+++ b/src/Avalonia/Artemis.UI.Shared/Converters/ColorToSKColorConverter.cs
@@ -13,7 +13,7 @@ namespace Artemis.UI.Shared.Converters
public class ColorToSKColorConverter : IValueConverter
{
///
- public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is Color avaloniaColor)
return new SKColor(avaloniaColor.R, avaloniaColor.G, avaloniaColor.B, avaloniaColor.A);
@@ -24,7 +24,7 @@ namespace Artemis.UI.Shared.Converters
}
///
- public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
Color result = new(0, 0, 0, 0);
if (value is SKColor skColor)
diff --git a/src/Avalonia/Artemis.UI.Shared/Converters/EnumToBooleanConverter.cs b/src/Avalonia/Artemis.UI.Shared/Converters/EnumToBooleanConverter.cs
index 3c7b00239..eb0c950d5 100644
--- a/src/Avalonia/Artemis.UI.Shared/Converters/EnumToBooleanConverter.cs
+++ b/src/Avalonia/Artemis.UI.Shared/Converters/EnumToBooleanConverter.cs
@@ -11,13 +11,13 @@ namespace Artemis.UI.Shared.Converters
public class EnumToBooleanConverter : IValueConverter
{
///
- public object Convert(object? value, Type targetType, object parameter, CultureInfo culture)
+ public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return Equals(value, parameter);
}
///
- public object ConvertBack(object? value, Type targetType, object parameter, CultureInfo culture)
+ public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return value?.Equals(true) == true ? parameter : BindingOperations.DoNothing;
}
diff --git a/src/Avalonia/Artemis.UI.Shared/Converters/SKColorToColorConverter.cs b/src/Avalonia/Artemis.UI.Shared/Converters/SKColorToColorConverter.cs
index ae1143a9e..5f0c7c454 100644
--- a/src/Avalonia/Artemis.UI.Shared/Converters/SKColorToColorConverter.cs
+++ b/src/Avalonia/Artemis.UI.Shared/Converters/SKColorToColorConverter.cs
@@ -13,7 +13,7 @@ namespace Artemis.UI.Shared.Converters
public class SKColorToColorConverter : IValueConverter
{
///
- public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
Color result = new(0, 0, 0, 0);
if (value is SKColor skColor)
@@ -25,7 +25,7 @@ namespace Artemis.UI.Shared.Converters
}
///
- public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is Color avaloniaColor)
return new SKColor(avaloniaColor.R, avaloniaColor.G, avaloniaColor.B, avaloniaColor.A);
diff --git a/src/Avalonia/Artemis.UI.Shared/Converters/TypeToStringConverter.cs b/src/Avalonia/Artemis.UI.Shared/Converters/TypeToStringConverter.cs
index 6dd6149eb..8bec6ce70 100644
--- a/src/Avalonia/Artemis.UI.Shared/Converters/TypeToStringConverter.cs
+++ b/src/Avalonia/Artemis.UI.Shared/Converters/TypeToStringConverter.cs
@@ -21,7 +21,7 @@ namespace Artemis.UI.Shared.Converters
}
///
- public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
diff --git a/src/Avalonia/Artemis.UI.Shared/DefaultTypes/DataModel/Display/DefaultDataModelDisplayView.axaml.cs b/src/Avalonia/Artemis.UI.Shared/DefaultTypes/DataModel/Display/DefaultDataModelDisplayView.axaml.cs
index e00449f1c..b956fe264 100644
--- a/src/Avalonia/Artemis.UI.Shared/DefaultTypes/DataModel/Display/DefaultDataModelDisplayView.axaml.cs
+++ b/src/Avalonia/Artemis.UI.Shared/DefaultTypes/DataModel/Display/DefaultDataModelDisplayView.axaml.cs
@@ -1,11 +1,16 @@
-using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Artemis.UI.Shared.DefaultTypes.DataModel.Display
{
- public partial class DefaultDataModelDisplayView : UserControl
+ ///
+ /// Represents a default data model display view.
+ ///
+ public class DefaultDataModelDisplayView : UserControl
{
+ ///
+ /// Creates a new instance of the class.
+ ///
public DefaultDataModelDisplayView()
{
InitializeComponent();
@@ -16,4 +21,4 @@ namespace Artemis.UI.Shared.DefaultTypes.DataModel.Display
AvaloniaXamlLoader.Load(this);
}
}
-}
+}
\ No newline at end of file
diff --git a/src/Avalonia/Artemis.UI.Shared/DefaultTypes/DataModel/Display/DefaultDataModelDisplayViewModel.cs b/src/Avalonia/Artemis.UI.Shared/DefaultTypes/DataModel/Display/DefaultDataModelDisplayViewModel.cs
index 86d1f9fdf..80578c565 100644
--- a/src/Avalonia/Artemis.UI.Shared/DefaultTypes/DataModel/Display/DefaultDataModelDisplayViewModel.cs
+++ b/src/Avalonia/Artemis.UI.Shared/DefaultTypes/DataModel/Display/DefaultDataModelDisplayViewModel.cs
@@ -22,6 +22,7 @@ namespace Artemis.UI.Shared.DefaultTypes.DataModel.Display
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
PreserveReferencesHandling = PreserveReferencesHandling.None
};
+ _display = "null";
}
public string Display
diff --git a/src/Avalonia/Artemis.UI.Shared/Services/Builders/ContentDialogBuilder.cs b/src/Avalonia/Artemis.UI.Shared/Services/Builders/ContentDialogBuilder.cs
index b6c65f276..b0a5c49d1 100644
--- a/src/Avalonia/Artemis.UI.Shared/Services/Builders/ContentDialogBuilder.cs
+++ b/src/Avalonia/Artemis.UI.Shared/Services/Builders/ContentDialogBuilder.cs
@@ -10,6 +10,9 @@ using ReactiveUI;
namespace Artemis.UI.Shared.Services.Builders
{
+ ///
+ /// Represents a builder that can be used to create Fluent UI dialogs.
+ ///
public class ContentDialogBuilder
{
private readonly ContentDialog _contentDialog;
@@ -27,24 +30,44 @@ namespace Artemis.UI.Shared.Services.Builders
};
}
+ ///
+ /// Changes the title of the dialog.
+ ///
+ /// The new title.
+ /// The builder that can be used to further build the dialog.
public ContentDialogBuilder WithTitle(string? title)
{
_contentDialog.Title = title;
return this;
}
+ ///
+ /// Changes the content of the dialog.
+ ///
+ /// The new content.
+ /// The builder that can be used to further build the dialog.
public ContentDialogBuilder WithContent(string? content)
{
_contentDialog.Content = content;
return this;
}
+ ///
+ /// Changes the default button of the dialog that is pressed on enter.
+ ///
+ /// The default button.
+ /// The builder that can be used to further build the dialog.
public ContentDialogBuilder WithDefaultButton(ContentDialogButton defaultButton)
{
- _contentDialog.DefaultButton = defaultButton;
+ _contentDialog.DefaultButton = (FluentAvalonia.UI.Controls.ContentDialogButton) defaultButton;
return this;
}
+ ///
+ /// Changes the primary button of the dialog.
+ ///
+ /// An action to configure the button.
+ /// The builder that can be used to further build the dialog.
public ContentDialogBuilder HavingPrimaryButton(Action configure)
{
ContentDialogButtonBuilder builder = new();
@@ -65,6 +88,11 @@ namespace Artemis.UI.Shared.Services.Builders
return this;
}
+ ///
+ /// Changes the secondary button of the dialog.
+ ///
+ /// An action to configure the button.
+ /// The builder that can be used to further build the dialog.
public ContentDialogBuilder HavingSecondaryButton(Action configure)
{
ContentDialogButtonBuilder builder = new();
@@ -85,12 +113,24 @@ namespace Artemis.UI.Shared.Services.Builders
return this;
}
+ ///
+ /// Changes the text of the close button of the dialog.
+ ///
+ /// The new text.
+ /// The builder that can be used to further build the dialog.
public ContentDialogBuilder WithCloseButtonText(string? text)
{
_contentDialog.CloseButtonText = text;
return this;
}
+ ///
+ /// Changes the view model of the content dialog, hosting it inside the dialog.
+ ///
+ /// The type of the view model to host.
+ /// The resulting view model.
+ /// Optional parameters to pass to the constructor of the view model, case and order sensitive.
+ /// The builder that can be used to further build the dialog.
public ContentDialogBuilder WithViewModel(out T viewModel, params (string name, object? value)[] parameters) where T : ContentDialogViewModelBase
{
IParameter[] paramsArray = parameters.Select(kv => new ConstructorArgument(kv.name, kv.value)).Cast().ToArray();
@@ -102,6 +142,11 @@ namespace Artemis.UI.Shared.Services.Builders
return this;
}
+ ///
+ /// Asynchronously shows the content dialog.
+ ///
+ /// A task containing the result of the content dialog.
+ /// Thrown when the parent window does not contain a panel at its root.
public async Task ShowAsync()
{
if (_parent.Content is not Panel panel)
@@ -111,9 +156,9 @@ namespace Artemis.UI.Shared.Services.Builders
{
panel.Children.Add(_contentDialog);
ContentDialogResult result = await _contentDialog.ShowAsync();
-
+
// Take the dialog away from the VM in case it's going to try to hide it again or whatever...
- if (_viewModel != null)
+ if (_viewModel != null)
_viewModel.ContentDialog = null;
return result;
@@ -125,6 +170,35 @@ namespace Artemis.UI.Shared.Services.Builders
}
}
+ ///
+ /// Represents a content dialog button.
+ ///
+ public enum ContentDialogButton
+ {
+ ///
+ /// No button.
+ ///
+ None,
+
+ ///
+ /// The primary button.
+ ///
+ Primary,
+
+ ///
+ /// The secondary button.
+ ///
+ Secondary,
+
+ ///
+ /// The close button.
+ ///
+ Close,
+ }
+
+ ///
+ /// Represents a builder that can be used to create buttons inside content dialogs.
+ ///
public class ContentDialogButtonBuilder
{
internal ContentDialogButtonBuilder()
@@ -133,20 +207,48 @@ namespace Artemis.UI.Shared.Services.Builders
internal string? Text { get; set; }
internal ICommand? Command { get; set; }
+ internal Action? Action { get; set; }
internal object? CommandParameter { get; set; }
+ ///
+ /// Changes text message of the button.
+ ///
+ /// The new text.
+ /// The notification builder that can be used to further build the button.
public ContentDialogButtonBuilder WithText(string? text)
{
Text = text;
return this;
}
+ ///
+ /// Changes action that is called when the button is clicked.
+ ///
+ /// The action to call when the button is clicked.
+ /// The builder that can be used to further build the button.
+ public ContentDialogButtonBuilder WithAction(Action action)
+ {
+ Action = action;
+ Command = ReactiveCommand.Create(() => Action());
+ return this;
+ }
+
+ ///
+ /// Changes command that is called when the button is clicked.
+ ///
+ /// The command to call when the button is clicked.
+ /// The builder that can be used to further build the button.
public ContentDialogButtonBuilder WithCommand(ICommand? command)
{
Command = command;
return this;
}
+ ///
+ /// Changes parameter of the command that is called when the button is clicked.
+ ///
+ /// The parameter of the command to call when the button is clicked.
+ /// The builder that can be used to further build the button.
public ContentDialogButtonBuilder WithCommandParameter(object? commandParameter)
{
CommandParameter = commandParameter;
diff --git a/src/Avalonia/Artemis.UI.Shared/Services/Builders/NotificationBuilder.cs b/src/Avalonia/Artemis.UI.Shared/Services/Builders/NotificationBuilder.cs
index 57167bb6b..dab6ab14e 100644
--- a/src/Avalonia/Artemis.UI.Shared/Services/Builders/NotificationBuilder.cs
+++ b/src/Avalonia/Artemis.UI.Shared/Services/Builders/NotificationBuilder.cs
@@ -101,7 +101,7 @@ namespace Artemis.UI.Shared.Services.Builders
}
///
- /// Changes the action button of the dialog.
+ /// Changes the action button of the notification.
///
/// An action to configure the button.
/// The notification builder that can be used to further build the notification.
@@ -154,6 +154,7 @@ namespace Artemis.UI.Shared.Services.Builders
private Action? _action;
private ICommand? _command;
private string _text = "Text";
+ private object? _commandParameter;
///
/// Changes text message of the button.
@@ -170,7 +171,7 @@ namespace Artemis.UI.Shared.Services.Builders
/// Changes action that is called when the button is clicked.
///
/// The action to call when the button is clicked.
- /// The notification builder that can be used to further build the button.
+ /// The builder that can be used to further build the button.
public NotificationButtonBuilder WithAction(Action action)
{
_command = null;
@@ -182,7 +183,7 @@ namespace Artemis.UI.Shared.Services.Builders
/// Changes command that is called when the button is clicked.
///
/// The command to call when the button is clicked.
- /// The notification builder that can be used to further build the button.
+ /// The builder that can be used to further build the button.
public NotificationButtonBuilder WithCommand(ICommand command)
{
_action = null;
@@ -190,21 +191,50 @@ namespace Artemis.UI.Shared.Services.Builders
return this;
}
+ ///
+ /// Changes parameter of the command that is called when the button is clicked.
+ ///
+ /// The parameter of the command to call when the button is clicked.
+ /// The builder that can be used to further build the button.
+ public NotificationButtonBuilder WithCommandParameter(object? commandParameter)
+ {
+ _commandParameter = commandParameter;
+ return this;
+ }
+
internal IControl Build()
{
if (_action != null)
return new Button {Content = _text, Command = ReactiveCommand.Create(() => _action())};
if (_command != null)
- return new Button {Content = _text, Command = _command};
+ return new Button {Content = _text, Command = _command, CommandParameter = _commandParameter};
return new Button {Content = _text};
}
}
+ ///
+ /// Represents a severity of a notification.
+ ///
public enum NotificationSeverity
{
+ ///
+ /// A severity for informational messages.
+ ///
Informational,
+
+ ///
+ /// A severity for success messages.
+ ///
Success,
+
+ ///
+ /// A severity for warning messages.
+ ///
Warning,
+
+ ///
+ /// A severity for error messages.
+ ///
Error
}
}
\ No newline at end of file
diff --git a/src/Avalonia/Artemis.UI.Shared/Services/Builders/OpenFileDialogBuilder.cs b/src/Avalonia/Artemis.UI.Shared/Services/Builders/OpenFileDialogBuilder.cs
index af6d98ae3..a89fdedb8 100644
--- a/src/Avalonia/Artemis.UI.Shared/Services/Builders/OpenFileDialogBuilder.cs
+++ b/src/Avalonia/Artemis.UI.Shared/Services/Builders/OpenFileDialogBuilder.cs
@@ -12,6 +12,10 @@ namespace Artemis.UI.Shared.Services.Builders
private readonly OpenFileDialog _openFileDialog;
private readonly Window _parent;
+ ///
+ /// Creates a new instance of the class.
+ ///
+ /// The parent window that will host the dialog.
public OpenFileDialogBuilder(Window parent)
{
_parent = parent;
@@ -67,7 +71,7 @@ namespace Artemis.UI.Shared.Services.Builders
}
///
- /// Shows the file dialog
+ /// Asynchronously shows the file dialog.
///
///
/// A task that on completion returns an array containing the full path to the selected
diff --git a/src/Avalonia/Artemis.UI.Shared/Services/Builders/SaveFileDialogBuilder.cs b/src/Avalonia/Artemis.UI.Shared/Services/Builders/SaveFileDialogBuilder.cs
index e9bc452c1..71d48c440 100644
--- a/src/Avalonia/Artemis.UI.Shared/Services/Builders/SaveFileDialogBuilder.cs
+++ b/src/Avalonia/Artemis.UI.Shared/Services/Builders/SaveFileDialogBuilder.cs
@@ -12,6 +12,10 @@ namespace Artemis.UI.Shared.Services.Builders
private readonly Window _parent;
private readonly SaveFileDialog _saveFileDialog;
+ ///
+ /// Creates a new instance of the class.
+ ///
+ /// The parent window that will host the notification.
public SaveFileDialogBuilder(Window parent)
{
_parent = parent;
@@ -67,7 +71,7 @@ namespace Artemis.UI.Shared.Services.Builders
}
///
- /// Shows the save file dialog.
+ /// Asynchronously shows the save file dialog.
///
///
/// A task that on completion contains the full path of the save location, or null if the
diff --git a/src/Avalonia/Artemis.UI.Shared/Services/Interfaces/INotificationService.cs b/src/Avalonia/Artemis.UI.Shared/Services/Interfaces/INotificationService.cs
index 580e1d99d..3ad5418dd 100644
--- a/src/Avalonia/Artemis.UI.Shared/Services/Interfaces/INotificationService.cs
+++ b/src/Avalonia/Artemis.UI.Shared/Services/Interfaces/INotificationService.cs
@@ -2,8 +2,15 @@
namespace Artemis.UI.Shared.Services.Interfaces
{
+ ///
+ /// A service that can be used to create notifications in either the application or on the desktop.
+ ///
public interface INotificationService : IArtemisSharedUIService
{
+ ///
+ /// Creates an in-app notification using a builder.
+ ///
+ /// A builder used to configure and show the notification.
NotificationBuilder CreateNotification();
}
}
\ No newline at end of file
diff --git a/src/Avalonia/Artemis.UI.Shared/Services/Interfaces/IWindowService.cs b/src/Avalonia/Artemis.UI.Shared/Services/Interfaces/IWindowService.cs
index 9dcf4ce8a..97af484ee 100644
--- a/src/Avalonia/Artemis.UI.Shared/Services/Interfaces/IWindowService.cs
+++ b/src/Avalonia/Artemis.UI.Shared/Services/Interfaces/IWindowService.cs
@@ -5,30 +5,34 @@ using Avalonia.Controls;
namespace Artemis.UI.Shared.Services.Interfaces
{
+ ///
+ /// A service that can be used to show windows and dialogs.
+ ///
public interface IWindowService : IArtemisSharedUIService
{
///
- /// Creates a view model instance of type and shows its corresponding View as a window
+ /// Creates a view model instance of type and shows its corresponding View as a
+ /// window
///
/// The type of view model to create
/// The created view model
TViewModel ShowWindow(params (string name, object value)[] parameters);
///
- /// Given a ViewModel, show its corresponding View as a window
+ /// Given a ViewModel, show its corresponding View as a window
///
/// ViewModel to show the View for
void ShowWindow(object viewModel);
///
- /// Shows a dialog displaying the given exception
+ /// Shows a dialog displaying the given exception
///
/// The title of the dialog
/// The exception to display
void ShowExceptionDialog(string title, Exception exception);
///
- /// Given an existing ViewModel, show its corresponding View as a Dialog
+ /// Given an existing ViewModel, show its corresponding View as a Dialog
///
/// The return type
/// ViewModel to show the View for
@@ -36,7 +40,8 @@ namespace Artemis.UI.Shared.Services.Interfaces
Task ShowDialogAsync(DialogViewModelBase viewModel);
///
- /// Creates a view model instance of type and shows its corresponding View as a Dialog
+ /// Creates a view model instance of type and shows its corresponding View as a
+ /// Dialog
///
/// The view model type
/// The return type
@@ -44,37 +49,40 @@ namespace Artemis.UI.Shared.Services.Interfaces
Task ShowDialogAsync(params (string name, object? value)[] parameters) where TViewModel : DialogViewModelBase;
///
- /// Shows a content dialog asking the user to confirm an action
+ /// Shows a content dialog asking the user to confirm an action
///
/// The title of the dialog
/// The message of the dialog
/// The text of the confirm button
- /// The text of the cancel button, if the cancel button will not be shown
- /// A task containing the result of the dialog, if confirmed; otherwise
+ /// The text of the cancel button, if the cancel button will not be shown
+ ///
+ /// A task containing the result of the dialog, if confirmed; otherwise
+ ///
+ ///
Task ShowConfirmContentDialog(string title, string message, string confirm = "Confirm", string? cancel = "Cancel");
///
- /// Creates an open file dialog, use the fluent API to configure it
+ /// Creates an open file dialog, use the fluent API to configure it
///
/// The builder that can be used to configure the dialog
OpenFileDialogBuilder CreateOpenFileDialog();
///
- /// Creates a save file dialog, use the fluent API to configure it
+ /// Creates a save file dialog, use the fluent API to configure it
///
/// The builder that can be used to configure the dialog
SaveFileDialogBuilder CreateSaveFileDialog();
///
- /// Creates a content dialog, use the fluent API to configure it
+ /// Creates a content dialog, use the fluent API to configure it
///
/// The builder that can be used to configure the dialog
ContentDialogBuilder CreateContentDialog();
///
- /// Gets the current window of the application
+ /// Gets the current window of the application
///
/// The current window of the application
- Window GetCurrentWindow();
+ Window? GetCurrentWindow();
}
}
\ No newline at end of file
diff --git a/src/Avalonia/Artemis.UI.Shared/Services/MainWindowService/IMainWindowService.cs b/src/Avalonia/Artemis.UI.Shared/Services/MainWindowService/IMainWindowService.cs
index 8a42d73a9..1022f39cb 100644
--- a/src/Avalonia/Artemis.UI.Shared/Services/MainWindowService/IMainWindowService.cs
+++ b/src/Avalonia/Artemis.UI.Shared/Services/MainWindowService/IMainWindowService.cs
@@ -3,6 +3,9 @@ using Artemis.UI.Shared.Services.Interfaces;
namespace Artemis.UI.Shared.Services.MainWindowService
{
+ ///
+ /// A service that can be used to manage the state of the main window.
+ ///
public interface IMainWindowService : IArtemisSharedUIService
{
///
diff --git a/src/Avalonia/Artemis.UI.Shared/Services/NotificationService.cs b/src/Avalonia/Artemis.UI.Shared/Services/NotificationService.cs
index 224fbf0cb..ed9408593 100644
--- a/src/Avalonia/Artemis.UI.Shared/Services/NotificationService.cs
+++ b/src/Avalonia/Artemis.UI.Shared/Services/NotificationService.cs
@@ -1,9 +1,10 @@
using Artemis.UI.Shared.Services.Builders;
using Artemis.UI.Shared.Services.Interfaces;
+using Avalonia.Controls;
namespace Artemis.UI.Shared.Services
{
- public class NotificationService : INotificationService
+ internal class NotificationService : INotificationService
{
private readonly IWindowService _windowService;
@@ -14,7 +15,11 @@ namespace Artemis.UI.Shared.Services
public NotificationBuilder CreateNotification()
{
- return new NotificationBuilder(_windowService.GetCurrentWindow());
+ Window? currentWindow = _windowService.GetCurrentWindow();
+ if (currentWindow == null)
+ throw new ArtemisSharedUIException("Can't show an in-app notification without any windows being shown.");
+
+ return new NotificationBuilder(currentWindow);
}
}
}
\ No newline at end of file
diff --git a/src/Avalonia/Artemis.UI.Shared/Services/WindowService/ExceptionDialogViewModel.cs b/src/Avalonia/Artemis.UI.Shared/Services/WindowService/ExceptionDialogViewModel.cs
index 093c9e53e..9aa31727b 100644
--- a/src/Avalonia/Artemis.UI.Shared/Services/WindowService/ExceptionDialogViewModel.cs
+++ b/src/Avalonia/Artemis.UI.Shared/Services/WindowService/ExceptionDialogViewModel.cs
@@ -24,6 +24,9 @@ namespace Artemis.UI.Shared.Services
public async Task CopyException()
{
+ if (Application.Current?.Clipboard == null)
+ return;
+
await Application.Current.Clipboard.SetTextAsync(Exception.ToString());
_notificationService.CreateNotification()
.WithMessage("Copied stack trace to clipboard.")
diff --git a/src/Avalonia/Artemis.UI.Shared/Services/WindowService/WindowService.cs b/src/Avalonia/Artemis.UI.Shared/Services/WindowService/WindowService.cs
index 691eca3cf..7479b4b16 100644
--- a/src/Avalonia/Artemis.UI.Shared/Services/WindowService/WindowService.cs
+++ b/src/Avalonia/Artemis.UI.Shared/Services/WindowService/WindowService.cs
@@ -39,14 +39,10 @@ namespace Artemis.UI.Shared.Services
Type? type = viewModel.GetType().Assembly.GetType(name);
if (type == null)
- {
throw new ArtemisSharedUIException($"Failed to find a window named {name}.");
- }
if (!type.IsAssignableTo(typeof(Window)))
- {
throw new ArtemisSharedUIException($"Type {name} is not a window.");
- }
Window window = (Window) Activator.CreateInstance(type)!;
window.DataContext = viewModel;
@@ -77,20 +73,16 @@ namespace Artemis.UI.Shared.Services
public async Task ShowDialogAsync(DialogViewModelBase viewModel)
{
- Window parent = GetCurrentWindow();
+ Window? parent = GetCurrentWindow();
string name = viewModel.GetType().FullName!.Split('`')[0].Replace("ViewModel", "View");
Type? type = viewModel.GetType().Assembly.GetType(name);
if (type == null)
- {
throw new ArtemisSharedUIException($"Failed to find a window named {name}.");
- }
if (!type.IsAssignableTo(typeof(Window)))
- {
throw new ArtemisSharedUIException($"Type {name} is not a window.");
- }
Window window = (Window) Activator.CreateInstance(type)!;
window.DataContext = viewModel;
@@ -122,25 +114,32 @@ namespace Artemis.UI.Shared.Services
public ContentDialogBuilder CreateContentDialog()
{
- return new ContentDialogBuilder(_kernel, GetCurrentWindow());
+ Window? currentWindow = GetCurrentWindow();
+ if (currentWindow == null)
+ throw new ArtemisSharedUIException("Can't show a content dialog without any windows being shown.");
+ return new ContentDialogBuilder(_kernel, currentWindow);
}
public OpenFileDialogBuilder CreateOpenFileDialog()
{
- return new OpenFileDialogBuilder(GetCurrentWindow());
+ Window? currentWindow = GetCurrentWindow();
+ if (currentWindow == null)
+ throw new ArtemisSharedUIException("Can't show an open file dialog without any windows being shown.");
+ return new OpenFileDialogBuilder(currentWindow);
}
public SaveFileDialogBuilder CreateSaveFileDialog()
{
- return new SaveFileDialogBuilder(GetCurrentWindow());
+ Window? currentWindow = GetCurrentWindow();
+ if (currentWindow == null)
+ throw new ArtemisSharedUIException("Can't show a save file dialog without any windows being shown.");
+ return new SaveFileDialogBuilder(currentWindow);
}
public Window? GetCurrentWindow()
{
- if (Application.Current.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime classic)
- {
- throw new ArtemisSharedUIException("Can't show a dialog when application lifetime is not IClassicDesktopStyleApplicationLifetime.");
- }
+ if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime classic)
+ throw new ArtemisSharedUIException("Find an open window when application lifetime is not IClassicDesktopStyleApplicationLifetime.");
Window? parent = classic.Windows.FirstOrDefault(w => w.IsActive && w.ShowInTaskbar) ?? classic.MainWindow;
return parent;
diff --git a/src/Avalonia/Artemis.UI.Windows/ApplicationStateManager.cs b/src/Avalonia/Artemis.UI.Windows/ApplicationStateManager.cs
index e12820631..aec129e73 100644
--- a/src/Avalonia/Artemis.UI.Windows/ApplicationStateManager.cs
+++ b/src/Avalonia/Artemis.UI.Windows/ApplicationStateManager.cs
@@ -34,7 +34,7 @@ namespace Artemis.UI.Windows
Core.Utilities.RestartRequested += UtilitiesOnRestartRequested;
// On Windows shutdown dispose the kernel just so device providers get a chance to clean up
- if (Application.Current.ApplicationLifetime is IControlledApplicationLifetime controlledApplicationLifetime)
+ if (Application.Current?.ApplicationLifetime is IControlledApplicationLifetime controlledApplicationLifetime)
{
controlledApplicationLifetime.Exit += (_, _) =>
{
@@ -159,7 +159,7 @@ namespace Artemis.UI.Windows
}
// Lets try a graceful shutdown, PowerShell will kill if needed
- if (Application.Current.ApplicationLifetime is IControlledApplicationLifetime controlledApplicationLifetime)
+ if (Application.Current?.ApplicationLifetime is IControlledApplicationLifetime controlledApplicationLifetime)
Dispatcher.UIThread.Post(() => controlledApplicationLifetime.Shutdown());
}
@@ -168,7 +168,7 @@ namespace Artemis.UI.Windows
// Use PowerShell to kill the process after 8 sec just in case
RunForcedShutdownIfEnabled();
- if (Application.Current.ApplicationLifetime is IControlledApplicationLifetime controlledApplicationLifetime)
+ if (Application.Current?.ApplicationLifetime is IControlledApplicationLifetime controlledApplicationLifetime)
Dispatcher.UIThread.Post(() => controlledApplicationLifetime.Shutdown());
}
diff --git a/src/Avalonia/Artemis.UI.Windows/Artemis.UI.Windows.csproj b/src/Avalonia/Artemis.UI.Windows/Artemis.UI.Windows.csproj
index 8197e5866..09a66cd75 100644
--- a/src/Avalonia/Artemis.UI.Windows/Artemis.UI.Windows.csproj
+++ b/src/Avalonia/Artemis.UI.Windows/Artemis.UI.Windows.csproj
@@ -3,6 +3,7 @@
WinExenet5.0-windowsenable
+ x64
diff --git a/src/Avalonia/Artemis.UI.Windows/Providers/Input/WindowsInputProvider.cs b/src/Avalonia/Artemis.UI.Windows/Providers/Input/WindowsInputProvider.cs
index ef4f81bd9..30ed82688 100644
--- a/src/Avalonia/Artemis.UI.Windows/Providers/Input/WindowsInputProvider.cs
+++ b/src/Avalonia/Artemis.UI.Windows/Providers/Input/WindowsInputProvider.cs
@@ -113,13 +113,13 @@ namespace Artemis.UI.Windows.Providers.Input
if (key == KeyboardKey.LeftCtrl && keyboardData.Keyboard.ScanCode == 56)
return;
- string identifier = data.Device?.DevicePath;
+ string? identifier = data.Device?.DevicePath;
// Let the core know there is an identifier so it can store new identifications if applicable
if (identifier != null)
OnIdentifierReceived(identifier, InputDeviceType.Keyboard);
- ArtemisDevice device = null;
+ ArtemisDevice? device = null;
if (identifier != null)
try
{
@@ -180,9 +180,10 @@ namespace Artemis.UI.Windows.Providers.Input
return;
}
- ArtemisDevice device = null;
- string identifier = data.Device?.DevicePath;
+ ArtemisDevice? device = null;
+ string? identifier = data.Device?.DevicePath;
if (identifier != null)
+ {
try
{
device = _inputService.GetDeviceByIdentifier(this, identifier, InputDeviceType.Mouse);
@@ -191,6 +192,7 @@ namespace Artemis.UI.Windows.Providers.Input
{
_logger.Warning(e, "Failed to retrieve input device by its identifier");
}
+ }
// Debug.WriteLine($"Buttons: {mouseData.Mouse.Buttons}, Data: {mouseData.Mouse.ButtonData}, Flags: {mouseData.Mouse.Flags}, XY: {mouseData.Mouse.LastX},{mouseData.Mouse.LastY}");
diff --git a/src/Avalonia/Artemis.UI.Windows/Utilities/ProcessUtilities.cs b/src/Avalonia/Artemis.UI.Windows/Utilities/ProcessUtilities.cs
index fc61a664c..7bf9ead89 100644
--- a/src/Avalonia/Artemis.UI.Windows/Utilities/ProcessUtilities.cs
+++ b/src/Avalonia/Artemis.UI.Windows/Utilities/ProcessUtilities.cs
@@ -91,7 +91,7 @@ namespace Artemis.UI.Windows.Utilities
}
PROCESS_INFORMATION pi = new();
- if (!CreateProcessWithTokenW(hPrimaryToken, 0, fileName, $"\"{fileName}\" {arguments}", 0, IntPtr.Zero, Path.GetDirectoryName(fileName), ref si, out pi))
+ if (!CreateProcessWithTokenW(hPrimaryToken, 0, fileName, $"\"{fileName}\" {arguments}", 0, IntPtr.Zero, Path.GetDirectoryName(fileName)!, ref si, out pi))
{
// Get the last error and display it.
int error = Marshal.GetLastWin32Error();
@@ -203,7 +203,7 @@ namespace Artemis.UI.Windows.Utilities
private static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
[DllImport("advapi32.dll", SetLastError = true)]
- private static extern bool LookupPrivilegeValue(string host, string name, ref LUID pluid);
+ private static extern bool LookupPrivilegeValue(string? host, string name, ref LUID pluid);
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
private static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TOKEN_PRIVILEGES newst, int len, IntPtr prev, IntPtr relen);
diff --git a/src/Avalonia/Artemis.UI/Converters/ColorToSolidColorBrushConverter.cs b/src/Avalonia/Artemis.UI/Converters/ColorToSolidColorBrushConverter.cs
index 5e764ef9e..7bf4a26e7 100644
--- a/src/Avalonia/Artemis.UI/Converters/ColorToSolidColorBrushConverter.cs
+++ b/src/Avalonia/Artemis.UI/Converters/ColorToSolidColorBrushConverter.cs
@@ -12,7 +12,7 @@ namespace Artemis.UI.Converters
public class ColorToSolidColorBrushConverter : IValueConverter
{
///
- public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return new SolidColorBrush(!(value is RGBColor color)
? new Color(0, 0, 0, 0)
@@ -20,7 +20,7 @@ namespace Artemis.UI.Converters
}
///
- public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return !(value is SolidColorBrush brush)
? RGBColor.Transparent
diff --git a/src/Avalonia/Artemis.UI/Converters/EnumToCollectionConverter.cs b/src/Avalonia/Artemis.UI/Converters/EnumToCollectionConverter.cs
deleted file mode 100644
index 4d64bc484..000000000
--- a/src/Avalonia/Artemis.UI/Converters/EnumToCollectionConverter.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Globalization;
-using System.Linq;
-using Avalonia.Data.Converters;
-using Avalonia.Markup.Xaml;
-
-namespace Artemis.UI.Converters
-{
- public class EnumToCollectionConverter : MarkupExtension, IValueConverter
- {
- public override object ProvideValue(IServiceProvider serviceProvider)
- {
- return this;
- }
-
- private static string Description(Enum value)
- {
- object[] attributes = value.GetType().GetField(value.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
- if (attributes.Any())
- return (attributes.First() as DescriptionAttribute)?.Description;
-
- // If no description is found, the least we can do is replace underscores with spaces
- TextInfo ti = CultureInfo.CurrentCulture.TextInfo;
- return ti.ToTitleCase(ti.ToLower(value.ToString().Replace("_", " ")));
- }
-
- private static IEnumerable> GetAllValuesAndDescriptions(Type t)
- {
- if (!t.IsEnum)
- throw new ArgumentException($"{nameof(t)} must be an enum type");
-
- return Enum.GetValues(t).Cast().Select(e => new Tuple