From 519f6bb44d3415f5be48e2ceb211bea73e678217 Mon Sep 17 00:00:00 2001 From: Robert Date: Sun, 5 Dec 2021 00:20:24 +0100 Subject: [PATCH] UI - Implemented profile create/update/delete --- .../ProfileConfigurationIcon.cs | 51 +++++++------- .../ProfileConfigurationIcon.axaml.cs | 66 +++++++++---------- .../Ninject/Factories/IVMFactory.cs | 2 +- .../ProfileConfigurationEditView.axaml | 15 ++--- .../ProfileConfigurationEditViewModel.cs | 25 ++++++- .../Root/Sidebar/SidebarCategoryViewModel.cs | 6 +- .../SidebarProfileConfigurationView.axaml | 3 +- .../SidebarProfileConfigurationViewModel.cs | 17 ++++- 8 files changed, 112 insertions(+), 73 deletions(-) diff --git a/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfigurationIcon.cs b/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfigurationIcon.cs index ff205f93d..46e5595a5 100644 --- a/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfigurationIcon.cs +++ b/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfigurationIcon.cs @@ -8,13 +8,10 @@ namespace Artemis.Core /// /// Represents the icon of a /// - 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 /// /// Gets the type of icon this profile configuration uses /// - public ProfileConfigurationIconType IconType - { - get => _iconType; - private set => SetAndNotify(ref _iconType, value); - } + public ProfileConfigurationIconType IconType { get; private set; } /// /// Gets the name of the icon if is /// - public string? IconName - { - get => _iconName; - private set => SetAndNotify(ref _iconName, value); - } + public string? IconName { get; private set; } /// /// Gets the original file name of the icon (if applicable) /// - public string? OriginalFileName - { - get => _originalFileName; - private set => SetAndNotify(ref _originalFileName, value); - } + public string? OriginalFileName { get; private set; } /// /// Updates the to the provided value and changes the is @@ -55,11 +40,14 @@ namespace Artemis.Core /// The name of the icon 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(); } /// @@ -81,6 +69,7 @@ namespace Artemis.Core IconName = null; OriginalFileName = originalFileName; IconType = OriginalFileName.EndsWith(".svg") ? ProfileConfigurationIconType.SvgImage : ProfileConfigurationIconType.BitmapImage; + OnIconUpdated(); } /// @@ -100,14 +89,30 @@ namespace Artemis.Core return stream; } + /// + /// Occurs when the icon was updated + /// + public event EventHandler? IconUpdated; + + /// + /// Invokes the event + /// + protected virtual void OnIconUpdated() + { + IconUpdated?.Invoke(this, EventArgs.Empty); + } + #region Implementation of IStorageModel /// public void Load() { IconType = (ProfileConfigurationIconType) _entity.IconType; - if (IconType == ProfileConfigurationIconType.MaterialIcon) - IconName = _entity.MaterialIcon; + if (IconType != ProfileConfigurationIconType.MaterialIcon) + return; + + IconName = _entity.MaterialIcon; + OnIconUpdated(); } /// diff --git a/src/Avalonia/Artemis.UI.Shared/Controls/ProfileConfigurationIcon.axaml.cs b/src/Avalonia/Artemis.UI.Shared/Controls/ProfileConfigurationIcon.axaml.cs index 6cbd39a0a..3037af3a8 100644 --- a/src/Avalonia/Artemis.UI.Shared/Controls/ProfileConfigurationIcon.axaml.cs +++ b/src/Avalonia/Artemis.UI.Shared/Controls/ProfileConfigurationIcon.axaml.cs @@ -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 - - /// - /// Gets or sets the to display - /// - public static readonly StyledProperty ConfigurationIconProperty = - AvaloniaProperty.Register(nameof(ConfigurationIcon)); - - /// - /// Gets or sets the to display - /// - 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 + + /// + /// Gets or sets the to display + /// + public static readonly StyledProperty ConfigurationIconProperty = + AvaloniaProperty.Register(nameof(ConfigurationIcon)); + + /// + /// Gets or sets the to display + /// + public Core.ProfileConfigurationIcon? ConfigurationIcon + { + get => GetValue(ConfigurationIconProperty); + set => SetValue(ConfigurationIconProperty, value); + } + #endregion } } \ No newline at end of file diff --git a/src/Avalonia/Artemis.UI/Ninject/Factories/IVMFactory.cs b/src/Avalonia/Artemis.UI/Ninject/Factories/IVMFactory.cs index 7f83f4027..2248b2bdc 100644 --- a/src/Avalonia/Artemis.UI/Ninject/Factories/IVMFactory.cs +++ b/src/Avalonia/Artemis.UI/Ninject/Factories/IVMFactory.cs @@ -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 diff --git a/src/Avalonia/Artemis.UI/Screens/Root/Sidebar/Dialogs/ProfileConfigurationEditView.axaml b/src/Avalonia/Artemis.UI/Screens/Root/Sidebar/Dialogs/ProfileConfigurationEditView.axaml index 8b36f089b..88bb927b5 100644 --- a/src/Avalonia/Artemis.UI/Screens/Root/Sidebar/Dialogs/ProfileConfigurationEditView.axaml +++ b/src/Avalonia/Artemis.UI/Screens/Root/Sidebar/Dialogs/ProfileConfigurationEditView.axaml @@ -72,10 +72,10 @@ - + - + + + + diff --git a/src/Avalonia/Artemis.UI/Screens/Root/Sidebar/Dialogs/ProfileConfigurationEditViewModel.cs b/src/Avalonia/Artemis.UI/Screens/Root/Sidebar/Dialogs/ProfileConfigurationEditViewModel.cs index 4e0261214..b152900fc 100644 --- a/src/Avalonia/Artemis.UI/Screens/Root/Sidebar/Dialogs/ProfileConfigurationEditViewModel.cs +++ b/src/Avalonia/Artemis.UI/Screens/Root/Sidebar/Dialogs/ProfileConfigurationEditViewModel.cs @@ -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(Enum.GetValues() + ObservableCollection icons = new(Enum.GetValues() .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() diff --git a/src/Avalonia/Artemis.UI/Screens/Root/Sidebar/SidebarCategoryViewModel.cs b/src/Avalonia/Artemis.UI/Screens/Root/Sidebar/SidebarCategoryViewModel.cs index 3093c95cf..ac865ee3e 100644 --- a/src/Avalonia/Artemis.UI/Screens/Root/Sidebar/SidebarCategoryViewModel.cs +++ b/src/Avalonia/Artemis.UI/Screens/Root/Sidebar/SidebarCategoryViewModel.cs @@ -86,14 +86,16 @@ namespace Artemis.UI.Screens.Root.Sidebar public async Task AddProfile() { - await _windowService.ShowDialogAsync(("profileCategory", ProfileCategory), ("profileConfiguration", null)); + bool result = await _windowService.ShowDialogAsync(("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); } diff --git a/src/Avalonia/Artemis.UI/Screens/Root/Sidebar/SidebarProfileConfigurationView.axaml b/src/Avalonia/Artemis.UI/Screens/Root/Sidebar/SidebarProfileConfigurationView.axaml index 093d3aced..01627b418 100644 --- a/src/Avalonia/Artemis.UI/Screens/Root/Sidebar/SidebarProfileConfigurationView.axaml +++ b/src/Avalonia/Artemis.UI/Screens/Root/Sidebar/SidebarProfileConfigurationView.axaml @@ -106,7 +106,8 @@ -