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

UI - Implemented profile create/update/delete

This commit is contained in:
Robert 2021-12-05 00:20:24 +01:00
parent 55337fe120
commit 519f6bb44d
8 changed files with 112 additions and 73 deletions

View File

@ -8,13 +8,10 @@ namespace Artemis.Core
/// <summary> /// <summary>
/// Represents the icon of a <see cref="ProfileConfiguration" /> /// Represents the icon of a <see cref="ProfileConfiguration" />
/// </summary> /// </summary>
public class ProfileConfigurationIcon : CorePropertyChanged, IStorageModel public class ProfileConfigurationIcon : IStorageModel
{ {
private readonly ProfileConfigurationEntity _entity; private readonly ProfileConfigurationEntity _entity;
private string? _iconName;
private Stream? _iconStream; private Stream? _iconStream;
private ProfileConfigurationIconType _iconType;
private string? _originalFileName;
internal ProfileConfigurationIcon(ProfileConfigurationEntity entity) internal ProfileConfigurationIcon(ProfileConfigurationEntity entity)
{ {
@ -24,29 +21,17 @@ namespace Artemis.Core
/// <summary> /// <summary>
/// Gets 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; private set; }
{
get => _iconType;
private set => SetAndNotify(ref _iconType, value);
}
/// <summary> /// <summary>
/// Gets the name of the icon if <see cref="IconType" /> is <see cref="ProfileConfigurationIconType.MaterialIcon" /> /// Gets the name of the icon if <see cref="IconType" /> is <see cref="ProfileConfigurationIconType.MaterialIcon" />
/// </summary> /// </summary>
public string? IconName public string? IconName { get; private set; }
{
get => _iconName;
private set => SetAndNotify(ref _iconName, value);
}
/// <summary> /// <summary>
/// Gets the original file name of the icon (if applicable) /// Gets the original file name of the icon (if applicable)
/// </summary> /// </summary>
public string? OriginalFileName public string? OriginalFileName { get; private set; }
{
get => _originalFileName;
private set => SetAndNotify(ref _originalFileName, value);
}
/// <summary> /// <summary>
/// Updates the <see cref="IconName" /> to the provided value and changes the <see cref="IconType" /> is /// Updates the <see cref="IconName" /> to the provided value and changes the <see cref="IconType" /> is
@ -55,11 +40,14 @@ namespace Artemis.Core
/// <param name="iconName">The name of the icon</param> /// <param name="iconName">The name of the icon</param>
public void SetIconByName(string iconName) public void SetIconByName(string iconName)
{ {
IconName = iconName ?? throw new ArgumentNullException(nameof(iconName)); if (iconName == null) throw new ArgumentNullException(nameof(iconName));
_iconStream?.Dispose();
IconName = iconName;
OriginalFileName = null; OriginalFileName = null;
IconType = ProfileConfigurationIconType.MaterialIcon; IconType = ProfileConfigurationIconType.MaterialIcon;
_iconStream?.Dispose(); OnIconUpdated();
} }
/// <summary> /// <summary>
@ -81,6 +69,7 @@ namespace Artemis.Core
IconName = null; IconName = null;
OriginalFileName = originalFileName; OriginalFileName = originalFileName;
IconType = OriginalFileName.EndsWith(".svg") ? ProfileConfigurationIconType.SvgImage : ProfileConfigurationIconType.BitmapImage; IconType = OriginalFileName.EndsWith(".svg") ? ProfileConfigurationIconType.SvgImage : ProfileConfigurationIconType.BitmapImage;
OnIconUpdated();
} }
/// <summary> /// <summary>
@ -100,14 +89,30 @@ namespace Artemis.Core
return stream; return stream;
} }
/// <summary>
/// Occurs when the icon was updated
/// </summary>
public event EventHandler? IconUpdated;
/// <summary>
/// Invokes the <see cref="IconUpdated" /> event
/// </summary>
protected virtual void OnIconUpdated()
{
IconUpdated?.Invoke(this, EventArgs.Empty);
}
#region Implementation of IStorageModel #region Implementation of IStorageModel
/// <inheritdoc /> /// <inheritdoc />
public void Load() public void Load()
{ {
IconType = (ProfileConfigurationIconType) _entity.IconType; IconType = (ProfileConfigurationIconType) _entity.IconType;
if (IconType == ProfileConfigurationIconType.MaterialIcon) if (IconType != ProfileConfigurationIconType.MaterialIcon)
return;
IconName = _entity.MaterialIcon; IconName = _entity.MaterialIcon;
OnIconUpdated();
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -1,5 +1,4 @@
using System; using System;
using System.ComponentModel;
using System.IO; using System.IO;
using Artemis.Core; using Artemis.Core;
using Avalonia; using Avalonia;
@ -15,25 +14,6 @@ namespace Artemis.UI.Shared.Controls
{ {
public class ProfileConfigurationIcon : UserControl public class ProfileConfigurationIcon : UserControl
{ {
#region Properties
/// <summary>
/// Gets or sets the <see cref="Core.ProfileConfigurationIcon" /> to display
/// </summary>
public static readonly StyledProperty<Core.ProfileConfigurationIcon?> ConfigurationIconProperty =
AvaloniaProperty.Register<ProfileConfigurationIcon, Core.ProfileConfigurationIcon?>(nameof(ConfigurationIcon));
/// <summary>
/// Gets or sets the <see cref="Core.ProfileConfigurationIcon" /> to display
/// </summary>
public Core.ProfileConfigurationIcon? ConfigurationIcon
{
get => GetValue(ConfigurationIconProperty);
set => SetValue(ConfigurationIconProperty, value);
}
#endregion
public ProfileConfigurationIcon() public ProfileConfigurationIcon()
{ {
InitializeComponent(); InitializeComponent();
@ -71,10 +51,14 @@ namespace Artemis.UI.Shared.Controls
Content = new Image {Source = new SvgImage {Source = source}}; Content = new Image {Source = new SvgImage {Source = source}};
} }
else if (ConfigurationIcon.IconType == ProfileConfigurationIconType.BitmapImage) else if (ConfigurationIcon.IconType == ProfileConfigurationIconType.BitmapImage)
{
Content = new Image {Source = new Bitmap(ConfigurationIcon.GetIconStream())}; Content = new Image {Source = new Bitmap(ConfigurationIcon.GetIconStream())};
}
else else
{
Content = new MaterialIcon {Kind = MaterialIconKind.QuestionMark}; Content = new MaterialIcon {Kind = MaterialIconKind.QuestionMark};
} }
}
catch catch
{ {
Content = new MaterialIcon {Kind = MaterialIconKind.QuestionMark}; Content = new MaterialIcon {Kind = MaterialIconKind.QuestionMark};
@ -86,12 +70,10 @@ namespace Artemis.UI.Shared.Controls
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
} }
#region Event handlers
private void OnDetachedFromLogicalTree(object? sender, LogicalTreeAttachmentEventArgs e) private void OnDetachedFromLogicalTree(object? sender, LogicalTreeAttachmentEventArgs e)
{ {
if (ConfigurationIcon != null) if (ConfigurationIcon != null)
ConfigurationIcon.PropertyChanged -= IconOnPropertyChanged; ConfigurationIcon.IconUpdated -= ConfigurationIconOnIconUpdated;
if (Content is Image image && image.Source is IDisposable disposable) if (Content is Image image && image.Source is IDisposable disposable)
disposable.Dispose(); disposable.Dispose();
@ -99,21 +81,39 @@ namespace Artemis.UI.Shared.Controls
private void OnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e) private void OnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{ {
if (e.Property == ConfigurationIconProperty) if (e.Property != ConfigurationIconProperty)
{ return;
if (e.OldValue is Core.ProfileConfigurationIcon oldIcon) if (e.OldValue is Core.ProfileConfigurationIcon oldIcon)
oldIcon.PropertyChanged -= IconOnPropertyChanged; oldIcon.IconUpdated -= ConfigurationIconOnIconUpdated;
if (e.NewValue is Core.ProfileConfigurationIcon newIcon) if (e.NewValue is Core.ProfileConfigurationIcon newIcon)
newIcon.PropertyChanged += IconOnPropertyChanged; newIcon.IconUpdated += ConfigurationIconOnIconUpdated;
Update(); Update();
} }
}
private void IconOnPropertyChanged(object? sender, PropertyChangedEventArgs e) private void ConfigurationIconOnIconUpdated(object? sender, EventArgs e)
{ {
Update(); Update();
} }
#region Properties
/// <summary>
/// Gets or sets the <see cref="Core.ProfileConfigurationIcon" /> to display
/// </summary>
public static readonly StyledProperty<Core.ProfileConfigurationIcon?> ConfigurationIconProperty =
AvaloniaProperty.Register<ProfileConfigurationIcon, Core.ProfileConfigurationIcon?>(nameof(ConfigurationIcon));
/// <summary>
/// Gets or sets the <see cref="Core.ProfileConfigurationIcon" /> to display
/// </summary>
public Core.ProfileConfigurationIcon? ConfigurationIcon
{
get => GetValue(ConfigurationIconProperty);
set => SetValue(ConfigurationIconProperty, value);
}
#endregion #endregion
} }
} }

View File

@ -36,7 +36,7 @@ namespace Artemis.UI.Ninject.Factories
{ {
SidebarViewModel? SidebarViewModel(IScreen hostScreen); SidebarViewModel? SidebarViewModel(IScreen hostScreen);
SidebarCategoryViewModel SidebarCategoryViewModel(SidebarViewModel sidebarViewModel, ProfileCategory profileCategory); SidebarCategoryViewModel SidebarCategoryViewModel(SidebarViewModel sidebarViewModel, ProfileCategory profileCategory);
SidebarProfileConfigurationViewModel SidebarProfileConfigurationViewModel(ProfileConfiguration profileConfiguration); SidebarProfileConfigurationViewModel SidebarProfileConfigurationViewModel(SidebarViewModel sidebarViewModel, ProfileConfiguration profileConfiguration);
} }
public interface SurfaceVmFactory : IVmFactory public interface SurfaceVmFactory : IVmFactory

View File

@ -84,9 +84,7 @@
<StackPanel Orientation="Horizontal" <StackPanel Orientation="Horizontal"
IsVisible="{Binding IconType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static core:ProfileConfigurationIconType.SvgImage}}"> IsVisible="{Binding IconType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static core:ProfileConfigurationIconType.SvgImage}}">
<Border Background="{DynamicResource CheckerboardBrush}" CornerRadius="{DynamicResource CardCornerRadius}" Width="98" Height="98"> <Border Background="{DynamicResource CheckerboardBrush}" CornerRadius="{DynamicResource CardCornerRadius}" Width="98" Height="98">
<Image Margin="10" Source="{Binding SelectedSvgSource}"> <Image Margin="10" Source="{Binding SelectedSvgSource}" />
</Image>
</Border> </Border>
<Button Command="{Binding BrowseSvgFile}" <Button Command="{Binding BrowseSvgFile}"
VerticalAlignment="Bottom" VerticalAlignment="Bottom"
@ -140,9 +138,10 @@
</StackPanel> </StackPanel>
</ScrollViewer> </ScrollViewer>
<Grid Grid.Row="1" ColumnDefinitions="*,Auto,Auto"> <Grid Grid.Row="1" ColumnDefinitions="Auto,Auto,Auto" HorizontalAlignment="Right">
<Button Grid.Column="0" Command="{Binding Import}">Import profile</Button> <Button Grid.Column="0" Classes="accent" Command="{Binding Confirm}">Confirm</Button>
<Button Grid.Column="1" Margin="10" Classes="accent" Command="{Binding Confirm}">Confirm</Button> <Button Grid.Column="1" Margin="5" Command="{Binding Import}" IsVisible="{Binding IsNew}">Import profile</Button>
<Button Grid.Column="1" Margin="5" Command="{Binding Delete}" IsVisible="{Binding !IsNew}">Delete profile</Button>
<Button Grid.Column="2" Command="{Binding Cancel}">Cancel</Button> <Button Grid.Column="2" Command="{Binding Cancel}">Cancel</Button>
</Grid> </Grid>
</Grid> </Grid>

View File

@ -76,6 +76,9 @@ namespace Artemis.UI.Screens.Root.Sidebar.Dialogs
public async Task Import() public async Task Import()
{ {
if (!IsNew)
return;
string[]? result = await _windowService.CreateOpenFileDialog() string[]? result = await _windowService.CreateOpenFileDialog()
.HavingFilter(f => f.WithExtension("json").WithName("Artemis profile")) .HavingFilter(f => f.WithExtension("json").WithName("Artemis profile"))
.ShowAsync(); .ShowAsync();
@ -100,7 +103,22 @@ namespace Artemis.UI.Screens.Root.Sidebar.Dialogs
return; return;
} }
// Remove the temporary profile configuration
_profileService.RemoveProfileConfiguration(_profileConfiguration);
// Import the new profile configuration
_profileService.ImportProfile(_profileCategory, profileConfigurationExportModel); _profileService.ImportProfile(_profileCategory, profileConfigurationExportModel);
Close(true);
}
public async Task Delete()
{
if (IsNew)
return;
if (!await _windowService.ShowConfirmContentDialog("Delete profile", "Are you sure you want to permanently delete this profile?"))
return;
_profileService.RemoveProfileConfiguration(_profileConfiguration);
Close(true); Close(true);
} }
@ -169,15 +187,16 @@ namespace Artemis.UI.Screens.Root.Sidebar.Dialogs
} }
// Prepare the contents of the dropdown box, it should be virtualized so no need to wait with this // 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>() ObservableCollection<ProfileIconViewModel> icons = new(Enum.GetValues<MaterialIconKind>()
.Select(kind => new ProfileIconViewModel(kind)) .Select(kind => new ProfileIconViewModel(kind))
.DistinctBy(vm => vm.DisplayName) .DistinctBy(vm => vm.DisplayName)
.OrderBy(vm => vm.DisplayName)); .OrderBy(vm => vm.DisplayName));
// Preselect the icon or fall back to a random one // Preselect the icon or fall back to a random one
SelectedMaterialIcon = !IsNew && Enum.TryParse(_profileConfiguration.Icon.IconName, out MaterialIconKind enumValue) SelectedMaterialIcon = !IsNew && Enum.TryParse(_profileConfiguration.Icon.IconName, out MaterialIconKind enumValue)
? MaterialIcons.FirstOrDefault(m => m.Icon == enumValue) ? icons.FirstOrDefault(m => m.Icon == enumValue)
: MaterialIcons.ElementAt(new Random().Next(0, MaterialIcons.Count - 1)); : icons.ElementAt(new Random().Next(0, icons.Count - 1));
MaterialIcons = icons;
} }
private async Task SaveIcon() private async Task SaveIcon()

View File

@ -86,14 +86,16 @@ namespace Artemis.UI.Screens.Root.Sidebar
public async Task AddProfile() public async Task AddProfile()
{ {
await _windowService.ShowDialogAsync<ProfileConfigurationEditViewModel, bool>(("profileCategory", ProfileCategory), ("profileConfiguration", null)); bool result = await _windowService.ShowDialogAsync<ProfileConfigurationEditViewModel, bool>(("profileCategory", ProfileCategory), ("profileConfiguration", null));
if (result)
_sidebarViewModel.UpdateProfileCategories();
} }
private void CreateProfileViewModels() private void CreateProfileViewModels()
{ {
ProfileConfigurations.Clear(); ProfileConfigurations.Clear();
foreach (ProfileConfiguration profileConfiguration in ProfileCategory.ProfileConfigurations.OrderBy(p => p.Order)) foreach (ProfileConfiguration profileConfiguration in ProfileCategory.ProfileConfigurations.OrderBy(p => p.Order))
ProfileConfigurations.Add(_vmFactory.SidebarProfileConfigurationViewModel(profileConfiguration)); ProfileConfigurations.Add(_vmFactory.SidebarProfileConfigurationViewModel(_sidebarViewModel, profileConfiguration));
SelectedProfileConfiguration = ProfileConfigurations.FirstOrDefault(i => i.ProfileConfiguration.IsBeingEdited); SelectedProfileConfiguration = ProfileConfigurations.FirstOrDefault(i => i.ProfileConfiguration.IsBeingEdited);
} }

View File

@ -106,7 +106,8 @@
</Border> </Border>
<Button Classes="icon-button icon-button-small" <Button Command="{Binding EditProfile}"
Classes="icon-button icon-button-small"
Grid.Column="2" Grid.Column="2"
ToolTip.Tip="View properties" ToolTip.Tip="View properties"
HorizontalAlignment="Right"> HorizontalAlignment="Right">

View File

@ -1,17 +1,24 @@
using Artemis.Core; using System.Threading.Tasks;
using Artemis.Core;
using Artemis.Core.Services; using Artemis.Core.Services;
using Artemis.UI.Screens.Root.Sidebar.Dialogs;
using Artemis.UI.Shared; using Artemis.UI.Shared;
using Artemis.UI.Shared.Services.Interfaces;
namespace Artemis.UI.Screens.Root.Sidebar namespace Artemis.UI.Screens.Root.Sidebar
{ {
public class SidebarProfileConfigurationViewModel : ViewModelBase public class SidebarProfileConfigurationViewModel : ViewModelBase
{ {
private readonly SidebarViewModel _sidebarViewModel;
private readonly IProfileService _profileService; private readonly IProfileService _profileService;
private readonly IWindowService _windowService;
public ProfileConfiguration ProfileConfiguration { get; } public ProfileConfiguration ProfileConfiguration { get; }
public SidebarProfileConfigurationViewModel(ProfileConfiguration profileConfiguration, IProfileService profileService) public SidebarProfileConfigurationViewModel(SidebarViewModel sidebarViewModel, ProfileConfiguration profileConfiguration, IProfileService profileService, IWindowService windowService)
{ {
_sidebarViewModel = sidebarViewModel;
_profileService = profileService; _profileService = profileService;
_windowService = windowService;
ProfileConfiguration = profileConfiguration; ProfileConfiguration = profileConfiguration;
_profileService.LoadProfileConfigurationIcon(ProfileConfiguration); _profileService.LoadProfileConfigurationIcon(ProfileConfiguration);
@ -28,5 +35,11 @@ namespace Artemis.UI.Screens.Root.Sidebar
_profileService.SaveProfileCategory(ProfileConfiguration.Category); _profileService.SaveProfileCategory(ProfileConfiguration.Category);
} }
} }
public async Task EditProfile()
{
if (await _windowService.ShowDialogAsync<ProfileConfigurationEditViewModel, bool>(("profileCategory", ProfileConfiguration.Category), ("profileConfiguration", ProfileConfiguration)))
_sidebarViewModel.UpdateProfileCategories();
}
} }
} }