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:
parent
55337fe120
commit
519f6bb44d
@ -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 />
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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">
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user