mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Core - Rewrote profile configuration icons
WPF UI - Adjusted for the above rewrite Avalonia UI - Implemented profile icons
This commit is contained in:
parent
4c5c785aa6
commit
a6f1b05c19
@ -27,7 +27,8 @@ namespace Artemis.Core
|
|||||||
_category = category;
|
_category = category;
|
||||||
|
|
||||||
Entity = new ProfileConfigurationEntity();
|
Entity = new ProfileConfigurationEntity();
|
||||||
Icon = new ProfileConfigurationIcon(Entity) {MaterialIcon = icon};
|
Icon = new ProfileConfigurationIcon(Entity);
|
||||||
|
Icon.SetIconByName(icon);
|
||||||
ActivationCondition = new NodeScript<bool>("Activate profile", "Whether or not the profile should be active", this);
|
ActivationCondition = new NodeScript<bool>("Activate profile", "Whether or not the profile should be active", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System.IO;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using Artemis.Core.JsonConverters;
|
using Artemis.Core.JsonConverters;
|
||||||
using Artemis.Storage.Entities.Profile;
|
using Artemis.Storage.Entities.Profile;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
@ -8,7 +9,7 @@ namespace Artemis.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A model that can be used to serialize a profile configuration, it's profile and it's icon
|
/// A model that can be used to serialize a profile configuration, it's profile and it's icon
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ProfileConfigurationExportModel
|
public class ProfileConfigurationExportModel : IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the storage entity of the profile configuration
|
/// Gets or sets the storage entity of the profile configuration
|
||||||
@ -26,5 +27,11 @@ namespace Artemis.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonConverter(typeof(StreamConverter))]
|
[JsonConverter(typeof(StreamConverter))]
|
||||||
public Stream? ProfileImage { get; set; }
|
public Stream? ProfileImage { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
ProfileImage?.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
using System.ComponentModel;
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Artemis.Storage.Entities.Profile;
|
using Artemis.Storage.Entities.Profile;
|
||||||
|
|
||||||
@ -10,9 +11,10 @@ namespace Artemis.Core
|
|||||||
public class ProfileConfigurationIcon : CorePropertyChanged, IStorageModel
|
public class ProfileConfigurationIcon : CorePropertyChanged, IStorageModel
|
||||||
{
|
{
|
||||||
private readonly ProfileConfigurationEntity _entity;
|
private readonly ProfileConfigurationEntity _entity;
|
||||||
private Stream? _fileIcon;
|
private string? _iconName;
|
||||||
|
private Stream? _iconStream;
|
||||||
private ProfileConfigurationIconType _iconType;
|
private ProfileConfigurationIconType _iconType;
|
||||||
private string? _materialIcon;
|
private string? _originalFileName;
|
||||||
|
|
||||||
internal ProfileConfigurationIcon(ProfileConfigurationEntity entity)
|
internal ProfileConfigurationIcon(ProfileConfigurationEntity entity)
|
||||||
{
|
{
|
||||||
@ -20,31 +22,82 @@ namespace Artemis.Core
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the type of icon this profile configuration uses
|
/// Gets the type of icon this profile configuration uses
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ProfileConfigurationIconType IconType
|
public ProfileConfigurationIconType IconType
|
||||||
{
|
{
|
||||||
get => _iconType;
|
get => _iconType;
|
||||||
set => SetAndNotify(ref _iconType, value);
|
private set => SetAndNotify(ref _iconType, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the icon if it is a Material icon
|
/// Gets the name of the icon if <see cref="IconType" /> is <see cref="ProfileConfigurationIconType.MaterialIcon" />
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? MaterialIcon
|
public string? IconName
|
||||||
{
|
{
|
||||||
get => _materialIcon;
|
get => _iconName;
|
||||||
set => SetAndNotify(ref _materialIcon, value);
|
private set => SetAndNotify(ref _iconName, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a stream containing the icon if it is bitmap or SVG
|
/// Gets the original file name of the icon (if applicable)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
public string? OriginalFileName
|
||||||
public Stream? FileIcon
|
|
||||||
{
|
{
|
||||||
get => _fileIcon;
|
get => _originalFileName;
|
||||||
set => SetAndNotify(ref _fileIcon, value);
|
private set => SetAndNotify(ref _originalFileName, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the <see cref="IconName" /> to the provided value and changes the <see cref="IconType" /> is
|
||||||
|
/// <see cref="ProfileConfigurationIconType.MaterialIcon" />
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="iconName">The name of the icon</param>
|
||||||
|
public void SetIconByName(string iconName)
|
||||||
|
{
|
||||||
|
IconName = iconName ?? throw new ArgumentNullException(nameof(iconName));
|
||||||
|
OriginalFileName = null;
|
||||||
|
IconType = ProfileConfigurationIconType.MaterialIcon;
|
||||||
|
|
||||||
|
_iconStream?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the stream returned by <see cref="GetIconStream" /> to the provided stream
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="originalFileName">The original file name backing the stream, should include the extension</param>
|
||||||
|
/// <param name="stream">The stream to copy</param>
|
||||||
|
public void SetIconByStream(string originalFileName, Stream stream)
|
||||||
|
{
|
||||||
|
if (originalFileName == null) throw new ArgumentNullException(nameof(originalFileName));
|
||||||
|
if (stream == null) throw new ArgumentNullException(nameof(stream));
|
||||||
|
|
||||||
|
_iconStream?.Dispose();
|
||||||
|
_iconStream = new MemoryStream();
|
||||||
|
stream.Seek(0, SeekOrigin.Begin);
|
||||||
|
stream.CopyTo(_iconStream);
|
||||||
|
_iconStream.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
IconName = null;
|
||||||
|
OriginalFileName = originalFileName;
|
||||||
|
IconType = OriginalFileName.EndsWith(".svg") ? ProfileConfigurationIconType.SvgImage : ProfileConfigurationIconType.BitmapImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a copy of the stream containing the icon
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A stream containing the icon</returns>
|
||||||
|
public Stream? GetIconStream()
|
||||||
|
{
|
||||||
|
if (_iconStream == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
MemoryStream stream = new();
|
||||||
|
_iconStream.CopyTo(stream);
|
||||||
|
|
||||||
|
stream.Seek(0, SeekOrigin.Begin);
|
||||||
|
_iconStream.Seek(0, SeekOrigin.Begin);
|
||||||
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Implementation of IStorageModel
|
#region Implementation of IStorageModel
|
||||||
@ -53,14 +106,15 @@ namespace Artemis.Core
|
|||||||
public void Load()
|
public void Load()
|
||||||
{
|
{
|
||||||
IconType = (ProfileConfigurationIconType) _entity.IconType;
|
IconType = (ProfileConfigurationIconType) _entity.IconType;
|
||||||
MaterialIcon = _entity.MaterialIcon;
|
if (IconType == ProfileConfigurationIconType.MaterialIcon)
|
||||||
|
IconName = _entity.MaterialIcon;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Save()
|
public void Save()
|
||||||
{
|
{
|
||||||
_entity.IconType = (int) IconType;
|
_entity.IconType = (int) IconType;
|
||||||
_entity.MaterialIcon = MaterialIcon;
|
_entity.MaterialIcon = IconType == ProfileConfigurationIconType.MaterialIcon ? IconName : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@ -304,10 +304,13 @@ namespace Artemis.Core.Services
|
|||||||
{
|
{
|
||||||
if (profileConfiguration.Icon.IconType == ProfileConfigurationIconType.MaterialIcon)
|
if (profileConfiguration.Icon.IconType == ProfileConfigurationIconType.MaterialIcon)
|
||||||
return;
|
return;
|
||||||
if (profileConfiguration.Icon.FileIcon != null)
|
|
||||||
return;
|
// This can happen if the icon was saved before the original file name was stored (pre-Avalonia)
|
||||||
|
profileConfiguration.Entity.IconOriginalFileName ??= profileConfiguration.Icon.IconType == ProfileConfigurationIconType.BitmapImage ? "icon.png" : "icon.svg";
|
||||||
|
|
||||||
profileConfiguration.Icon.FileIcon = _profileCategoryRepository.GetProfileIconStream(profileConfiguration.Entity.FileIconId);
|
using Stream? stream = _profileCategoryRepository.GetProfileIconStream(profileConfiguration.Entity.FileIconId);
|
||||||
|
if (stream != null)
|
||||||
|
profileConfiguration.Icon.SetIconByStream(profileConfiguration.Entity.IconOriginalFileName, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SaveProfileConfigurationIcon(ProfileConfiguration profileConfiguration)
|
public void SaveProfileConfigurationIcon(ProfileConfiguration profileConfiguration)
|
||||||
@ -315,10 +318,11 @@ namespace Artemis.Core.Services
|
|||||||
if (profileConfiguration.Icon.IconType == ProfileConfigurationIconType.MaterialIcon)
|
if (profileConfiguration.Icon.IconType == ProfileConfigurationIconType.MaterialIcon)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (profileConfiguration.Icon.FileIcon != null)
|
using Stream? stream = profileConfiguration.Icon.GetIconStream();
|
||||||
|
if (stream != null && profileConfiguration.Icon.OriginalFileName != null)
|
||||||
{
|
{
|
||||||
profileConfiguration.Icon.FileIcon.Position = 0;
|
profileConfiguration.Entity.IconOriginalFileName = profileConfiguration.Icon.OriginalFileName;
|
||||||
_profileCategoryRepository.SaveProfileIconStream(profileConfiguration.Entity, profileConfiguration.Icon.FileIcon);
|
_profileCategoryRepository.SaveProfileIconStream(profileConfiguration.Entity, stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -532,7 +536,7 @@ namespace Artemis.Core.Services
|
|||||||
{
|
{
|
||||||
ProfileConfigurationEntity = profileConfiguration.Entity,
|
ProfileConfigurationEntity = profileConfiguration.Entity,
|
||||||
ProfileEntity = profile.ProfileEntity,
|
ProfileEntity = profile.ProfileEntity,
|
||||||
ProfileImage = profileConfiguration.Icon.FileIcon
|
ProfileImage = profileConfiguration.Icon.GetIconStream()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -579,12 +583,8 @@ namespace Artemis.Core.Services
|
|||||||
profileConfiguration = new ProfileConfiguration(category, profileEntity.Name, "Import");
|
profileConfiguration = new ProfileConfiguration(category, profileEntity.Name, "Import");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exportModel.ProfileImage != null)
|
if (exportModel.ProfileImage != null && exportModel.ProfileConfigurationEntity?.IconOriginalFileName != null)
|
||||||
{
|
profileConfiguration.Icon.SetIconByStream(exportModel.ProfileConfigurationEntity.IconOriginalFileName, exportModel.ProfileImage);
|
||||||
profileConfiguration.Icon.FileIcon = new MemoryStream();
|
|
||||||
exportModel.ProfileImage.Position = 0;
|
|
||||||
exportModel.ProfileImage.CopyTo(profileConfiguration.Icon.FileIcon);
|
|
||||||
}
|
|
||||||
|
|
||||||
profileConfiguration.Entity.ProfileId = profileEntity.Id;
|
profileConfiguration.Entity.ProfileId = profileEntity.Id;
|
||||||
category.AddProfileConfiguration(profileConfiguration, 0);
|
category.AddProfileConfiguration(profileConfiguration, 0);
|
||||||
|
|||||||
@ -8,6 +8,7 @@ namespace Artemis.Storage.Entities.Profile
|
|||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string MaterialIcon { get; set; }
|
public string MaterialIcon { get; set; }
|
||||||
|
public string IconOriginalFileName { get; set; }
|
||||||
public Guid FileIconId { get; set; }
|
public Guid FileIconId { get; set; }
|
||||||
public int IconType { get; set; }
|
public int IconType { get; set; }
|
||||||
public int Order { get; set; }
|
public int Order { get; set; }
|
||||||
|
|||||||
@ -70,7 +70,7 @@ namespace Artemis.Storage.Repositories
|
|||||||
if (stream == null && _profileIcons.Exists(profileConfigurationEntity.FileIconId))
|
if (stream == null && _profileIcons.Exists(profileConfigurationEntity.FileIconId))
|
||||||
_profileIcons.Delete(profileConfigurationEntity.FileIconId);
|
_profileIcons.Delete(profileConfigurationEntity.FileIconId);
|
||||||
|
|
||||||
_profileIcons.Upload(profileConfigurationEntity.FileIconId, "image", stream);
|
_profileIcons.Upload(profileConfigurationEntity.FileIconId, profileConfigurationEntity.IconOriginalFileName, stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,6 +166,17 @@
|
|||||||
<member name="M:Artemis.UI.Shared.Converters.ColorToSKColorConverter.ConvertBack(System.Object,System.Type,System.Object,System.Globalization.CultureInfo)">
|
<member name="M:Artemis.UI.Shared.Converters.ColorToSKColorConverter.ConvertBack(System.Object,System.Type,System.Object,System.Globalization.CultureInfo)">
|
||||||
<inheritdoc />
|
<inheritdoc />
|
||||||
</member>
|
</member>
|
||||||
|
<member name="T:Artemis.UI.Shared.Converters.EnumToBooleanConverter">
|
||||||
|
<summary>
|
||||||
|
Converts an enum into a boolean.
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.Converters.EnumToBooleanConverter.Convert(System.Object,System.Type,System.Object,System.Globalization.CultureInfo)">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
|
<member name="M:Artemis.UI.Shared.Converters.EnumToBooleanConverter.ConvertBack(System.Object,System.Type,System.Object,System.Globalization.CultureInfo)">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
<member name="T:Artemis.UI.Shared.Converters.SKColorToColorConverter">
|
<member name="T:Artemis.UI.Shared.Converters.SKColorToColorConverter">
|
||||||
<summary>
|
<summary>
|
||||||
Converts <see cref="T:SkiaSharp.SKColor" /> into <see cref="T:Avalonia.Media.Color" />.
|
Converts <see cref="T:SkiaSharp.SKColor" /> into <see cref="T:Avalonia.Media.Color" />.
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
<Setter Property="ContentTemplate">
|
<Setter Property="ContentTemplate">
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<materialDesign:PackIcon Kind="{Binding ConfigurationIcon.MaterialIcon, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
|
<materialDesign:PackIcon Kind="{Binding ConfigurationIcon.IconName, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
|
||||||
Width="Auto"
|
Width="Auto"
|
||||||
Height="Auto" />
|
Height="Auto" />
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
xmlns:profileEdit="clr-namespace:Artemis.UI.Screens.Sidebar.Dialogs.ProfileEdit"
|
xmlns:profileEdit="clr-namespace:Artemis.UI.Screens.Sidebar.Dialogs.ProfileEdit"
|
||||||
xmlns:core="clr-namespace:Artemis.Core;assembly=Artemis.Core"
|
xmlns:core="clr-namespace:Artemis.Core;assembly=Artemis.Core"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="280"
|
d:DesignHeight="450" d:DesignWidth="600"
|
||||||
d:DataContext="{d:DesignInstance {x:Type profileEdit:ProfileEditViewModel}}"
|
d:DataContext="{d:DesignInstance {x:Type profileEdit:ProfileEditViewModel}}"
|
||||||
Width="800">
|
Width="800">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
|
|||||||
@ -28,6 +28,7 @@ namespace Artemis.UI.Screens.Sidebar.Dialogs.ProfileEdit
|
|||||||
private ProfileConfigurationIconType _selectedIconType;
|
private ProfileConfigurationIconType _selectedIconType;
|
||||||
private Stream _selectedImage;
|
private Stream _selectedImage;
|
||||||
private ProfileModuleViewModel _selectedModule;
|
private ProfileModuleViewModel _selectedModule;
|
||||||
|
private string _selectedIconPath;
|
||||||
|
|
||||||
public ProfileEditViewModel(ProfileConfiguration profileConfiguration, bool isNew,
|
public ProfileEditViewModel(ProfileConfiguration profileConfiguration, bool isNew,
|
||||||
IProfileService profileService,
|
IProfileService profileService,
|
||||||
@ -48,7 +49,7 @@ namespace Artemis.UI.Screens.Sidebar.Dialogs.ProfileEdit
|
|||||||
pluginManagementService.GetFeaturesOfType<Module>().Where(m => !m.IsAlwaysAvailable).Select(m => new ProfileModuleViewModel(m))
|
pluginManagementService.GetFeaturesOfType<Module>().Where(m => !m.IsAlwaysAvailable).Select(m => new ProfileModuleViewModel(m))
|
||||||
);
|
);
|
||||||
Initializing = true;
|
Initializing = true;
|
||||||
|
|
||||||
ModuleActivationRequirementsViewModel = new ModuleActivationRequirementsViewModel(sidebarVmFactory);
|
ModuleActivationRequirementsViewModel = new ModuleActivationRequirementsViewModel(sidebarVmFactory);
|
||||||
ModuleActivationRequirementsViewModel.ConductWith(this);
|
ModuleActivationRequirementsViewModel.ConductWith(this);
|
||||||
ModuleActivationRequirementsViewModel.SetModule(ProfileConfiguration.Module);
|
ModuleActivationRequirementsViewModel.SetModule(ProfileConfiguration.Module);
|
||||||
@ -60,7 +61,7 @@ namespace Artemis.UI.Screens.Sidebar.Dialogs.ProfileEdit
|
|||||||
_profileName = ProfileConfiguration.Name;
|
_profileName = ProfileConfiguration.Name;
|
||||||
_selectedModule = Modules.FirstOrDefault(m => m.Module == ProfileConfiguration.Module);
|
_selectedModule = Modules.FirstOrDefault(m => m.Module == ProfileConfiguration.Module);
|
||||||
_selectedIconType = ProfileConfiguration.Icon.IconType;
|
_selectedIconType = ProfileConfiguration.Icon.IconType;
|
||||||
_selectedImage = ProfileConfiguration.Icon.FileIcon;
|
_selectedImage = ProfileConfiguration.Icon.GetIconStream();
|
||||||
|
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
@ -71,11 +72,11 @@ namespace Artemis.UI.Screens.Sidebar.Dialogs.ProfileEdit
|
|||||||
if (IsNew)
|
if (IsNew)
|
||||||
SelectedIcon = Icons[new Random().Next(0, Icons.Count - 1)];
|
SelectedIcon = Icons[new Random().Next(0, Icons.Count - 1)];
|
||||||
else
|
else
|
||||||
SelectedIcon = Icons.FirstOrDefault(i => i.Icon.ToString() == ProfileConfiguration.Icon.MaterialIcon);
|
SelectedIcon = Icons.FirstOrDefault(i => i.Icon.ToString() == ProfileConfiguration.Icon.IconName);
|
||||||
Initializing = false;
|
Initializing = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModuleActivationRequirementsViewModel ModuleActivationRequirementsViewModel { get; }
|
public ModuleActivationRequirementsViewModel ModuleActivationRequirementsViewModel { get; }
|
||||||
public ProfileConfigurationHotkeyViewModel EnableHotkeyViewModel { get; }
|
public ProfileConfigurationHotkeyViewModel EnableHotkeyViewModel { get; }
|
||||||
public ProfileConfigurationHotkeyViewModel DisableHotkeyViewModel { get; }
|
public ProfileConfigurationHotkeyViewModel DisableHotkeyViewModel { get; }
|
||||||
@ -167,18 +168,18 @@ namespace Artemis.UI.Screens.Sidebar.Dialogs.ProfileEdit
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
ProfileConfiguration.Name = ProfileName;
|
ProfileConfiguration.Name = ProfileName;
|
||||||
ProfileConfiguration.Icon.IconType = SelectedIconType;
|
if (SelectedIconType == ProfileConfigurationIconType.MaterialIcon)
|
||||||
ProfileConfiguration.Icon.MaterialIcon = SelectedIcon?.Icon.ToString();
|
ProfileConfiguration.Icon.SetIconByName(SelectedIcon?.Icon.ToString());
|
||||||
ProfileConfiguration.Icon.FileIcon = SelectedImage;
|
else if (_selectedIconPath != null)
|
||||||
|
{
|
||||||
|
await using FileStream fileStream = File.OpenRead(_selectedIconPath);
|
||||||
|
ProfileConfiguration.Icon.SetIconByStream(Path.GetFileName(_selectedIconPath), fileStream);
|
||||||
|
}
|
||||||
|
|
||||||
ProfileConfiguration.Module = SelectedModule?.Module;
|
ProfileConfiguration.Module = SelectedModule?.Module;
|
||||||
|
|
||||||
if (_changedImage)
|
if (_changedImage)
|
||||||
{
|
|
||||||
ProfileConfiguration.Icon.FileIcon = SelectedImage;
|
|
||||||
_profileService.SaveProfileConfigurationIcon(ProfileConfiguration);
|
_profileService.SaveProfileConfigurationIcon(ProfileConfiguration);
|
||||||
}
|
|
||||||
|
|
||||||
_profileService.SaveProfileCategory(ProfileConfiguration.Category);
|
_profileService.SaveProfileCategory(ProfileConfiguration.Category);
|
||||||
|
|
||||||
Session.Close(nameof(Accept));
|
Session.Close(nameof(Accept));
|
||||||
@ -199,6 +200,7 @@ namespace Artemis.UI.Screens.Sidebar.Dialogs.ProfileEdit
|
|||||||
|
|
||||||
// TODO: Scale down to 100x100-ish
|
// TODO: Scale down to 100x100-ish
|
||||||
SelectedImage = File.OpenRead(dialog.FileName);
|
SelectedImage = File.OpenRead(dialog.FileName);
|
||||||
|
_selectedIconPath = dialog.FileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SelectSvgFile()
|
public void SelectSvgFile()
|
||||||
@ -214,6 +216,7 @@ namespace Artemis.UI.Screens.Sidebar.Dialogs.ProfileEdit
|
|||||||
|
|
||||||
_changedImage = true;
|
_changedImage = true;
|
||||||
SelectedImage = File.OpenRead(dialog.FileName);
|
SelectedImage = File.OpenRead(dialog.FileName);
|
||||||
|
_selectedIconPath = dialog.FileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Overrides of Screen
|
#region Overrides of Screen
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.IO;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
@ -48,20 +49,29 @@ namespace Artemis.UI.Shared.Controls
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (ConfigurationIcon.IconType == ProfileConfigurationIconType.SvgImage && ConfigurationIcon.FileIcon != null)
|
if (ConfigurationIcon.IconType == ProfileConfigurationIconType.MaterialIcon)
|
||||||
{
|
{
|
||||||
SvgSource source = new();
|
Content = Enum.TryParse(ConfigurationIcon.IconName, true, out MaterialIconKind parsedIcon)
|
||||||
source.Load(ConfigurationIcon.FileIcon);
|
|
||||||
Content = new SvgImage {Source = source};
|
|
||||||
}
|
|
||||||
else if (ConfigurationIcon.IconType == ProfileConfigurationIconType.MaterialIcon && ConfigurationIcon.MaterialIcon != null)
|
|
||||||
{
|
|
||||||
Content = Enum.TryParse(ConfigurationIcon.MaterialIcon, true, out MaterialIconKind parsedIcon)
|
|
||||||
? new MaterialIcon {Kind = parsedIcon!}
|
? new MaterialIcon {Kind = parsedIcon!}
|
||||||
: new MaterialIcon {Kind = MaterialIconKind.QuestionMark};
|
: new MaterialIcon {Kind = MaterialIconKind.QuestionMark};
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else if (ConfigurationIcon.IconType == ProfileConfigurationIconType.BitmapImage && ConfigurationIcon.FileIcon != null)
|
|
||||||
Content = new Image {Source = new Bitmap(ConfigurationIcon.FileIcon)};
|
Stream? stream = ConfigurationIcon.GetIconStream();
|
||||||
|
if (stream == null)
|
||||||
|
{
|
||||||
|
Content = new MaterialIcon {Kind = MaterialIconKind.QuestionMark};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ConfigurationIcon.IconType == ProfileConfigurationIconType.SvgImage)
|
||||||
|
{
|
||||||
|
SvgSource source = new();
|
||||||
|
source.Load(stream);
|
||||||
|
Content = new Image {Source = new SvgImage {Source = source}};
|
||||||
|
}
|
||||||
|
else if (ConfigurationIcon.IconType == ProfileConfigurationIconType.BitmapImage)
|
||||||
|
Content = new Image {Source = new Bitmap(ConfigurationIcon.GetIconStream())};
|
||||||
else
|
else
|
||||||
Content = new MaterialIcon {Kind = MaterialIconKind.QuestionMark};
|
Content = new MaterialIcon {Kind = MaterialIconKind.QuestionMark};
|
||||||
}
|
}
|
||||||
@ -83,10 +93,8 @@ namespace Artemis.UI.Shared.Controls
|
|||||||
if (ConfigurationIcon != null)
|
if (ConfigurationIcon != null)
|
||||||
ConfigurationIcon.PropertyChanged -= IconOnPropertyChanged;
|
ConfigurationIcon.PropertyChanged -= IconOnPropertyChanged;
|
||||||
|
|
||||||
if (Content is SvgImage svgImage)
|
if (Content is Image image && image.Source is IDisposable disposable)
|
||||||
svgImage.Source?.Dispose();
|
disposable.Dispose();
|
||||||
else if (Content is Image image)
|
|
||||||
((Bitmap) image.Source).Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
|
private void OnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
|
||||||
|
|||||||
@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using Avalonia.Data;
|
||||||
|
using Avalonia.Data.Converters;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Shared.Converters
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts an enum into a boolean.
|
||||||
|
/// </summary>
|
||||||
|
public class EnumToBooleanConverter : IValueConverter
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public object Convert(object? value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
return Equals(value, parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public object ConvertBack(object? value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
return value?.Equals(true) == true ? parameter : BindingOperations.DoNothing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -41,7 +41,7 @@ namespace Artemis.UI.Shared.Services.Interfaces
|
|||||||
/// <typeparam name="TViewModel">The view model type</typeparam>
|
/// <typeparam name="TViewModel">The view model type</typeparam>
|
||||||
/// <typeparam name="TResult">The return type</typeparam>
|
/// <typeparam name="TResult">The return type</typeparam>
|
||||||
/// <returns>A task containing the return value of type <typeparamref name="TResult" /></returns>
|
/// <returns>A task containing the return value of type <typeparamref name="TResult" /></returns>
|
||||||
Task<TResult> ShowDialogAsync<TViewModel, TResult>(params (string name, object value)[] parameters) where TViewModel : DialogViewModelBase<TResult>;
|
Task<TResult> ShowDialogAsync<TViewModel, TResult>(params (string name, object? value)[] parameters) where TViewModel : DialogViewModelBase<TResult>;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shows a content dialog asking the user to confirm an action
|
/// Shows a content dialog asking the user to confirm an action
|
||||||
|
|||||||
@ -56,7 +56,7 @@ namespace Artemis.UI.Shared.Services
|
|||||||
window.Show();
|
window.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
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>
|
||||||
{
|
{
|
||||||
IParameter[] paramsArray = parameters.Select(kv => new ConstructorArgument(kv.name, kv.value)).Cast<IParameter>().ToArray();
|
IParameter[] paramsArray = parameters.Select(kv => new ConstructorArgument(kv.name, kv.value)).Cast<IParameter>().ToArray();
|
||||||
TViewModel viewModel = _kernel.Get<TViewModel>(paramsArray)!;
|
TViewModel viewModel = _kernel.Get<TViewModel>(paramsArray)!;
|
||||||
|
|||||||
@ -1,5 +1,17 @@
|
|||||||
<Styles xmlns="https://github.com/avaloniaui"
|
<Styles xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
<Styles.Resources>
|
||||||
|
<VisualBrush x:Key="CheckerboardBrush" TileMode="Tile" Stretch="Uniform" DestinationRect="0,0,15,15">
|
||||||
|
<VisualBrush.Visual>
|
||||||
|
<Grid Width="15" Height="15" RowDefinitions="*,*" ColumnDefinitions="*,*">
|
||||||
|
<Rectangle Grid.Row="0" Grid.Column="0" Fill="Black" Opacity="0.15" />
|
||||||
|
<Rectangle Grid.Row="0" Grid.Column="1" />
|
||||||
|
<Rectangle Grid.Row="1" Grid.Column="0" />
|
||||||
|
<Rectangle Grid.Row="1" Grid.Column="1" Fill="Black" Opacity="0.15" />
|
||||||
|
</Grid>
|
||||||
|
</VisualBrush.Visual>
|
||||||
|
</VisualBrush>
|
||||||
|
</Styles.Resources>
|
||||||
<StyleInclude Source="/Styles/Border.axaml" />
|
<StyleInclude Source="/Styles/Border.axaml" />
|
||||||
<StyleInclude Source="/Styles/Button.axaml" />
|
<StyleInclude Source="/Styles/Button.axaml" />
|
||||||
<StyleInclude Source="/Styles/TextBlock.axaml" />
|
<StyleInclude Source="/Styles/TextBlock.axaml" />
|
||||||
|
|||||||
@ -15,6 +15,10 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Design.PreviewWith>
|
</Design.PreviewWith>
|
||||||
|
|
||||||
|
<Styles.Resources>
|
||||||
|
<CornerRadius x:Key="CardCornerRadius">8</CornerRadius>
|
||||||
|
</Styles.Resources>
|
||||||
|
|
||||||
<!-- Add Styles Here -->
|
<!-- Add Styles Here -->
|
||||||
<Style Selector="Border.router-container">
|
<Style Selector="Border.router-container">
|
||||||
<Setter Property="Background" Value="{DynamicResource SolidBackgroundFillColorTertiary}" />
|
<Setter Property="Background" Value="{DynamicResource SolidBackgroundFillColorTertiary}" />
|
||||||
@ -25,13 +29,13 @@
|
|||||||
<Style Selector="Border.card">
|
<Style Selector="Border.card">
|
||||||
<Setter Property="Padding" Value="25" />
|
<Setter Property="Padding" Value="25" />
|
||||||
<Setter Property="Background" Value="{DynamicResource ControlFillColorDefaultBrush}" />
|
<Setter Property="Background" Value="{DynamicResource ControlFillColorDefaultBrush}" />
|
||||||
<Setter Property="CornerRadius" Value="10" />
|
<Setter Property="CornerRadius" Value="{DynamicResource CardCornerRadius}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style Selector="Border.card-condensed">
|
<Style Selector="Border.card-condensed">
|
||||||
<Setter Property="Padding" Value="15" />
|
<Setter Property="Padding" Value="15" />
|
||||||
<Setter Property="Background" Value="{DynamicResource ControlFillColorDefaultBrush}" />
|
<Setter Property="Background" Value="{DynamicResource ControlFillColorDefaultBrush}" />
|
||||||
<Setter Property="CornerRadius" Value="10" />
|
<Setter Property="CornerRadius" Value="{DynamicResource CardCornerRadius}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style Selector="Separator.card-separator">
|
<Style Selector="Separator.card-separator">
|
||||||
|
|||||||
@ -51,5 +51,11 @@
|
|||||||
<Compile Update="Screens\Debugger\Tabs\Settings\DebugSettingsView.axaml.cs">
|
<Compile Update="Screens\Debugger\Tabs\Settings\DebugSettingsView.axaml.cs">
|
||||||
<DependentUpon>DebugSettingsView.axaml</DependentUpon>
|
<DependentUpon>DebugSettingsView.axaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Update="Screens\Root\Sidebar\ContentDialogs\SidebarCategoryEditView.axaml.cs">
|
||||||
|
<DependentUpon>SidebarCategoryEditView.axaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="Screens\Root\Sidebar\Dialogs\ProfileConfigurationEditView.axaml.cs">
|
||||||
|
<DependentUpon>ProfileConfigurationEditView.axaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@ -9,20 +9,7 @@
|
|||||||
x:Class="Artemis.UI.Screens.Device.DeviceSettingsView">
|
x:Class="Artemis.UI.Screens.Device.DeviceSettingsView">
|
||||||
<Border Classes="card" Padding="0" Width="200" ClipToBounds="True" Margin="5">
|
<Border Classes="card" Padding="0" Width="200" ClipToBounds="True" Margin="5">
|
||||||
<Grid RowDefinitions="140,*,Auto">
|
<Grid RowDefinitions="140,*,Auto">
|
||||||
<Rectangle Grid.Row="0">
|
<Rectangle Grid.Row="0" Fill="{DynamicResource CheckerboardBrush}"/>
|
||||||
<Rectangle.Fill>
|
|
||||||
<VisualBrush TileMode="Tile" Stretch="Uniform" DestinationRect="0,0,15,15">
|
|
||||||
<VisualBrush.Visual>
|
|
||||||
<Grid Width="15" Height="15" RowDefinitions="*,*" ColumnDefinitions="*,*">
|
|
||||||
<Rectangle Grid.Row="0" Grid.Column="0" Fill="Black" Opacity="0.15" />
|
|
||||||
<Rectangle Grid.Row="0" Grid.Column="1" />
|
|
||||||
<Rectangle Grid.Row="1" Grid.Column="0" />
|
|
||||||
<Rectangle Grid.Row="1" Grid.Column="1" Fill="Black" Opacity="0.15" />
|
|
||||||
</Grid>
|
|
||||||
</VisualBrush.Visual>
|
|
||||||
</VisualBrush>
|
|
||||||
</Rectangle.Fill>
|
|
||||||
</Rectangle>
|
|
||||||
<controls1:DeviceVisualizer VerticalAlignment="Center"
|
<controls1:DeviceVisualizer VerticalAlignment="Center"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
Margin="5"
|
Margin="5"
|
||||||
|
|||||||
@ -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.Screens.Root.Sidebar.Dialogs.SidebarCategoryCreateView">
|
x:Class="Artemis.UI.Screens.Root.Sidebar.Dialogs.SidebarCategoryEditView">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<StackPanel.KeyBindings>
|
<StackPanel.KeyBindings>
|
||||||
<KeyBinding Gesture="Enter" Command="{Binding Confirm}" />
|
<KeyBinding Gesture="Enter" Command="{Binding Confirm}" />
|
||||||
@ -5,9 +5,9 @@ using ReactiveUI;
|
|||||||
|
|
||||||
namespace Artemis.UI.Screens.Root.Sidebar.Dialogs
|
namespace Artemis.UI.Screens.Root.Sidebar.Dialogs
|
||||||
{
|
{
|
||||||
public class SidebarCategoryCreateView : ReactiveUserControl<SidebarCategoryCreateViewModel>
|
public class SidebarCategoryEditView : ReactiveUserControl<SidebarCategoryEditViewModel>
|
||||||
{
|
{
|
||||||
public SidebarCategoryCreateView()
|
public SidebarCategoryEditView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
this.WhenActivated(_ => this.ClearAllDataValidationErrors());
|
this.WhenActivated(_ => this.ClearAllDataValidationErrors());
|
||||||
@ -8,13 +8,13 @@ using ReactiveUI.Validation.Extensions;
|
|||||||
|
|
||||||
namespace Artemis.UI.Screens.Root.Sidebar.Dialogs
|
namespace Artemis.UI.Screens.Root.Sidebar.Dialogs
|
||||||
{
|
{
|
||||||
public class SidebarCategoryCreateViewModel : ContentDialogViewModelBase
|
public class SidebarCategoryEditViewModel : ContentDialogViewModelBase
|
||||||
{
|
{
|
||||||
private readonly IProfileService _profileService;
|
private readonly IProfileService _profileService;
|
||||||
private readonly ProfileCategory? _category;
|
private readonly ProfileCategory? _category;
|
||||||
private string? _categoryName;
|
private string? _categoryName;
|
||||||
|
|
||||||
public SidebarCategoryCreateViewModel(IProfileService profileService, ProfileCategory? category)
|
public SidebarCategoryEditViewModel(IProfileService profileService, ProfileCategory? category)
|
||||||
{
|
{
|
||||||
_profileService = profileService;
|
_profileService = profileService;
|
||||||
_category = category;
|
_category = category;
|
||||||
@ -0,0 +1,150 @@
|
|||||||
|
<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"
|
||||||
|
xmlns:core="clr-namespace:Artemis.Core;assembly=Artemis.Core"
|
||||||
|
xmlns:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
|
||||||
|
xmlns:local="clr-namespace:Artemis.UI.Screens.Root.Sidebar.Dialogs"
|
||||||
|
xmlns:converters="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared"
|
||||||
|
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||||
|
xmlns:svg="clr-namespace:Avalonia.Svg.Skia;assembly=Avalonia.Svg.Skia"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="850"
|
||||||
|
x:Class="Artemis.UI.Screens.Root.Sidebar.Dialogs.ProfileConfigurationEditView"
|
||||||
|
Title="{Binding DisplayName}"
|
||||||
|
Icon="/Assets/Images/Logo/bow.ico"
|
||||||
|
Width="800"
|
||||||
|
Height="850">
|
||||||
|
<Window.Resources>
|
||||||
|
<converters:EnumToBooleanConverter x:Key="EnumBoolConverter" />
|
||||||
|
</Window.Resources>
|
||||||
|
<Grid Margin="16" RowDefinitions="*,Auto">
|
||||||
|
<ScrollViewer>
|
||||||
|
<StackPanel>
|
||||||
|
<StackPanel.Styles>
|
||||||
|
<Style Selector="TextBlock.label">
|
||||||
|
<Setter Property="Margin" Value="0 10 0 5" />
|
||||||
|
</Style>
|
||||||
|
</StackPanel.Styles>
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<TextBlock Classes="h4" IsVisible="{Binding IsNew}">Add a new profile</TextBlock>
|
||||||
|
<TextBlock Classes="h4" IsVisible="{Binding !IsNew}" Text="{Binding ProfileConfiguration.Name}" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<TextBlock Classes="h5">General</TextBlock>
|
||||||
|
|
||||||
|
<Border Classes="card" Margin="0 0 0 15">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Classes="label">Profile name</TextBlock>
|
||||||
|
<TextBox Text="{Binding ProfileName}" />
|
||||||
|
<TextBlock Classes="label">Module</TextBlock>
|
||||||
|
<ComboBox SelectedItem="{Binding SelectedModule}" IsEnabled="{Binding Modules.Count}" Items="{Binding Modules}" HorizontalAlignment="Stretch">
|
||||||
|
<ComboBox.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<VirtualizingStackPanel />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ComboBox.ItemsPanel>
|
||||||
|
<ComboBox.ItemTemplate>
|
||||||
|
<DataTemplate DataType="{x:Type local:ProfileModuleViewModel}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<controls:ArtemisIcon Icon="{Binding Icon}" Width="16" Height="16" Margin="0 0 5 0" />
|
||||||
|
<TextBlock Text="{Binding Name}" />
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ComboBox.ItemTemplate>
|
||||||
|
</ComboBox>
|
||||||
|
<Grid>
|
||||||
|
<TextBlock Classes="subtitle" IsVisible="{Binding Modules.Count}">Optional and binds the profile to the selected module, making module data available</TextBlock>
|
||||||
|
<TextBlock Classes="subtitle" IsVisible="{Binding !Modules.Count}">No available modules were found</TextBlock>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<TextBlock Classes="label">Icon type</TextBlock>
|
||||||
|
<WrapPanel Orientation="Horizontal">
|
||||||
|
<RadioButton Content="Material Icon"
|
||||||
|
IsChecked="{Binding IconType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static core:ProfileConfigurationIconType.MaterialIcon}}" />
|
||||||
|
<RadioButton Content="Bitmap image"
|
||||||
|
IsChecked="{Binding IconType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static core:ProfileConfigurationIconType.BitmapImage}}" />
|
||||||
|
<RadioButton Content="SVG image"
|
||||||
|
IsChecked="{Binding IconType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static core:ProfileConfigurationIconType.SvgImage}}" />
|
||||||
|
</WrapPanel>
|
||||||
|
|
||||||
|
<TextBlock Classes="label">Icon</TextBlock>
|
||||||
|
<StackPanel Orientation="Horizontal"
|
||||||
|
IsVisible="{Binding IconType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static core:ProfileConfigurationIconType.BitmapImage}}">
|
||||||
|
<Border Background="{DynamicResource CheckerboardBrush}" CornerRadius="{DynamicResource CardCornerRadius}" Width="98" Height="98">
|
||||||
|
<Image Source="{Binding SelectedBitmapSource}" Margin="10"/>
|
||||||
|
</Border>
|
||||||
|
<Button Command="{Binding BrowseBitmapFile}"
|
||||||
|
VerticalAlignment="Bottom"
|
||||||
|
Margin="10 0"
|
||||||
|
IsVisible="{Binding IconType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static core:ProfileConfigurationIconType.BitmapImage}}">
|
||||||
|
Browse bitmap file
|
||||||
|
</Button>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal"
|
||||||
|
IsVisible="{Binding IconType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static core:ProfileConfigurationIconType.SvgImage}}">
|
||||||
|
<Border Background="{DynamicResource CheckerboardBrush}" CornerRadius="{DynamicResource CardCornerRadius}" Width="98" Height="98">
|
||||||
|
<Image Margin="10" Source="{Binding SelectedSvgSource}">
|
||||||
|
|
||||||
|
</Image>
|
||||||
|
</Border>
|
||||||
|
<Button Command="{Binding BrowseSvgFile}"
|
||||||
|
VerticalAlignment="Bottom"
|
||||||
|
Margin="10 0"
|
||||||
|
IsVisible="{Binding IconType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static core:ProfileConfigurationIconType.SvgImage}}">
|
||||||
|
Browse SVG file
|
||||||
|
</Button>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal"
|
||||||
|
IsVisible="{Binding IconType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static core:ProfileConfigurationIconType.MaterialIcon}}">
|
||||||
|
<Border Background="{DynamicResource CheckerboardBrush}" CornerRadius="{DynamicResource CardCornerRadius}" Width="98" Height="98">
|
||||||
|
<avalonia:MaterialIcon Kind="{Binding SelectedMaterialIcon.Icon}" Width="65" Height="65" />
|
||||||
|
</Border>
|
||||||
|
<ComboBox Items="{Binding MaterialIcons}"
|
||||||
|
SelectedItem="{Binding SelectedMaterialIcon}"
|
||||||
|
VirtualizationMode="Simple"
|
||||||
|
VerticalAlignment="Bottom"
|
||||||
|
IsTextSearchEnabled="True"
|
||||||
|
Margin="10 0"
|
||||||
|
Width="250"
|
||||||
|
IsVisible="{Binding IconType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static core:ProfileConfigurationIconType.MaterialIcon}}">
|
||||||
|
<ComboBox.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<VirtualizingStackPanel />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ComboBox.ItemsPanel>
|
||||||
|
<ComboBox.ItemTemplate>
|
||||||
|
<DataTemplate DataType="local:ProfileIconViewModel">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<avalonia:MaterialIcon Kind="{Binding Icon}" Margin="0 0 5 0" />
|
||||||
|
<TextBlock Text="{Binding DisplayName}" />
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ComboBox.ItemTemplate>
|
||||||
|
</ComboBox>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<TextBlock Classes="h5">Keybindings</TextBlock>
|
||||||
|
<TextBlock Classes="subtitle">You may set up hotkeys to activate/deactivate the profile</TextBlock>
|
||||||
|
<Border Classes="card" Margin="0 5 0 15">
|
||||||
|
<TextBlock>TODO</TextBlock>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<TextBlock Classes="h5">Activation conditions</TextBlock>
|
||||||
|
<TextBlock Classes="subtitle">If you only want this profile to be active under certain conditions, configure those conditions below</TextBlock>
|
||||||
|
<Border Classes="card" Margin="0 5 0 15">
|
||||||
|
<TextBlock>TODO</TextBlock>
|
||||||
|
</Border>
|
||||||
|
</StackPanel>
|
||||||
|
</ScrollViewer>
|
||||||
|
|
||||||
|
<Grid Grid.Row="1" ColumnDefinitions="*,Auto,Auto">
|
||||||
|
<Button Grid.Column="0" Command="{Binding Import}">Import profile</Button>
|
||||||
|
<Button Grid.Column="1" Margin="10" Classes="accent" Command="{Binding Confirm}">Confirm</Button>
|
||||||
|
<Button Grid.Column="2" Command="{Binding Cancel}">Cancel</Button>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Window>
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Root.Sidebar.Dialogs
|
||||||
|
{
|
||||||
|
public partial class ProfileConfigurationEditView : ReactiveWindow<ProfileConfigurationEditViewModel>
|
||||||
|
{
|
||||||
|
public ProfileConfigurationEditView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
#if DEBUG
|
||||||
|
this.AttachDevTools();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,225 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.Core.Modules;
|
||||||
|
using Artemis.Core.Services;
|
||||||
|
using Artemis.UI.Shared;
|
||||||
|
using Artemis.UI.Shared.Services.Interfaces;
|
||||||
|
using Avalonia.Media.Imaging;
|
||||||
|
using Avalonia.Svg.Skia;
|
||||||
|
using Avalonia.Threading;
|
||||||
|
using Castle.Core.Resource;
|
||||||
|
using Material.Icons;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Root.Sidebar.Dialogs
|
||||||
|
{
|
||||||
|
public class ProfileConfigurationEditViewModel : DialogViewModelBase<bool>
|
||||||
|
{
|
||||||
|
private readonly ProfileCategory _profileCategory;
|
||||||
|
private readonly IProfileService _profileService;
|
||||||
|
private readonly IWindowService _windowService;
|
||||||
|
private ProfileConfigurationIconType _iconType;
|
||||||
|
private ObservableCollection<ProfileIconViewModel>? _materialIcons;
|
||||||
|
private ProfileConfiguration _profileConfiguration;
|
||||||
|
private string _profileName;
|
||||||
|
private Bitmap? _selectedBitmapSource;
|
||||||
|
private ProfileIconViewModel? _selectedMaterialIcon;
|
||||||
|
private ProfileModuleViewModel? _selectedModule;
|
||||||
|
private string? _selectedIconPath;
|
||||||
|
private SvgImage? _selectedSvgSource;
|
||||||
|
|
||||||
|
public ProfileConfigurationEditViewModel(ProfileCategory profileCategory, ProfileConfiguration? profileConfiguration, IWindowService windowService,
|
||||||
|
IProfileService profileService, IPluginManagementService pluginManagementService)
|
||||||
|
{
|
||||||
|
_profileCategory = profileCategory;
|
||||||
|
_windowService = windowService;
|
||||||
|
_profileService = profileService;
|
||||||
|
_profileConfiguration = profileConfiguration ?? profileService.CreateProfileConfiguration(profileCategory, "New profile", Enum.GetValues<MaterialIconKind>().First().ToString());
|
||||||
|
_profileName = _profileConfiguration.Name;
|
||||||
|
_iconType = _profileConfiguration.Icon.IconType;
|
||||||
|
|
||||||
|
IsNew = profileConfiguration == null;
|
||||||
|
DisplayName = IsNew ? "Artemis | Add profile" : "Artemis | Edit profile";
|
||||||
|
Modules = new ObservableCollection<ProfileModuleViewModel>(
|
||||||
|
pluginManagementService.GetFeaturesOfType<Module>().Where(m => !m.IsAlwaysAvailable).Select(m => new ProfileModuleViewModel(m))
|
||||||
|
);
|
||||||
|
|
||||||
|
Dispatcher.UIThread.Post(LoadIcon, DispatcherPriority.Background);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsNew { get; }
|
||||||
|
|
||||||
|
public ProfileConfiguration ProfileConfiguration
|
||||||
|
{
|
||||||
|
get => _profileConfiguration;
|
||||||
|
set => this.RaiseAndSetIfChanged(ref _profileConfiguration, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ProfileName
|
||||||
|
{
|
||||||
|
get => _profileName;
|
||||||
|
set => this.RaiseAndSetIfChanged(ref _profileName, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableCollection<ProfileModuleViewModel> Modules { get; }
|
||||||
|
|
||||||
|
public ProfileModuleViewModel? SelectedModule
|
||||||
|
{
|
||||||
|
get => _selectedModule;
|
||||||
|
set => this.RaiseAndSetIfChanged(ref _selectedModule, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Import()
|
||||||
|
{
|
||||||
|
string[]? result = await _windowService.CreateOpenFileDialog()
|
||||||
|
.HavingFilter(f => f.WithExtension("json").WithName("Artemis profile"))
|
||||||
|
.ShowAsync();
|
||||||
|
|
||||||
|
if (result == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string json = await File.ReadAllTextAsync(result[0]);
|
||||||
|
ProfileConfigurationExportModel? profileConfigurationExportModel = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
profileConfigurationExportModel = JsonConvert.DeserializeObject<ProfileConfigurationExportModel>(json, IProfileService.ExportSettings);
|
||||||
|
}
|
||||||
|
catch (JsonException e)
|
||||||
|
{
|
||||||
|
_windowService.ShowExceptionDialog("Import profile failed", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (profileConfigurationExportModel == null)
|
||||||
|
{
|
||||||
|
await _windowService.ShowConfirmContentDialog("Import profile", "Failed to import this profile, make sure it is a valid Artemis profile.", "Confirm", null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_profileService.ImportProfile(_profileCategory, profileConfigurationExportModel);
|
||||||
|
Close(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Confirm()
|
||||||
|
{
|
||||||
|
ProfileConfiguration.Name = ProfileName;
|
||||||
|
ProfileConfiguration.Module = SelectedModule?.Module;
|
||||||
|
await SaveIcon();
|
||||||
|
|
||||||
|
_profileService.SaveProfileConfigurationIcon(ProfileConfiguration);
|
||||||
|
_profileService.SaveProfileCategory(_profileCategory);
|
||||||
|
Close(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Cancel()
|
||||||
|
{
|
||||||
|
if (IsNew)
|
||||||
|
_profileService.RemoveProfileConfiguration(_profileConfiguration);
|
||||||
|
Close(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Icon
|
||||||
|
|
||||||
|
public ProfileConfigurationIconType IconType
|
||||||
|
{
|
||||||
|
get => _iconType;
|
||||||
|
set => this.RaiseAndSetIfChanged(ref _iconType, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableCollection<ProfileIconViewModel>? MaterialIcons
|
||||||
|
{
|
||||||
|
get => _materialIcons;
|
||||||
|
set => this.RaiseAndSetIfChanged(ref _materialIcons, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProfileIconViewModel? SelectedMaterialIcon
|
||||||
|
{
|
||||||
|
get => _selectedMaterialIcon;
|
||||||
|
set => this.RaiseAndSetIfChanged(ref _selectedMaterialIcon, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bitmap? SelectedBitmapSource
|
||||||
|
{
|
||||||
|
get => _selectedBitmapSource;
|
||||||
|
set => this.RaiseAndSetIfChanged(ref _selectedBitmapSource, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SvgImage? SelectedSvgSource
|
||||||
|
{
|
||||||
|
get => _selectedSvgSource;
|
||||||
|
set => this.RaiseAndSetIfChanged(ref _selectedSvgSource, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadIcon()
|
||||||
|
{
|
||||||
|
// Preselect the icon based on streams if needed
|
||||||
|
if (_profileConfiguration.Icon.IconType == ProfileConfigurationIconType.BitmapImage)
|
||||||
|
{
|
||||||
|
SelectedBitmapSource = new Bitmap(_profileConfiguration.Icon.GetIconStream());
|
||||||
|
}
|
||||||
|
else if (_profileConfiguration.Icon.IconType == ProfileConfigurationIconType.SvgImage)
|
||||||
|
{
|
||||||
|
SvgSource newSource = new();
|
||||||
|
newSource.Load(_profileConfiguration.Icon.GetIconStream());
|
||||||
|
SelectedSvgSource = new SvgImage {Source = newSource};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare the contents of the dropdown box, it should be virtualized so no need to wait with this
|
||||||
|
MaterialIcons = new ObservableCollection<ProfileIconViewModel>(Enum.GetValues<MaterialIconKind>()
|
||||||
|
.Select(kind => new ProfileIconViewModel(kind))
|
||||||
|
.DistinctBy(vm => vm.DisplayName)
|
||||||
|
.OrderBy(vm => vm.DisplayName));
|
||||||
|
|
||||||
|
// Preselect the icon or fall back to a random one
|
||||||
|
SelectedMaterialIcon = !IsNew && Enum.TryParse(_profileConfiguration.Icon.IconName, out MaterialIconKind enumValue)
|
||||||
|
? MaterialIcons.FirstOrDefault(m => m.Icon == enumValue)
|
||||||
|
: MaterialIcons.ElementAt(new Random().Next(0, MaterialIcons.Count - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SaveIcon()
|
||||||
|
{
|
||||||
|
if (IconType == ProfileConfigurationIconType.MaterialIcon && SelectedMaterialIcon != null)
|
||||||
|
ProfileConfiguration.Icon.SetIconByName(SelectedMaterialIcon.Icon.ToString());
|
||||||
|
else if (_selectedIconPath != null)
|
||||||
|
{
|
||||||
|
await using FileStream fileStream = File.OpenRead(_selectedIconPath);
|
||||||
|
ProfileConfiguration.Icon.SetIconByStream(Path.GetFileName(_selectedIconPath), fileStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task BrowseBitmapFile()
|
||||||
|
{
|
||||||
|
string[]? result = await _windowService.CreateOpenFileDialog()
|
||||||
|
.HavingFilter(f => f.WithExtension("png").WithExtension("jpg").WithExtension("bmp").WithName("Bitmap image"))
|
||||||
|
.ShowAsync();
|
||||||
|
|
||||||
|
if (result == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SelectedBitmapSource = new Bitmap(result[0]);
|
||||||
|
_selectedIconPath = result[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task BrowseSvgFile()
|
||||||
|
{
|
||||||
|
string[]? result = await _windowService.CreateOpenFileDialog()
|
||||||
|
.HavingFilter(f => f.WithExtension("svg").WithName("SVG image"))
|
||||||
|
.ShowAsync();
|
||||||
|
|
||||||
|
if (result == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SvgSource newSource = new();
|
||||||
|
newSource.Load(result[0]);
|
||||||
|
|
||||||
|
SelectedSvgSource = new SvgImage {Source = newSource};
|
||||||
|
_selectedIconPath = result[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
using Artemis.UI.Shared;
|
||||||
|
using Material.Icons;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Root.Sidebar.Dialogs
|
||||||
|
{
|
||||||
|
public class ProfileIconViewModel : ViewModelBase
|
||||||
|
{
|
||||||
|
public ProfileIconViewModel(MaterialIconKind icon)
|
||||||
|
{
|
||||||
|
Icon = icon;
|
||||||
|
DisplayName = icon.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MaterialIconKind Icon { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
using Artemis.Core.Modules;
|
||||||
|
using Artemis.UI.Shared;
|
||||||
|
using Material.Icons;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Root.Sidebar.Dialogs
|
||||||
|
{
|
||||||
|
public class ProfileModuleViewModel : ViewModelBase
|
||||||
|
{
|
||||||
|
public ProfileModuleViewModel(Module module)
|
||||||
|
{
|
||||||
|
Module = module;
|
||||||
|
Name = module.Info.Name;
|
||||||
|
Icon = module.Info.ResolvedIcon ?? MaterialIconKind.QuestionMark.ToString();
|
||||||
|
Description = module.Info.Description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Icon { get; }
|
||||||
|
public string Name { get; }
|
||||||
|
public string? Description { get; }
|
||||||
|
|
||||||
|
public Module Module { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -29,7 +29,7 @@
|
|||||||
</Style>
|
</Style>
|
||||||
</UserControl.Styles>
|
</UserControl.Styles>
|
||||||
<Grid x:Name="ContainerGrid" Margin="0 8 0 0" RowDefinitions="Auto,*">
|
<Grid x:Name="ContainerGrid" Margin="0 8 0 0" RowDefinitions="Auto,*">
|
||||||
<Grid Grid.Row="0" Background="Transparent" ColumnDefinitions="Auto,Auto,*,Auto,Auto">
|
<Grid Grid.Row="0" Background="Transparent" ColumnDefinitions="Auto,Auto,*,Auto,Auto,Auto">
|
||||||
|
|
||||||
<avalonia:MaterialIcon Classes.chevron-collapsed="{Binding ShowItems}"
|
<avalonia:MaterialIcon Classes.chevron-collapsed="{Binding ShowItems}"
|
||||||
Kind="ChevronUp"
|
Kind="ChevronUp"
|
||||||
@ -84,11 +84,17 @@
|
|||||||
<ToggleButton Classes="category-button icon-button icon-button-small"
|
<ToggleButton Classes="category-button icon-button icon-button-small"
|
||||||
Grid.Column="3"
|
Grid.Column="3"
|
||||||
ToolTip.Tip="Suspend profile"
|
ToolTip.Tip="Suspend profile"
|
||||||
Margin="2 0 0 0"
|
Margin="5 0"
|
||||||
IsChecked="{Binding IsSuspended}">
|
IsChecked="{Binding IsSuspended}">
|
||||||
<avalonia:MaterialIcon Kind="Pause" />
|
<avalonia:MaterialIcon Kind="Pause" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
|
<Button Classes="category-button icon-button icon-button-small"
|
||||||
|
Grid.Column="4"
|
||||||
|
ToolTip.Tip="Add profile"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Command="{Binding AddProfile}">
|
||||||
|
<avalonia:MaterialIcon Kind="Plus" />
|
||||||
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Border Grid.Row="1">
|
<Border Grid.Row="1">
|
||||||
|
|||||||
@ -74,15 +74,21 @@ namespace Artemis.UI.Screens.Root.Sidebar
|
|||||||
{
|
{
|
||||||
await _windowService.CreateContentDialog()
|
await _windowService.CreateContentDialog()
|
||||||
.WithTitle("Edit category")
|
.WithTitle("Edit category")
|
||||||
.WithViewModel<SidebarCategoryCreateViewModel>(out var vm, ("category", ProfileCategory))
|
.WithViewModel<SidebarCategoryEditViewModel>(out var vm, ("category", ProfileCategory))
|
||||||
.HavingPrimaryButton(b => b.WithText("Confirm").WithCommand(vm.Confirm))
|
.HavingPrimaryButton(b => b.WithText("Confirm").WithCommand(vm.Confirm))
|
||||||
.HavingSecondaryButton(b => b.WithText("Delete").WithCommand(vm.Delete))
|
.HavingSecondaryButton(b => b.WithText("Delete").WithCommand(vm.Delete))
|
||||||
|
.WithCloseButtonText("Cancel")
|
||||||
.WithDefaultButton(ContentDialogButton.Primary)
|
.WithDefaultButton(ContentDialogButton.Primary)
|
||||||
.ShowAsync();
|
.ShowAsync();
|
||||||
|
|
||||||
_sidebarViewModel.UpdateProfileCategories();
|
_sidebarViewModel.UpdateProfileCategories();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task AddProfile()
|
||||||
|
{
|
||||||
|
await _windowService.ShowDialogAsync<ProfileConfigurationEditViewModel, bool>(("profileCategory", ProfileCategory), ("profileConfiguration", null));
|
||||||
|
}
|
||||||
|
|
||||||
private void CreateProfileViewModels()
|
private void CreateProfileViewModels()
|
||||||
{
|
{
|
||||||
ProfileConfigurations.Clear();
|
ProfileConfigurations.Clear();
|
||||||
|
|||||||
@ -7,22 +7,8 @@
|
|||||||
xmlns:svg="clr-namespace:Avalonia.Svg.Skia;assembly=Avalonia.Svg.Skia"
|
xmlns:svg="clr-namespace:Avalonia.Svg.Skia;assembly=Avalonia.Svg.Skia"
|
||||||
mc:Ignorable="d" d:DesignWidth="240" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="240" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.Root.Sidebar.SidebarView">
|
x:Class="Artemis.UI.Screens.Root.Sidebar.SidebarView">
|
||||||
<Grid>
|
<Grid RowDefinitions="60,Auto,Auto,*,Auto,Auto">
|
||||||
<Grid.RowDefinitions>
|
<Grid Grid.Row="0" IsHitTestVisible="False" ColumnDefinitions="Auto,*">
|
||||||
<RowDefinition Height="60" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<Grid Grid.Row="0" IsHitTestVisible="False">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<Image Grid.Column="0">
|
<Image Grid.Column="0">
|
||||||
<Image.Source>
|
<Image.Source>
|
||||||
<svg:SvgImage Source="/Assets/Images/Logo/bow.svg" />
|
<svg:SvgImage Source="/Assets/Images/Logo/bow.svg" />
|
||||||
|
|||||||
@ -90,8 +90,9 @@ namespace Artemis.UI.Screens.Root.Sidebar
|
|||||||
{
|
{
|
||||||
await _windowService.CreateContentDialog()
|
await _windowService.CreateContentDialog()
|
||||||
.WithTitle("Add new category")
|
.WithTitle("Add new category")
|
||||||
.WithViewModel<SidebarCategoryCreateViewModel>(out var vm, ("category", null))
|
.WithViewModel<SidebarCategoryEditViewModel>(out var vm, ("category", null))
|
||||||
.HavingPrimaryButton(b => b.WithText("Confirm").WithCommand(vm.Confirm))
|
.HavingPrimaryButton(b => b.WithText("Confirm").WithCommand(vm.Confirm))
|
||||||
|
.WithCloseButtonText("Cancel")
|
||||||
.WithDefaultButton(ContentDialogButton.Primary)
|
.WithDefaultButton(ContentDialogButton.Primary)
|
||||||
.ShowAsync();
|
.ShowAsync();
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,6 @@
|
|||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
<ResourceInclude Source="/ArtemisTrayIcon.axaml"/>
|
<ResourceInclude Source="/ArtemisTrayIcon.axaml"/>
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
<SolidColorBrush x:Key="Warning">Yellow</SolidColorBrush>
|
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</Styles.Resources>
|
</Styles.Resources>
|
||||||
<!-- Third party styles -->
|
<!-- Third party styles -->
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user