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>
/// Represents the icon of a <see cref="ProfileConfiguration" />
/// </summary>
public class ProfileConfigurationIcon : CorePropertyChanged, IStorageModel
public class ProfileConfigurationIcon : IStorageModel
{
private readonly ProfileConfigurationEntity _entity;
private string? _iconName;
private Stream? _iconStream;
private ProfileConfigurationIconType _iconType;
private string? _originalFileName;
internal ProfileConfigurationIcon(ProfileConfigurationEntity entity)
{
@ -24,29 +21,17 @@ namespace Artemis.Core
/// <summary>
/// Gets the type of icon this profile configuration uses
/// </summary>
public ProfileConfigurationIconType IconType
{
get => _iconType;
private set => SetAndNotify(ref _iconType, value);
}
public ProfileConfigurationIconType IconType { get; private set; }
/// <summary>
/// Gets the name of the icon if <see cref="IconType" /> is <see cref="ProfileConfigurationIconType.MaterialIcon" />
/// </summary>
public string? IconName
{
get => _iconName;
private set => SetAndNotify(ref _iconName, value);
}
public string? IconName { get; private set; }
/// <summary>
/// Gets the original file name of the icon (if applicable)
/// </summary>
public string? OriginalFileName
{
get => _originalFileName;
private set => SetAndNotify(ref _originalFileName, value);
}
public string? OriginalFileName { get; private set; }
/// <summary>
/// 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>
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;
IconType = ProfileConfigurationIconType.MaterialIcon;
_iconStream?.Dispose();
OnIconUpdated();
}
/// <summary>
@ -81,6 +69,7 @@ namespace Artemis.Core
IconName = null;
OriginalFileName = originalFileName;
IconType = OriginalFileName.EndsWith(".svg") ? ProfileConfigurationIconType.SvgImage : ProfileConfigurationIconType.BitmapImage;
OnIconUpdated();
}
/// <summary>
@ -100,14 +89,30 @@ namespace Artemis.Core
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
/// <inheritdoc />
public void Load()
{
IconType = (ProfileConfigurationIconType) _entity.IconType;
if (IconType == ProfileConfigurationIconType.MaterialIcon)
IconName = _entity.MaterialIcon;
if (IconType != ProfileConfigurationIconType.MaterialIcon)
return;
IconName = _entity.MaterialIcon;
OnIconUpdated();
}
/// <inheritdoc />

View File

@ -1,5 +1,4 @@
using System;
using System.ComponentModel;
using System.IO;
using Artemis.Core;
using Avalonia;
@ -15,25 +14,6 @@ namespace Artemis.UI.Shared.Controls
{
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()
{
InitializeComponent();
@ -71,9 +51,13 @@ namespace Artemis.UI.Shared.Controls
Content = new Image {Source = new SvgImage {Source = source}};
}
else if (ConfigurationIcon.IconType == ProfileConfigurationIconType.BitmapImage)
{
Content = new Image {Source = new Bitmap(ConfigurationIcon.GetIconStream())};
}
else
{
Content = new MaterialIcon {Kind = MaterialIconKind.QuestionMark};
}
}
catch
{
@ -86,34 +70,50 @@ namespace Artemis.UI.Shared.Controls
AvaloniaXamlLoader.Load(this);
}
#region Event handlers
private void OnDetachedFromLogicalTree(object? sender, LogicalTreeAttachmentEventArgs e)
{
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();
}
private void OnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{
if (e.Property == ConfigurationIconProperty)
{
if (e.OldValue is Core.ProfileConfigurationIcon oldIcon)
oldIcon.PropertyChanged -= IconOnPropertyChanged;
if (e.NewValue is Core.ProfileConfigurationIcon newIcon)
newIcon.PropertyChanged += IconOnPropertyChanged;
Update();
}
if (e.Property != ConfigurationIconProperty)
return;
if (e.OldValue is Core.ProfileConfigurationIcon oldIcon)
oldIcon.IconUpdated -= ConfigurationIconOnIconUpdated;
if (e.NewValue is Core.ProfileConfigurationIcon newIcon)
newIcon.IconUpdated += ConfigurationIconOnIconUpdated;
Update();
}
private void IconOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
private void ConfigurationIconOnIconUpdated(object? sender, EventArgs e)
{
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
}
}

View File

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

View File

@ -72,10 +72,10 @@
<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"/>
<Image Source="{Binding SelectedBitmapSource}" Margin="10" />
</Border>
<Button Command="{Binding BrowseBitmapFile}"
VerticalAlignment="Bottom"
VerticalAlignment="Bottom"
Margin="10 0"
IsVisible="{Binding IconType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static core:ProfileConfigurationIconType.BitmapImage}}">
Browse bitmap file
@ -84,9 +84,7 @@
<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>
<Image Margin="10" Source="{Binding SelectedSvgSource}" />
</Border>
<Button Command="{Binding BrowseSvgFile}"
VerticalAlignment="Bottom"
@ -140,9 +138,10 @@
</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>
<Grid Grid.Row="1" ColumnDefinitions="Auto,Auto,Auto" HorizontalAlignment="Right">
<Button Grid.Column="0" 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>
</Grid>
</Grid>

View File

@ -76,6 +76,9 @@ namespace Artemis.UI.Screens.Root.Sidebar.Dialogs
public async Task Import()
{
if (!IsNew)
return;
string[]? result = await _windowService.CreateOpenFileDialog()
.HavingFilter(f => f.WithExtension("json").WithName("Artemis profile"))
.ShowAsync();
@ -100,7 +103,22 @@ namespace Artemis.UI.Screens.Root.Sidebar.Dialogs
return;
}
// Remove the temporary profile configuration
_profileService.RemoveProfileConfiguration(_profileConfiguration);
// Import the new profile configuration
_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);
}
@ -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
MaterialIcons = new ObservableCollection<ProfileIconViewModel>(Enum.GetValues<MaterialIconKind>()
ObservableCollection<ProfileIconViewModel> icons = new(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));
? icons.FirstOrDefault(m => m.Icon == enumValue)
: icons.ElementAt(new Random().Next(0, icons.Count - 1));
MaterialIcons = icons;
}
private async Task SaveIcon()

View File

@ -86,14 +86,16 @@ namespace Artemis.UI.Screens.Root.Sidebar
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()
{
ProfileConfigurations.Clear();
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);
}

View File

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

View File

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